跳到正文
openrouter blog·· 24 天前精選AI 評分63

如何透過 OpenRouter API 使用 Gemini 編輯圖片

Nano Banana API: Edit Images with Gemini in Code

AI 導讀

本文介紹如何透過 OpenRouter API 與 google/gemini-3.1-flash-image 進行圖片編輯,並提供 Python 與 TypeScript 的完整程式碼範例。

推薦理由

原文提供透過 API 編輯圖片的程式碼範例與實作細節,讀者可據此評估如何整合至現有工作流程。

正文 · AI 翻譯

本指南說明如何在程式碼中使用文字提示編輯影像。您透過 OpenRouter API 將來源影像和編輯提示送至 google/gemini-3.1-flash-image,編輯後的影像會回傳於回應中。『Nano Banana』是 Google Gemini 影像模型的暱稱。此 slug 為 Nano Banana 2,該系列的預設快速模型。因為您是透過 一個 API 進入,之後可以藉由變更一個欄位來使用不同的編輯模型。

影像編輯會改變現有的影像。影像生成則是從文字產生全新的影像。本指南涵蓋編輯功能,因此此處的每個請求都包含來源影像。若要從文字建立影像,請參閱 影像生成檔案 或 影像生成教學。

Before-and-after example of a natural-language image edit: a portrait photo, the prompt "Add a red wool scarf around the person's neck. Keep everything else the same.", and the edited result with the scarf added and everything else intact

TL;DR

  • 編輯只需一次請求。將來源影像放於 input_references,指令放於 prompt,然後從 data[0].b64_json 讀取編輯後的影像並解碼至磁碟。
  • google/gemini-3.1-flash-image 為 Nano Banana 2,預設的快速 Gemini 影像模型。在使用前請確認模型是否接受影像輸入,因為編輯支援程度不同。
  • 對於本地或私有檔案,請以 base64 資料 URL 方式傳送輸入;對於已託管的影像,則使用純 HTTP(S) URL。
  • 分階段編輯。將每次回傳的影像再次作為下一個來源,並一次呼叫一條指令,這樣改動會疊加。
  • 透過編輯一個欄位來切換編輯模型。

先決條件

您需要三樣東西:

  1. 來自 金鑰頁面 的 OpenRouter API 金鑰以及基礎 URL https://openrouter.ai/api/v1。
  2. 一個 HTTP 客戶端。範例使用 Python requests 和 TypeScript fetch。您也可以使用 curl 或 OpenRouter SDK。任何能送出帶 Authorization 標頭的 JSON POST 的客戶端皆可。
  3. 來源影像,可為本機檔案或公開 URL。

使用哪個模型

本指南的預設模型為 google/gemini-3.1-flash-image,Nano Banana 2。它以影像作為輸入並回傳編輯後的影像。Nano Banana 系列目前有四個成員:Nano Banana 2 (google/gemini-3.1-flash-image) 為本指南預設,Nano Banana 2 Lite (google/gemini-3.1-flash-lite-image) 是最便宜且最快速的,Nano Banana Pro (google/gemini-3-pro-image) 速度較慢但品質更高,原始 Nano Banana (google/gemini-2.5-flash-image) 為最早的模型。

影像目錄經常變動。模型會被新增、棄用或重新定價,因此今天固定的 slug 可能將來會被淘汰。在以模型為基礎開發前,請確認它是否接受影像輸入並支援您所需的編輯功能。您可以在 影像模型集合 中瀏覽具備編輯功能的模型。若要瀏覽目錄,請參閱 影像生成模型。

以下範例使用每個請求中顯示的 slug,因此您可以直接執行並稍後更改模型。請將金鑰存於環境變數,而非程式碼中:

export OPENROUTER_API_KEY="sk-or-..."

您的第一個影像編輯

要編輯影像,請在一次請求中送出來源影像與文字指令。編輯後的影像會回傳於回應中。以下是一個在 Python 中編碼本機檔案的可執行請求:

import base64, os, requests

api_key = os.environ["OPENROUTER_API_KEY"]

# Encode a local source image as a base64 data URL.
with open("portrait.jpg", "rb") as f:
    encoded = base64.b64encode(f.read()).decode()
source = f"data:image/jpeg;base64,{encoded}"

resp = requests.post(
    "https://openrouter.ai/api/v1/images",
    headers={"Authorization": f"Bearer {api_key}"},
    json={
        "model": "google/gemini-3.1-flash-image",
        "prompt": "Add a red wool scarf around the person's neck. Keep everything else the same.",
        "input_references": [
            {"type": "image_url", "image_url": {"url": source}}
        ],
    },
)
resp.raise_for_status()

相同的請求在 TypeScript 中:

import { readFileSync } from "node:fs";

const apiKey = process.env.OPENROUTER_API_KEY!;
const encoded = readFileSync("portrait.jpg").toString("base64");
const source = `data:image/jpeg;base64,${encoded}`;

const resp = await fetch("https://openrouter.ai/api/v1/images", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "google/gemini-3.1-flash-image",
    prompt: "Add a red wool scarf around the person's neck. Keep everything else the same.",
    input_references: [{ type: "image_url", image_url: { url: source } }],
  }),
});

請求主體在兩種語言中相同。將參考影像放於 input_references,指令放於 prompt。這就是整個請求。

編碼輸入影像:base64 或 URL

input_references 欄位可接受 base64 資料 URL 或 HTTP(S) URL。上述範例編碼了本機檔案。若您的影像已公開託管,請直接傳遞連結並跳過編碼:

"input_references": [
  {"type": "image_url", "image_url": {"url": "https://example.com/portrait.jpg"}}
]

影像公開且已託管時請使用 URL,因為這能保持請求主體小。對於本機或私有檔案請使用 base64。Gemini 接受 image/png、image/jpeg、image/webp、image/heic 與 image/heif 輸入。支援的格式因模型而異,請於傳送前檢查模型頁面。

從回應中檢索已編輯的影像

API 以 base64 資料形式返回已編輯的影像,位於 data 陣列中。解碼 b64_json 值並將其寫入檔案:

data = resp.json()["data"][0]
with open("edited.png", "wb") as out:
    out.write(base64.b64decode(data["b64_json"]))

TypeScript 版本:

import { writeFileSync } from "node:fs";

const { data } = await resp.json();
writeFileSync("edited.png", Buffer.from(data[0].b64_json, "base64"));

開啟 edited.png 以檢視結果。若想使用型別化的客戶端而非原始 HTTP,OpenRouter SDK 擁有一個 images 資源,會呼叫相同的端點:

from openrouter import OpenRouter

client = OpenRouter(api_key=api_key)
result = client.images.generate(
    model="google/gemini-3.1-flash-image",
    prompt="Add a red wool scarf around the person's neck. Keep everything else the same.",
    input_references=[{"type": "image_url", "image_url": {"url": source}}],
)

使用 pip install openrouter 安裝 SDK。它會重複使用之前定義的 api_key,因此不需要額外設定。

撰寫編輯提示

生成提示描述一個全新的影像。編輯提示則說明要改變什麼以及要保留什麼。先說明變更,再說明必須保持不變:

  • 物件交換: “將咖啡杯替換為一杯橙汁。保持手部位置與背景不變。”
  • 背景變更: “將背景改為夜晚的雪地街道。保持主體完全不變。”
  • 風格轉換: “將此照片渲染成水彩畫。保留構圖與主體姿勢。”
  • 文字修正: “將招牌文字改為 ‘OPEN’。匹配原始字型與顏色。”

你也可以將提示寫成一小段 JSON 文本:

"prompt": "{\"edit\": \"add sunglasses\", \"preserve\": [\"face\", \"hair\", \"lighting\"], \"style\": \"photorealistic\"}"

API 將此視為純文字,因此並非特殊模式。此結構可協助模型區分變更與保持不變的部分。嘗試句子形式與 JSON 形式,並保留效果較佳的版本。

再次編輯結果

一次編輯並不一定能得到你想要的結果。若要再次處理,將返回的影像作為下一個來源重新送出。取回回應中的 b64_json 值,將其轉換為資料 URL,並在下一個 input_references 中傳遞:

def edit(source_data_url, prompt):
    resp = requests.post(
        "https://openrouter.ai/api/v1/images",
        headers={"Authorization": f"Bearer {api_key}"},
        json={
            "model": "google/gemini-3.1-flash-image",
            "prompt": prompt,
            "input_references": [
                {"type": "image_url", "image_url": {"url": source_data_url}}
            ],
        },
    )
    resp.raise_for_status()
    item = resp.json()["data"][0]
    media_type = item.get("media_type", "image/png")
    return f"data:{media_type};base64,{item['b64_json']}"

step1 = edit(source, "Add a red wool scarf. Keep everything else the same.")
step2 = edit(step1, "Now make the scarf navy blue instead of red.")
step3 = edit(step2, "Add soft morning light coming from the left.")

每一次呼叫都會編輯上一次的結果,因此早期的變更會繼續保留。每次呼叫給一條指示。小幅編輯更易於檢查,也更易於在出錯時重新編輯。模型不會記住先前的提示,因此在每個新提示中重複應保留的部分。

更換編輯模型

若要將相同的編輯請求送至不同模型,請更改 model 欄位。來源影像、提示以及回應處理程式碼保持不變:

json={
    "model": "openai/gpt-5-image",  # was google/gemini-3.1-flash-image
    "prompt": "Add a red wool scarf. Keep everything else the same.",
    "input_references": [
        {"type": "image_url", "image_url": {"url": source}}
    ],
},

使用 google/gemini-3.1-flash-image 作為快速預設。使用 google/gemini-3.1-flash-lite-image 以取得最低價格。使用 google/gemini-3-pro-image 以獲得較高品質且可接受更高延遲。原始的 google/gemini-2.5-flash-image 仍可使用相同的請求結構,但上述更新模型是更佳預設。若想在自己的影像上 比較品質、成本或速度,可使用另一供應商的模型,例如 openai/gpt-5-image。此單欄位變更僅適用於接受影像輸入且支援相同 input_references 結構的模型,使用前請確認模型具備編輯功能。

若想按環境設定模型與其選項,而非在程式碼中,請使用 OpenRouter Presets。

錯誤與成本

這些失敗情況足以預先規劃:

  • 不支援的輸入。模型可能拒絕不支援的影像格式,也可能拒絕無法存取的 URL。在送出前請檢查檔案型別與 URL。
  • 影像過大。大型檔案可能逾時或失敗。先縮小影像,因為大多數編輯不需要 40 兆畫素的來源。
  • 文字而非影像。像「這張照片裡是什麼?」這類問題可能會使模型以文字回覆而非產生影像。API 會以 400 錯誤回傳,例如 Gemini could not generate an image (STOP),而非空回應。請改寫為指示而非提問,並在解碼前檢查 HTTP 狀態。

回應會在可用使用量資料時以 USD 報告每個請求的成本。請將其記錄以追蹤支出:

usage = resp.json().get("usage")
if usage:
    print(f"This edit cost ${usage['cost']}")

對於批次工作,請遵守 速率限制。對 429 與 5xx 回應重試時,逐次增加延遲,並限制同時執行的編輯數量。每次取得圖片後先儲存,再進行下一次編輯,避免一次失敗造成已完成的工作遺失。

後續步驟

複製第一個請求,使用自己的圖片並執行編輯。若要改為從文字產生圖片,請參閱 圖片產生檔案。要查詢目前支援編輯的模型,請瀏覽 圖片模型集合。

常見問題

我能使用 Gemini API 編輯圖片嗎?

可以。將原始圖片和文字指令一起送至 google/gemini-3.1-flash-image 的 OpenRouter API,編輯後的圖片會以 base64 形式回傳。該模型為 Nano Banana 2。完整請求可在一個螢幕內顯示,您可在 Python、TypeScript 或 curl 中執行。

圖片產生與圖片編輯有何差異?

圖片編輯會改變現有圖片;圖片產生則從文字產生全新圖片。每一次編輯請求都包含一張原始圖片於 input_references,以及說明要改變什麼、保留什麼的指令。如果請求沒有原始圖片,只根據文字提示進行,則屬於產生。

如何將圖片送至 API,使用 URL 或 base64?

input_references 欄位可接受本地或私人檔案的 base64 資料 URL,或公開主機圖片的純 HTTP(S) URL。若圖片已上線,使用 URL 形式可減少請求大小;若檔案在本機,則使用 base64 形式。Gemini 接受 png、jpeg、webp、heic 與 heif 輸入(image/png、image/jpeg、image/webp、image/heic、image/heif)。支援格式依模型而異,請於送出前檢視模型頁面。

我能使用非 Gemini 的模型來編輯圖片嗎?

可以。改變 model 欄位,其他請求保持不變。請先查閱 圖片模型集合,因為編輯支援、價格與速度因模型而異。

如何提示 AI 模型編輯圖片?

先描述要更改的內容,再說明要保留什麼,例如「將背景改為夜晚的雪景街道。保持主體不變。」每個請求只使用一條指令效果最佳。若需精準結果,請分小步驟編輯,並將每次回傳的圖片作為下一個提示的來源。

參考資料

來源:openrouter blog · openrouter.ai