Gemini 图片接入
Gemini 原生出图使用 generateContent 内容结构:文本与参考图放在 contents[].parts[] 中,生成内容从 candidates[].content.parts[] 读取。这与 OpenAI Images 的 prompt / data 结构不同。
接入方式与鉴权
在 控制台 确认支持图片输出的模型 ID、平台路由及鉴权方式。
| 接入方式 | 调用约定 |
|---|---|
| 官方 Gemini API | POST /v1beta/models/YOUR_IMAGE_MODEL:generateContent,官方 API Key 使用 x-goog-api-key |
| 平台原生兼容路由 | 仅当渠道明确开放同一路径和鉴权时,才能使用下方兼容示例;平台 Key 不等于 Google Key |
| 平台异步封装 | 内容输入与最终生成内容沿用官方结构;提交路由、鉴权、任务回执和查询方式使用平台单独提供的协议 |
不要把官方鉴权或路径当作封装接口约定
下方 cURL 仅适用于已确认提供 Gemini 原生路径及 x-goog-api-key 鉴权的渠道。如果开通的是 Bearer 鉴权或异步封装,请按渠道说明替换路径与请求头;不要同时发送多种密钥头进行试探。尚未获得任务协议时,先取得平台调用说明,不要猜测查询地址或任务字段。
文本生成图片
以下为原生兼容渠道的最小请求模板。模型放在 URL 中,不是 JSON 顶层的 model:
bash
curl --fail-with-body -X POST \
"https://api.yu-yu.ai/v1beta/models/YOUR_IMAGE_MODEL:generateContent" \
-H "x-goog-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [{
"role": "user",
"parts": [{"text": "生成一张极简咖啡店海报,暖色自然光"}]
}],
"generationConfig": {
"responseModalities": ["TEXT", "IMAGE"]
}
}' --output response.jsonYOUR_IMAGE_MODEL 必须替换成已开通且支持图片输出的模型;普通文本模型不能仅靠设置 responseModalities 变成出图模型。
请求字段
| 字段 | 说明 |
|---|---|
model(URL 路径参数) | 保留路径中的模型参数,将 YOUR_IMAGE_MODEL 替换为已开通模型 ID;原生请求体不额外添加此字段 |
contents | 对话内容数组 |
contents[].role | 用户输入使用 user |
contents[].parts[].text | 文本提示词 |
contents[].parts[].inlineData | 内嵌参考图,包含 MIME 类型和 Base64 |
generationConfig.responseModalities | 请求输出模态,例如 TEXT 与 IMAGE;以模型支持为准 |
generationConfig.imageConfig | 可选图片配置;宽高比、输出尺寸等取值必须与选定模型及渠道匹配 |
使用参考图编辑
将请求中的 parts 替换为下面的内容,在独立 part 中提供图片和文本:
json
[
{
"inlineData": {
"mimeType": "image/png",
"data": "BASE64_OF_INPUT_PNG"
}
},
{"text": "保留杯子的外形与位置,将背景改成木质咖啡桌"}
]data 使用图片文件的纯 Base64,不附加 data:image/png;base64, 前缀;mimeType 应与文件真实格式一致。图片数量、体积和可用格式以当前模型及渠道限制为准。不要把 OpenAI 的 image、mask 字段直接搬到 Gemini 请求体。
读取文字与图片
最终生成内容的结构示意(字段可能按结果缺省):
json
{
"candidates": [{
"content": {
"role": "model",
"parts": [
{"text": "已生成海报。"},
{"inlineData": {"mimeType": "image/png", "data": "BASE64_IMAGE_DATA"}}
]
}
}]
}不要假设第一个 part 一定是图片,也不要只读取文本。对于原生同步结果,或已从异步封装中取出的最终 GenerateContentResponse,可以使用以下代码:
python
import base64
import json
from pathlib import Path
result = json.loads(Path("response.json").read_text(encoding="utf-8"))
if result.get("error"):
raise RuntimeError("请求失败,请检查服务端错误信息")
extensions = {"image/png": ".png", "image/jpeg": ".jpg", "image/webp": ".webp"}
count = 0
for candidate in result.get("candidates") or []:
for part in (candidate.get("content") or {}).get("parts") or []:
if part.get("thought"):
continue
if part.get("text"):
print(part["text"])
image = part.get("inlineData") or {}
if not image.get("data"):
continue
extension = extensions.get(image.get("mimeType"))
if not extension:
raise RuntimeError("未知图片 MIME 类型,请先确认输出格式")
Path(f"output-{count}{extension}").write_bytes(
base64.b64decode(image["data"], validate=True)
)
count += 1
if count == 0:
raise RuntimeError("未返回图片,请检查模型、promptFeedback 和候选 finishReason")多轮编辑时保留原始对话 part 及服务端返回的签名字段(如 thoughtSignature),不要只复制可见文字再当成完整历史。
通过 OpenAI 图片接口调用
Gemini 渠道上的原生出图模型(nano-banana 系列、gemini-*-image)也可以按 OpenAI Images 契约调用:下游发 POST /v1/images/generations,网关把它翻译成上面的 generateContent 结构,再按 data[].b64_json 返回图片。
| OpenAI Images 字段 | 下发位置 |
|---|---|
prompt | contents[].parts[].text |
size = 16:9 这类比例,或 1024x1024 / 1792x1024 这类像素写法;aspect_ratio | generationConfig.imageConfig.aspectRatio |
size = 1K / 2K / 4K / 512px(大小写不敏感);quality = hd / high → 2K,4K → 4K,其它非空值 → 1K | generationConfig.imageConfig.imageSize(仅对确认接受该字段的模型族下发,见下) |
n > 1 | generationConfig.candidateCount |
image_size(显式传) | generationConfig.imageConfig.imageSize,覆盖上面的按族判定 |
stream | 不下发:原生出图是一次性调用,请求按非流式处理 |
imageSize 是 3 代才引入的参数,而且各代接受的取值不同:gemini-2.5-flash-image 会以 403 拒绝 imageSize(只能用 aspect_ratio),gemini-3-pro-image* 只接受 1K / 2K / 4K(不含 512px),gemini-3.1-flash-image* 额外接受 512px;聚合上游改名的模型(gemini-nano-banana-2.1 之类)无法判断代数。因此网关只对确认接受该取值的模型下发 imageSize,其余模型只下发画面比例,分辨率取模型默认值;确实要指定分辨率时显式传 image_size(1K / 2K / 4K / 512px)。
模型名必须满足下列之一,网关才认这是原生出图模型:在「模型设置 → Gemini → 支持生图的模型」里登记(图片入口既接受完整模型名,也接受族名片段),或者同时满足「属于内置的图片模型」与「名字带 gemini / nano-banana 族名标记」(gemini-2.5-flash-image、gemini-nano-banana-2.1、nano-banana-pro-preview 等)。后者是代码级判定,不依赖实例里保存过的旧配置。
判定前会先归一模型名:去掉厂商/路径前缀(google/gemini-3-pro-image、models/gemini-2.5-flash-image,只影响判定与 URL 后缀选择,URL 里的模型名保持上游写法),并抹平 preview 后缀差异(gemini-3-pro-image ↔ gemini-3-pro-image-preview)。同一个 Imagen/Gemini 图片模型的不同上游写法因此都能命中;归一后仍按整名比较,不做族名片段匹配——配置项在对话链路(决定是否为一次对话注入 IMAGE 模态)上也只做整名匹配,把它写成 gemini、flash 这类短片段会让该渠道的纯文本模型也被要求输出图片。模型还需要在「模型倍率/定价」里配置价格,否则按次计费的生图请求会在调用上游之前失败。
厂商前缀是聚合上游的命名约定(请求路径需要原样带上)。走官方端点的 Vertex 渠道请把模型名配成裸名:Vertex 的 URL 会自行补上 publishers/google/models/,再带一层厂商前缀会拼出 publishers/google/models/google/... 而拿到上游 404;同理,倍率表按调用方传入的模型名(OriginModelName)查表,前缀名不会被 gemini-3-pro-image* 这类默认倍率命中,需要在「模型倍率」里为该名字显式配置。
/v1/images/edits(参考图 / 蒙版)暂不支持:这些模型只有 :generateContent 一个入口,丢掉参考图会生成一张与请求无关的图片,因此网关直接返回错误,请改用上面的原生结构传 inlineData。开启请求体直通(PassThroughRequestEnabled 或渠道级直通)时这个本地闸门不生效,请求体会按原样发给 :generateContent。
平台异步封装
异步接入需要先完成提交、按任务协议等待成功,再取得最终生成内容。内容层仍按本页的 contents 和 candidates 结构处理,但不代表提交回执也是该结构。
上线前请确认任务 ID 字段、查询方法、终态、失败原因、超时策略和最终结果所在字段。不要使用视频任务路径,也不要把 streamGenerateContent 当作任务查询接口。
