外观
生图接入指南
适合需要通过 API 或 SDK 生成、编辑图片的用户。本文用三个当前网关识别的模型示例,带你完成一次最小请求,并把返回的图片保存到本地。
先看结论
| 模型 | 请求地址 | 认证头 | 图片通常在哪里 |
|---|---|---|---|
gpt-image-2 | 生成:https://api.bestai.chat/v1/images/generations编辑: https://api.bestai.chat/v1/images/edits | Authorization: Bearer <BestAI Key> | data[].b64_json,有些上游也会返回 data[].url |
gemini-3.1-flash-image | https://api.bestai.chat/v1beta/models/gemini-3.1-flash-image:generateContent | x-goog-api-key: <BestAI Key> | candidates[].content.parts[].inlineData |
gemini-3-pro-image | 同上,把 URL 中的模型名替换掉 | x-goog-api-key: <BestAI Key> | candidates[].content.parts[].inlineData |
几点需要先分清:
- 这里的
<BestAI Key>是你在 BestAI 控制台创建的 Key,不是 Google AI Studio Key,也不是 OpenAI 官方 Key。 - OpenAI 生成和编辑使用两个 endpoint;Gemini 没有单独的编辑 endpoint,在同一个
generateContent请求中附上原图即可。 - 模型、分组、尺寸和价格属于运营配置,以控制台当前显示为准。文档中的模型名只用于示例。
gemini-3-pro-image是当前网关保留的兼容模型 ID。它是否可用、实际映射到哪个上游账号,由 Key 所属分组和服务端映射决定;不要把它当成始终独立、始终可用的上游模型。- 下面的验证请求会产生用量。第一次请使用
1K、n=1和简短提示词;1K只是输出规格,不代表固定价格。
开始前准备
在当前终端设置 Key。不要把真实值写进代码仓库、截图或聊天记录:
bash
export BESTAI_API_KEY="sk-你的Key"建议先在仪表盘确认余额和 Key 额度,再开始测试。
OpenAI:gpt-image-2
1. 发出最小请求
OpenAI 图片接口的 Base URL 是 https://api.bestai.chat/v1,完整 endpoint 是 /images/generations。请求体先只保留模型、提示词、尺寸和数量:
bash
curl -sS \
"https://api.bestai.chat/v1/images/generations" \
-H "Authorization: Bearer $BESTAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "一张简洁的蓝色几何海报,纯色背景,居中构图",
"size": "1024x1024",
"n": 1
}' \
-o openai-image-response.json \
-w "HTTP %{http_code}\n"注意:这里把响应保存成 JSON 文件。不要把整个 JSON 直接重命名成 .png,图片数据还需要解码。
2. 读取并保存图片
OpenAI 返回的常见结构是 data[0].b64_json。如果上游返回的是 data[0].url,下面脚本也会直接下载。脚本只使用 Python 标准库,不需要额外安装依赖:
bash
python3 - openai-image-response.json <<'PY'
import base64
import json
import sys
import urllib.request
with open(sys.argv[1], encoding="utf-8") as f:
response = json.load(f)
if response.get("error"):
raise SystemExit(response["error"])
item = (response.get("data") or [None])[0]
if not item:
raise SystemExit("响应中没有 data[0]")
if item.get("b64_json"):
image = base64.b64decode(item["b64_json"])
elif item.get("url"):
# URL 可能有有效期,拿到后立即下载,不要把完整 URL 写入日志。
with urllib.request.urlopen(item["url"], timeout=120) as source:
image = source.read()
else:
raise SystemExit("data[0] 中没有 b64_json 或 url")
if image.startswith(b"\x89PNG"):
suffix = ".png"
elif image.startswith(b"\xff\xd8"):
suffix = ".jpg"
elif image.startswith(b"RIFF") and image[8:12] == b"WEBP":
suffix = ".webp"
else:
suffix = ".bin"
output = "gpt-image-2" + suffix
with open(output, "wb") as f:
f.write(image)
print(f"已保存 {output} ({len(image)} bytes)")
PY如果你已经确认响应一定是 Base64,也可以使用命令行解码:
bash
# Linux
jq -r '.data[0].b64_json' openai-image-response.json | base64 -d > gpt-image-2.png
# macOS
jq -r '.data[0].b64_json' openai-image-response.json | base64 -D > gpt-image-2.png3. 使用原图编辑图片
编辑接口是 POST /v1/images/edits,必须使用 multipart/form-data 上传原图。先准备一张 PNG、JPEG 或 WebP 图片:
bash
export SOURCE_IMAGE="./source.png"
curl -sS \
"https://api.bestai.chat/v1/images/edits" \
-H "Authorization: Bearer $BESTAI_API_KEY" \
-F "image=@${SOURCE_IMAGE}" \
-F "model=gpt-image-2" \
-F "prompt=保留主体和构图,只把白色背景改为浅蓝色" \
-F "size=1024x1024" \
-F "n=1" \
-o openai-image-edit-response.json \
-w "HTTP %{http_code}\n"curl -F 会自动生成包含 boundary 的 Content-Type,不要手动填写 multipart/form-data 请求头。单个上传文件不要超过 20 MB。
编辑响应与生成响应的取图方式相同。复用上面“读取并保存图片”的 Python 脚本,只需将输入文件名改为 openai-image-edit-response.json。
4. OpenAI SDK 的最小写法
OpenAI Python SDK 可以复用同一个 Base URL:
python
import base64
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.bestai.chat/v1",
api_key=os.environ["BESTAI_API_KEY"],
)
result = client.images.generate(
model="gpt-image-2",
prompt="一张简洁的蓝色几何海报,纯色背景,居中构图",
size="1024x1024",
)
item = result.data[0]
if item.b64_json:
with open("gpt-image-2.png", "wb") as f:
f.write(base64.b64decode(item.b64_json))
elif item.url:
print("请立即下载 item.url;图片 URL 可能会过期")编辑时改用 client.images.edit(...);返回值的取图逻辑不变:
python
with open("source.png", "rb") as source:
result = client.images.edit(
model="gpt-image-2",
image=source,
prompt="保留主体和构图,只把白色背景改为浅蓝色",
size="1024x1024",
)某些客户端会把 gpt-image-2 作为 Responses API 的 image_generation 工具调用。那是另一条协议路径;本文的最小验证使用 Images API。如果客户端报“不支持 /v1/responses”,请在客户端切换到图片接口,或按该客户端的 Responses 配置说明处理。
Gemini:gemini-3.1-flash-image
1. 发出原生 Gemini 请求
Gemini 原生兼容接口的 Base URL 是 https://api.bestai.chat/v1beta。generateContent 是 endpoint 的动作名,不能省略:
bash
export GEMINI_IMAGE_MODEL="gemini-3.1-flash-image"
curl -sS \
"https://api.bestai.chat/v1beta/models/${GEMINI_IMAGE_MODEL}:generateContent" \
-H "x-goog-api-key: $BESTAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{"text": "生成一个简单的绿色圆形,纯色背景,仅用于接口验证"}
]
}
],
"generationConfig": {
"responseModalities": ["TEXT", "IMAGE"],
"imageConfig": {
"aspectRatio": "1:1",
"imageSize": "1K"
}
}
}' \
-o gemini-image-response.json \
-w "HTTP %{http_code}\n"responseModalities 必须包含 IMAGE。aspectRatio 和 imageSize 是生成配置,不要把它们放在 contents 里。常见比例包括 1:1、16:9、9:16、4:3 和 3:4;1K、2K、4K 是否可用,以当前模型和分组为准。
2. 从 inlineData 保存图片
Gemini 的图片通常位于 candidates[].content.parts[] 中,字段名是大小写敏感的 inlineData,其中:
mimeType是图片类型,例如image/png或image/jpeg。data是不带data:image/...;base64,前缀的 Base64 字符串。
下面脚本会保存响应中的全部图片 part:
bash
python3 - gemini-image-response.json <<'PY'
import base64
import json
import mimetypes
import sys
with open(sys.argv[1], encoding="utf-8") as f:
response = json.load(f)
if response.get("error"):
raise SystemExit(response["error"])
count = 0
for candidate in response.get("candidates", []):
for part in (candidate.get("content") or {}).get("parts", []):
inline = part.get("inlineData") or part.get("inline_data")
if not inline or not inline.get("data"):
continue
raw = base64.b64decode(inline["data"])
mime = inline.get("mimeType", "image/png")
suffix = mimetypes.guess_extension(mime) or ".bin"
if suffix == ".jpe":
suffix = ".jpg"
count += 1
output = f"gemini-image-{count:02d}{suffix}"
with open(output, "wb") as f:
f.write(raw)
print(f"已保存 {output} ({len(raw)} bytes)")
if count == 0:
raise SystemExit("响应中没有 inlineData 图片 part")
PY3. 使用原图编辑图片
Gemini 编辑仍请求 generateContent。区别是 parts 中必须同时包含修改要求和原图 inlineData。下面的 Python 只使用标准库,用来构造请求 JSON:
bash
export SOURCE_IMAGE="./source.png"
python3 - "$SOURCE_IMAGE" > gemini-image-edit-request.json <<'PY'
import base64
import json
import pathlib
import sys
source = pathlib.Path(sys.argv[1]).read_bytes()
request = {
"contents": [
{
"role": "user",
"parts": [
{"text": "保留主体和构图,只把白色背景改为浅蓝色"},
{
"inlineData": {
"mimeType": "image/png",
"data": base64.b64encode(source).decode("ascii"),
}
},
],
}
],
"generationConfig": {
"responseModalities": ["TEXT", "IMAGE"],
"imageConfig": {"aspectRatio": "1:1", "imageSize": "1K"},
},
}
json.dump(request, sys.stdout, ensure_ascii=False)
PY
curl -sS \
"https://api.bestai.chat/v1beta/models/${GEMINI_IMAGE_MODEL}:generateContent" \
-H "x-goog-api-key: $BESTAI_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @gemini-image-edit-request.json \
-o gemini-image-edit-response.json \
-w "HTTP %{http_code}\n"如果原图不是 PNG,将 mimeType 改成实际类型,例如 image/jpeg 或 image/webp。然后复用上面“从 inlineData 保存图片”的脚本,把输入文件名改为 gemini-image-edit-response.json。
4. 使用 gemini-3-pro-image
只需要替换模型 ID:
bash
export GEMINI_IMAGE_MODEL="gemini-3-pro-image"请求体和保存方式不变。这个 ID 在当前网关中用于兼容已有客户端;如果返回模型不可用、余额不足或上游拒绝,请先检查 Key 所属分组、余额和控制台当前配置,再尝试 gemini-3.1-flash-image。不要通过不断重试来解决额度问题。
如何判断图片真的生成成功
一次图片生成或编辑验证同时满足下面三点,才算接入完成:
- HTTP 请求成功,并且响应中确实找到
b64_json、url或inlineData图片数据。 - 脚本能把图片写入本地,且文件能被图片查看器打开。
- 在使用记录中找到同一时间的请求,核对模型、状态和实际扣费。
只有 HTTP 200、但没有图片字段时,不要直接把响应当成图片;先保存 JSON 并检查是否返回了文本、错误或安全拦截信息。图片 URL 可能有有效期,拿到后立即下载;Base64 图片很大时也不要把完整响应打印到终端日志。
常见错误
| 现象 | 第一检查项 |
|---|---|
401 / 403 | Key 是否完整、认证头是否正确、Key 所属分组是否开放生图、余额和额度是否足够 |
404 | OpenAI 是否漏了 /v1,Gemini 是否漏了 /v1beta 或 :generateContent |
| 模型不存在 / 不在白名单 | 使用控制台当前显示的模型 ID;不要把其他分组的模型名直接照抄过来 |
Insufficient account balance | 这是上游账号或当前分组的余额问题,先查余额/分组,不是保存图片脚本的问题 |
image file is required | OpenAI 编辑请求是否使用 -F "image=@...",并确认文件存在 |
image_endpoint_required | 当前分组的上游没有提供这条兼容接口;不要反复重试,也不要擅自更换 BestAI Base URL |
| 返回成功但没有图片 | 检查 data[].b64_json、data[].url 或 Gemini 的 inlineData,并确认请求包含图片模态 |
| 有图片但没有使用记录 | 当前客户端可能走了其他 Provider;回到配置中确认 Base URL 和 Key |
生图请求通常比短文本验证更贵。排查时保留请求时间、模型 ID、HTTP 状态和使用记录即可,不要提交完整 API Key、Cookie 或完整响应内容。
返回通用 SDK 接入指南查看其他协议,或回到文档中心选择下一项任务。
