> ## Documentation Index
> Fetch the complete documentation index at: https://apidoc.cometapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Gemini 画像モデルを使う

> Google Gen AI SDK を使って CometAPI 上で Gemini 画像モデル（Nano Banana 2 / Pro）を呼び出し、テキストから画像、画像から画像、複数画像の合成を行います。

このガイドでは、**Google Gen AI SDK** を使用して CometAPI 経由で Gemini 画像モデルを利用する方法を説明します。対象内容は次のとおりです。

* テキストから画像の生成
* 画像から画像への編集
* 複数画像の合成
* 生成した画像の保存

<Info>
  - **Base URL:** `https://api.cometapi.com`
  - SDK のインストール: `pip install google-genai`（Python）または `npm install @google/genai`（Node.js）
</Info>

***

## セットアップ

CometAPI のベース URL を指定してクライアントを初期化します。

<CodeGroup>
  ```python Python theme={null}
  from google import genai
  from google.genai import types
  import os

  COMETAPI_KEY = os.environ["COMETAPI_KEY"]

  client = genai.Client(
      http_options={"api_version": "v1beta", "base_url": "https://api.cometapi.com"},
      api_key=COMETAPI_KEY,
  )
  ```

  ```javascript Node.js theme={null}
  import { GoogleGenAI } from "@google/genai";

  const COMETAPI_KEY = process.env.COMETAPI_KEY;

  const ai = new GoogleGenAI({
    apiKey: COMETAPI_KEY,
    httpOptions: { apiVersion: "v1beta", baseUrl: "https://api.cometapi.com" },
  });
  ```

  ```go Go theme={null}
  package main

  import (
  	"context"
  	"os"
  	"google.golang.org/genai"
  )

  func main() {
  	ctx := context.Background()
  	apiKey := os.Getenv("COMETAPI_KEY")

  	client, _ := genai.NewClient(ctx, &genai.ClientConfig{
  		APIKey:  apiKey,
  		Backend: genai.BackendGeminiAPI,
  		HTTPOptions: genai.HTTPOptions{
  			BaseURL: "https://api.cometapi.com",
  		},
  	})
  	// use client below...
  }
  ```
</CodeGroup>

***

## テキストから画像の生成

テキストプロンプト（Prompt）から画像を生成し、ファイルに保存します。

<CodeGroup>
  ```python Python theme={null}
  from google import genai
  from google.genai import types
  from PIL import Image
  import os

  client = genai.Client(
      http_options={"api_version": "v1beta", "base_url": "https://api.cometapi.com"},
      api_key=os.environ.get("COMETAPI_KEY"),
  )

  response = client.models.generate_content(
      model="gemini-3.1-flash-image-preview",
      contents="Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme",
      config=types.GenerateContentConfig(
          response_modalities=["TEXT", "IMAGE"],
      ),
  )

  final_image = None
  for part in response.parts:
      if getattr(part, "thought", False):
          continue
      if part.text is not None:
          print(part.text)
      elif part.inline_data is not None:
          final_image = part.as_image()

  if final_image:
      final_image.save("generated_image.png")
      print("Image saved to generated_image.png")
  ```

  ```javascript Node.js theme={null}
  import { GoogleGenAI } from "@google/genai";
  import * as fs from "fs";

  const ai = new GoogleGenAI({
    apiKey: process.env.COMETAPI_KEY,
    httpOptions: { apiVersion: "v1beta", baseUrl: "https://api.cometapi.com" },
  });

  const response = await ai.models.generateContent({
    model: "gemini-3.1-flash-image-preview",
    contents: "Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme",
    config: { responseModalities: ["TEXT", "IMAGE"] },
  });

  let finalImagePart;
  for (const part of response.candidates[0].content.parts) {
    if (part.thought === true) {
      continue;
    }
    if (part.text) {
      console.log(part.text);
    }
    if (part.inlineData) {
      finalImagePart = part;
    }
  }

  if (finalImagePart) {
    const buffer = Buffer.from(finalImagePart.inlineData.data, "base64");
    fs.writeFileSync("generated_image.png", buffer);
    console.log("Image saved to generated_image.png");
  }
  ```

  ```bash Shell theme={null}
  curl -s -X POST \
    "https://api.cometapi.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent" \
    -H "Authorization: Bearer $COMETAPI_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "contents": [{
        "parts": [{"text": "Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme"}]
      }],
      "generationConfig": {
        "responseModalities": ["TEXT", "IMAGE"]
      }
    }'
  ```
</CodeGroup>

**最終的な画像パートを保存する:**

画像データは `candidates[0].content.parts` にあり、ここにはテキストパートや画像パートが含まれる場合があります。Gemini の画像モデルは、特にテキストと画像の両方をリクエストした場合や、thinking 出力を明示的に有効にした場合、最終画像の前に中間的な thought パートを返すこともあります。最初の `inlineData` をそのまま保存してはいけません。`thought` が `true` のパートをスキップし、その後に残る最後の画像パートを保存してください。

最終画像のみを含む典型的なレスポンス:

```json theme={null}
{
  "candidates": [{
    "content": {
      "parts": [
        { "text": "Here is your image..." },
        {
          "inlineData": {
            "mimeType": "image/png",
            "data": "<base64-encoded-image>"
          }
        }
      ]
    }
  }]
}
```

テキストパート、中間 thought 画像、最終画像を含むレスポンス:

```json theme={null}
{
  "candidates": [{
    "content": {
      "role": "model",
      "parts": [
        { "text": "Here is your image..." },
        {
          "inlineData": {
            "mimeType": "image/jpeg",
            "data": "<base64-encoded-intermediate-image>"
          },
          "thought": true
        },
        {
          "inlineData": {
            "mimeType": "image/jpeg",
            "data": "<base64-encoded-final-image>"
          },
          "thought": false,
          "thoughtSignature": "<signature>"
        }
      ]
    },
    "finishReason": "STOP"
  }]
}
```

この解析ルールをすべての Gemini 画像レスポンスで使用してください:

```javascript theme={null}
const imageParts = response.candidates[0].content.parts.filter(
  (part) => part.inlineData && part.thought !== true,
);
const finalImagePart = imageParts.at(-1);
```

***

## 画像から画像への生成

入力画像をアップロードし、テキストプロンプトで変換します。

<CodeGroup>
  ```python Python theme={null}
  from google import genai
  from google.genai import types
  from PIL import Image
  import os

  client = genai.Client(
      http_options={"api_version": "v1beta", "base_url": "https://api.cometapi.com"},
      api_key=os.environ.get("COMETAPI_KEY"),
  )

  # Load the source image
  source_image = Image.open("source.jpg")

  response = client.models.generate_content(
      model="gemini-3.1-flash-image-preview",
      contents=["Transform this into a watercolor painting", source_image],
      config=types.GenerateContentConfig(
          response_modalities=["TEXT", "IMAGE"],
      ),
  )

  final_image = None
  for part in response.parts:
      if getattr(part, "thought", False):
          continue
      if part.text is not None:
          print(part.text)
      elif part.inline_data is not None:
          final_image = part.as_image()

  if final_image:
      final_image.save("watercolor_output.png")
  ```

  ```javascript Node.js theme={null}
  import { GoogleGenAI } from "@google/genai";
  import * as fs from "fs";

  const ai = new GoogleGenAI({
    apiKey: process.env.COMETAPI_KEY,
    httpOptions: { apiVersion: "v1beta", baseUrl: "https://api.cometapi.com" },
  });

  const imageData = fs.readFileSync("source.jpg").toString("base64");

  const response = await ai.models.generateContent({
    model: "gemini-3.1-flash-image-preview",
    contents: [
      { text: "Transform this into a watercolor painting" },
      { inlineData: { mimeType: "image/jpeg", data: imageData } },
    ],
    config: { responseModalities: ["TEXT", "IMAGE"] },
  });

  const imageParts = response.candidates[0].content.parts.filter(
    (part) => part.inlineData && part.thought !== true,
  );
  const finalImagePart = imageParts.at(-1);

  if (finalImagePart) {
    fs.writeFileSync("watercolor_output.png", Buffer.from(finalImagePart.inlineData.data, "base64"));
  }
  ```

  ```bash Shell theme={null}
  curl -s -X POST \
    "https://api.cometapi.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent" \
    -H "Authorization: Bearer $COMETAPI_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "contents": [{
        "role": "user",
        "parts": [
          { "text": "Transform this into a watercolor painting" },
          { "inline_data": { "mime_type": "image/jpeg", "data": "<base64-encoded-source-image>" } }
        ]
      }],
      "generationConfig": { "responseModalities": ["TEXT", "IMAGE"] }
    }'
  ```
</CodeGroup>

<Note>
  * Python SDK は `PIL.Image` オブジェクトを直接受け付けるため、手動での Base64 エンコードは不要です。
  * 生の Base64 文字列を渡す際は、`data:image/jpeg;base64,` プレフィックスを含めないでください。
</Note>

***

## 複数画像の合成

複数の入力画像から新しい画像を生成します。CometAPI は2つのアプローチをサポートしています。

### 方法 1: 1枚のコラージュ画像

複数の元画像を1つのコラージュにまとめ、その後で希望する出力を説明します。

<Frame>
  <img src="https://mintcdn.com/cometapi/OukMcVwzR05umRJn/images/image/gemini/6100640_569419.png?fit=max&auto=format&n=OukMcVwzR05umRJn&q=85&s=02d820e809bd8e21e3b7b0c58592c6ab" alt="入力コラージュの例" width="1200" height="754" data-path="images/image/gemini/6100640_569419.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/cometapi/OukMcVwzR05umRJn/images/image/gemini/6100640_569420.png?fit=max&auto=format&n=OukMcVwzR05umRJn&q=85&s=b8f128a921f62619b575926da824fd43" alt="生成された出力" width="1200" height="733" data-path="images/image/gemini/6100640_569420.png" />
</Frame>

<CodeGroup>
  ```python Python theme={null}
  from google import genai
  from google.genai import types
  from PIL import Image
  import os

  client = genai.Client(
      http_options={"api_version": "v1beta", "base_url": "https://api.cometapi.com"},
      api_key=os.environ.get("COMETAPI_KEY"),
  )

  collage = Image.open("collage.jpg")

  response = client.models.generate_content(
      model="gemini-3.1-flash-image-preview",
      contents=[
          "A model is posing and leaning against a pink BMW with a green alien keychain attached to a pink handbag, a pink parrot on her shoulder, and a pug wearing a pink collar and gold headphones",
          collage,
      ],
      config=types.GenerateContentConfig(
          response_modalities=["TEXT", "IMAGE"],
      ),
  )

  final_image = None
  for part in response.parts:
      if getattr(part, "thought", False):
          continue
      if part.inline_data is not None:
          final_image = part.as_image()

  if final_image:
      final_image.save("composition_output.png")
  ```

  ```bash Shell theme={null}
  curl -s -X POST \
    "https://api.cometapi.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent" \
    -H "Authorization: Bearer $COMETAPI_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "contents": [{
        "role": "user",
        "parts": [
          { "text": "A model is posing and leaning against a pink BMW with a green alien keychain attached to a pink handbag, a pink parrot on her shoulder, and a pug wearing a pink collar and gold headphones" },
          { "inline_data": { "mime_type": "image/jpeg", "data": "<base64-encoded-collage-image>" } }
        ]
      }],
      "generationConfig": { "responseModalities": ["TEXT", "IMAGE"] }
    }'
  ```
</CodeGroup>

### 方法 2: 複数の個別画像（最大14枚）

複数の画像を直接渡します。Gemini 3 モデルは最大14枚の参照画像（オブジェクト + キャラクター）をサポートします。

<CodeGroup>
  ```python Python theme={null}
  from google import genai
  from google.genai import types
  from PIL import Image
  import os

  client = genai.Client(
      http_options={"api_version": "v1beta", "base_url": "https://api.cometapi.com"},
      api_key=os.environ.get("COMETAPI_KEY"),
  )

  image1 = Image.open("image1.jpg")
  image2 = Image.open("image2.jpg")
  image3 = Image.open("image3.jpg")

  response = client.models.generate_content(
      model="gemini-3.1-flash-image-preview",
      contents=["Merge the three images", image1, image2, image3],
      config=types.GenerateContentConfig(
          response_modalities=["TEXT", "IMAGE"],
      ),
  )

  final_image = None
  for part in response.parts:
      if getattr(part, "thought", False):
          continue
      if part.inline_data is not None:
          final_image = part.as_image()

  if final_image:
      final_image.save("merged_output.png")
  ```

  ```bash Shell theme={null}
  curl -s -X POST \
    "https://api.cometapi.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent" \
    -H "Authorization: Bearer $COMETAPI_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "contents": [{
        "role": "user",
        "parts": [
          { "text": "Merge the three images" },
          { "inline_data": { "mime_type": "image/jpeg", "data": "<base64-image-1>" } },
          { "inline_data": { "mime_type": "image/jpeg", "data": "<base64-image-2>" } },
          { "inline_data": { "mime_type": "image/jpeg", "data": "<base64-image-3>" } }
        ]
      }],
      "generationConfig": { "responseModalities": ["TEXT", "IMAGE"] }
    }'
  ```
</CodeGroup>

<Frame>
  <img src="https://mintcdn.com/cometapi/OukMcVwzR05umRJn/images/image/gemini/6100640_569429.png?fit=max&auto=format&n=OukMcVwzR05umRJn&q=85&s=2a1ea93ce3477491d8014283896c31e2" alt="複数画像生成の結果" width="1248" height="832" data-path="images/image/gemini/6100640_569429.png" />
</Frame>

***

## 4K画像生成

高解像度の出力には、`aspect_ratio` と `image_size` を含む `image_config` を指定します。

<CodeGroup>
  ```python Python theme={null}
  from google import genai
  from google.genai import types
  import os

  client = genai.Client(
      http_options={"api_version": "v1beta", "base_url": "https://api.cometapi.com"},
      api_key=os.environ.get("COMETAPI_KEY"),
  )

  response = client.models.generate_content(
      model="gemini-3.1-flash-image-preview",
      contents="Da Vinci style anatomical sketch of a Monarch butterfly on textured parchment",
      config=types.GenerateContentConfig(
          response_modalities=["TEXT", "IMAGE"],
          image_config=types.ImageConfig(
              aspect_ratio="1:1",
              image_size="4K",
          ),
      ),
  )

  final_image = None
  for part in response.parts:
      if getattr(part, "thought", False):
          continue
      if part.text is not None:
          print(part.text)
      elif image := part.as_image():
          final_image = image

  if final_image:
      final_image.save("butterfly_4k.png")
  ```

  ```javascript Node.js theme={null}
  import { GoogleGenAI } from "@google/genai";
  import * as fs from "fs";

  const ai = new GoogleGenAI({
    apiKey: process.env.COMETAPI_KEY,
    httpOptions: { apiVersion: "v1beta", baseUrl: "https://api.cometapi.com" },
  });

  const response = await ai.models.generateContent({
    model: "gemini-3.1-flash-image-preview",
    contents: "Da Vinci style anatomical sketch of a Monarch butterfly on textured parchment",
    config: {
      responseModalities: ["TEXT", "IMAGE"],
      imageConfig: { aspectRatio: "1:1", imageSize: "4K" },
    },
  });

  const imageParts = response.candidates[0].content.parts.filter(
    (part) => part.inlineData && part.thought !== true,
  );
  const finalImagePart = imageParts.at(-1);

  if (finalImagePart) {
    fs.writeFileSync("butterfly_4k.png", Buffer.from(finalImagePart.inlineData.data, "base64"));
  }
  ```

  ```bash Shell theme={null}
  curl -s -X POST \
    "https://api.cometapi.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent" \
    -H "Authorization: Bearer $COMETAPI_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "contents": [{"parts": [{"text": "Da Vinci style anatomical sketch of a Monarch butterfly on textured parchment"}]}],
      "generationConfig": {
        "responseModalities": ["TEXT", "IMAGE"],
        "imageConfig": {"aspectRatio": "1:1", "imageSize": "4K"}
      }
    }'
  ```
</CodeGroup>

<Note>
  高解像度リクエストでは、最終的な非thoughtの画像パートを基準に出力を判断してください。統合側で最初の `inlineData` パートを保存すると、要求した `imageSize` よりも低解像度の中間thought画像を保存してしまう場合があります。
</Note>

***

## マルチターン画像編集（チャット）

SDK のチャット機能を使って、画像を反復的にブラッシュアップできます。

<CodeGroup>
  ```python Python theme={null}
  from google import genai
  from google.genai import types
  import os

  client = genai.Client(
      http_options={"api_version": "v1beta", "base_url": "https://api.cometapi.com"},
      api_key=os.environ.get("COMETAPI_KEY"),
  )

  chat = client.chats.create(
      model="gemini-3.1-flash-image-preview",
      config=types.GenerateContentConfig(
          response_modalities=["TEXT", "IMAGE"],
      ),
  )

  ## First turn: Generate
  response = chat.send_message(
      "Create a vibrant infographic explaining photosynthesis as a recipe, styled like a colorful kids cookbook"
  )

  final_image = None
  for part in response.parts:
      if getattr(part, "thought", False):
          continue
      if part.text is not None:
          print(part.text)
      elif image := part.as_image():
          final_image = image

  if final_image:
      final_image.save("photosynthesis.png")
  ```

  ## 2 回目のターン: 改良

  response = chat.send\_message("このインフォグラフィックをスペイン語にしてください。他の要素は一切変更しないでください。")

  final\_image = None
  for part in response.parts:
  if getattr(part, "thought", False):
  continue
  if part.text is not None:
  print(part.text)
  elif image := part.as\_image():
  final\_image = image

  if final\_image:
  final\_image.save("photosynthesis\_spanish.png")

  ````

  ```javascript Node.js
  import { GoogleGenAI } from "@google/genai";
  import * as fs from "fs";

  const ai = new GoogleGenAI({
    apiKey: process.env.COMETAPI_KEY,
    httpOptions: { apiVersion: "v1beta", baseUrl: "https://api.cometapi.com" },
  });

  const chat = ai.chats.create({
    model: "gemini-3.1-flash-image-preview",
    config: { responseModalities: ["TEXT", "IMAGE"] },
  });

  // First turn: generate
  const response1 = await chat.sendMessage(
    "Create a vibrant infographic explaining photosynthesis as a recipe, styled like a colorful kids cookbook"
  );
  const imageParts1 = response1.candidates[0].content.parts.filter(
    (part) => part.inlineData && part.thought !== true,
  );
  const finalImagePart1 = imageParts1.at(-1);
  if (finalImagePart1) {
    fs.writeFileSync("photosynthesis.png", Buffer.from(finalImagePart1.inlineData.data, "base64"));
  }

  // Second turn: refine
  const response2 = await chat.sendMessage(
    "Update this infographic to be in Spanish. Do not change any other elements."
  );
  const imageParts2 = response2.candidates[0].content.parts.filter(
    (part) => part.inlineData && part.thought !== true,
  );
  const finalImagePart2 = imageParts2.at(-1);
  if (finalImagePart2) {
    fs.writeFileSync("photosynthesis_spanish.png", Buffer.from(finalImagePart2.inlineData.data, "base64"));
  }
  ````
</CodeGroup>

***

## ヒント

<AccordionGroup>
  <Accordion title="プロンプトの最適化">
    スタイルのキーワード（例: "cyberpunk, film grain, low contrast"）、アスペクト比、被写体、背景、照明、ディテールのレベルを指定してください。
  </Accordion>

  <Accordion title="Base64 形式">
    raw HTTP を使用する場合は、`data:image/png;base64,` のプレフィックスを含めず、raw Base64 文字列のみを使用してください。Python SDK では、`PIL.Image` オブジェクトを使うことでこれが自動的に処理されます。
  </Accordion>

  <Accordion title="画像出力を強制する">
    テキストなしで画像出力を確実に行うには、`"responseModalities"` を `["IMAGE"]` のみに設定してください。
  </Accordion>

  <Accordion title="画像がぼやけている、または解像度が低いのはなぜですか？">
    コードが中間の thought image を保存していないか確認してください。Gemini の画像レスポンスには、`thought` が `true` の image part が含まれる場合があります。これらは最終出力ではありません。`thought: true` の part はスキップし、`inlineData` が存在し、かつ `thought` が `true` ではない最後の image part を保存してください。テキスト出力が不要な場合は、混在したテキスト/画像レスポンスの処理を減らすために `"responseModalities": ["IMAGE"]` をリクエストしてください。
  </Accordion>
</AccordionGroup>

詳細は、[API リファレンス](/api/image/gemini/gemini-generates-image) を参照してください。

**公式ドキュメント:** [Nano Banana image generation](https://ai.google.dev/gemini-api/docs/image-generation)

* [Gemini Image Understanding](https://ai.google.dev/gemini-api/docs/image-understanding)
