跳转到内容
免费注册
GPT Image

GPT Image 图片编辑 API

通过 BetterToken 的 OpenAI 兼容接口调用 GPT Image,根据参考图片生成或编辑图片。

POST /v1/images/edits

图生图接口使用 multipart/form-data 请求体。上传一张或多张参考图片,并通过表单字段提交提示词和参数。普通参考图编辑不需要提供 mask。

推荐请求值

以下为起步建议,并非固定要求。建议先使用 n=1;接口接受 1 到 10 的整数,但实际返回图片数可能更少。

model=gpt-image-2
n=1
response_format=b64_json
output_format=png

单参考图使用字段名 image。多参考图使用可重复的字段名 image[]。

可选择 gpt-image-2、gpt-image-2.5-flare 或 gpt-image-2.5-sunburst;三款模型均已有普通参考图编辑成功结果。当前可用性请查看模型广场。

quality 为可选字段。gpt-image-2 接受 auto、low、medium、high;两款 2.5 模型还接受 xhigh 和 max。传入时必须使用非空字符串;不设置偏好时直接省略字段。size 同样可以省略,但不能传空字符串。质量参数被接受不保证画面质量随档位提高。

单参考图

准备真实参考图 reference.png,将 YOUR_API_KEY 替换为你的 BetterToken API Key。一个 Key 可调用所有可用模型。使用 curl -F 或 Python files 时,让客户端自动生成包含 boundary 的 Content-Type,不要手动覆盖。

提交这些表单字段:

表单字段示例值
modelgpt-image-2
prompt参考这张图片,生成一张更精致的方形产品主视觉,保持主体风格一致。
n1
size1024x1024
response_formatb64_json
output_formatpng
image选择本地文件 reference.png
终端窗口
curl --max-time 300 'https://bettertoken.ai/v1/images/edits' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-F 'model=gpt-image-2' \
-F 'prompt=参考这张图片,生成一张更精致的方形产品主视觉,保持主体风格一致。' \
-F 'n=1' \
-F 'size=1024x1024' \
-F 'response_format=b64_json' \
-F 'output_format=png' \
-F 'image=@reference.png'

多参考图

提交这些表单字段:

表单字段示例值
modelgpt-image-2
prompt综合这些参考图,生成一张统一风格的宣传海报。
n1
size1024x1024
response_formatb64_json
output_formatpng
image[]选择本地文件 reference-1.png
image[]选择本地文件 reference-2.jpg
image[]选择本地文件 reference-3.png
终端窗口
curl --max-time 300 'https://bettertoken.ai/v1/images/edits' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-F 'model=gpt-image-2' \
-F 'prompt=综合这些参考图,生成一张统一风格的宣传海报。' \
-F 'n=1' \
-F 'size=1024x1024' \
-F 'response_format=b64_json' \
-F 'output_format=png' \
-F 'image[]=@reference-1.png' \
-F 'image[]=@reference-2.jpg' \
-F 'image[]=@reference-3.png'

按蒙版局部编辑

需要引导模型修改指定区域时,可以增加一个可选文件字段 mask,不要重复提交 mask[]。Mask 编辑的可用性取决于模型和尺寸组合,普通编辑成功不代表 Mask 编辑也可用。

  • 原图和 mask 必须使用相同的文件格式和像素尺寸,每个文件必须小于 50 MB。为了获得最佳兼容性,建议原图和 mask 都使用带 Alpha 通道的 PNG。
  • mask 必须实际包含 Alpha 通道。完全透明像素(Alpha 0)表示允许模型重绘的区域;完全不透明像素(Alpha 255)用于引导模型保留该区域。
  • 普通 RGB 黑白图不是有效 mask,除非文件实际包含 Alpha 通道。
  • 如果提交多个 image[] 字段,mask 会应用于第一张输入图。
  • mask 是生成引导,不保证区域外的主体或像素保持不变。GPT Image 2 和 Flare 的实测均出现过非目标区域明显变化;Sunburst 的局部区域控制效果尚未验证。用于商品、标识或精确修图时,请检查非编辑区域后再采用结果。
终端窗口
curl --max-time 300 'https://bettertoken.ai/v1/images/edits' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-F 'model=gpt-image-2' \
-F 'prompt=Replace only the masked area with a blue circle. Preserve everything else.' \
-F 'n=1' \
-F 'size=1024x1024' \
-F 'response_format=b64_json' \
-F 'output_format=png' \
-F 'image=@original.png' \
-F 'mask=@mask.png'

使用 Python 按蒙版编辑

准备 original.png 和符合下方要求的 mask.png。Python 示例需要 requests;文件检查示例还需要 Pillow。在同一个 with 语句中打开两个文件,确保请求结束后正确关闭文件:

import requests
url = "https://bettertoken.ai/v1/images/edits"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
data = {
"model": "gpt-image-2",
"prompt": "Replace only the masked area with a blue circle. Preserve everything else.",
"n": "1",
"size": "1024x1024",
"response_format": "b64_json",
"output_format": "png",
}
with open("original.png", "rb") as image_file, open("mask.png", "rb") as mask_file:
files = {
"image": ("original.png", image_file, "image/png"),
"mask": ("mask.png", mask_file, "image/png"),
}
response = requests.post(url, headers=headers, data=data, files=files, timeout=300)
response.raise_for_status()
result = response.json()

上传前检查文件

下面的最小 Pillow 检查会验证文件格式、尺寸和 Alpha 通道这些强制要求。对于常见的局部 mask,如果 Alpha 通道没有同时包含完全透明和完全不透明的区域,代码还会输出提醒:

from pathlib import Path
from PIL import Image
image_path = Path("original.png")
mask_path = Path("mask.png")
if image_path.stat().st_size >= 50 * 1024 * 1024 or mask_path.stat().st_size >= 50 * 1024 * 1024:
raise ValueError("Each file must be smaller than 50 MB")
with Image.open(image_path) as image, Image.open(mask_path) as mask:
if image.format != mask.format:
raise ValueError("The image and mask formats must match")
if image.size != mask.size:
raise ValueError("The image and mask dimensions must match")
if "A" not in mask.getbands():
raise ValueError("The mask must contain an Alpha channel")
alpha_min, alpha_max = mask.getchannel("A").getextrema()
if alpha_min > 0 or alpha_max < 255:
print("Warning: for a typical local mask, include fully transparent and fully opaque areas")

Python 示例

此示例需要 requests。准备 reference.png 并替换 API Key 后运行;它会提交普通编辑请求,并按实际格式保存返回图片。

import base64
from pathlib import Path
import requests
url = "https://bettertoken.ai/v1/images/edits"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
}
data = {
"model": "gpt-image-2",
"prompt": "参考这张图片,生成一张更精致的方形产品主视觉,保持主体风格一致。",
"n": "1",
"size": "1024x1024",
"response_format": "b64_json",
"output_format": "png",
}
with open("reference.png", "rb") as image_file:
files = {
"image": ("reference.png", image_file, "image/png"),
}
response = requests.post(url, headers=headers, data=data, files=files, timeout=300)
response.raise_for_status()
result = response.json()
for index, item in enumerate(result["data"], start=1):
encoded = item["b64_json"]
if "," in encoded and "base64" in encoded.split(",", 1)[0]:
encoded = encoded.split(",", 1)[1]
image_bytes = base64.b64decode(encoded)
if image_bytes.startswith(b"\x89PNG\r\n\x1a\n"):
extension = "png"
elif image_bytes.startswith(b"\xff\xd8\xff"):
extension = "jpg"
elif image_bytes.startswith(b"RIFF") and image_bytes[8:12] == b"WEBP":
extension = "webp"
else:
raise ValueError("Unsupported image signature")
Path(f"output-{index}.{extension}").write_bytes(image_bytes)

推荐尺寸

size比例适用场景
auto自动自动选择尺寸
1024x10241:1方图,通用头像、封面、素材图
1536x10243:2横图,海报、banner、场景图
1024x15362:3竖图,移动端封面、人物海报
1536x11524:3标准横图,商品图、内容配图、横版素材
1152x15363:4标准竖图,移动端封面、竖版海报、人物图
2048x20481:1高清方图
2048x115216:9高清横图
3840x216016:94K 横图
2160x38409:164K 竖图

表格列出常用示例,并非封闭清单。显式尺寸必须为正数且是 16 的倍数,宽高各不超过 3840,宽高比不超过 3:1,像素总数为 655360 到 8294400。例如 2080x2080 是合法尺寸。实际交付尺寸可能不同;请读取图片真实尺寸,不要强行裁切。

保存返回图片

成功响应为 OpenAI 兼容图片响应结构。下面的金额用于展示回执格式,不代表固定价格:

{
"created": 1710000000,
"data": [
{
"b64_json": "iVBORw0KGgoAAAANSUhEUgAA...(truncated)",
"revised_prompt": "Optional revised prompt"
}
],
"bettertoken_image_billing": {
"currency": "CNY",
"settled_amount": "0.15",
"outputs": [
{
"index": 0,
"width": 1254,
"height": 1254,
"billing_resolution": "2K",
"currency": "CNY",
"amount": "0.15"
}
]
}
}

客户端应读取 data[].b64_json 中的每张图片,并允许 revised_prompt 等额外字段。BetterToken 在根级 bettertoken_image_billing 对象中返回计费明细:settled_amount 和每张图片的 amount 是十进制字符串,outputs[].index 从 0 开始。

保存图片时请检查图片字节并使用匹配的文件扩展名。业务需要固定编码时再按需转码;仅修改扩展名不会转换图片。文生图页面提供识别 PNG、JPEG、WebP 并保存每张图片的 Python 和 Node.js 标准库示例。

读取实际费用

bettertoken_image_billing 随生成结果一起返回,无需额外调用费用查询接口。

字段含义
currency本次结算币种。不要假定始终为 USD 或 CNY。
settled_amount本次请求实际结算总额,使用十进制字符串表示。
requested_resolution根据请求识别的尺寸档位。
outputs[].index图片编号,从 0 开始,对应 data[]。
outputs[].width、height对应图片的实际宽、高,单位为像素。
outputs[].billing_resolution对应图片最终使用的计费档位。
outputs[].currency、amount对应图片的结算币种和金额。

请求尺寸与计费档位可能不同。例如,已有请求 1024×1024、实际返回 1254×1254 并按 2K 结算的结果。请读取回执中的实际金额;当前单价在模型广场查看。

下面的代码接在 result = response.json() 后使用。金额保留为字符串展示;需要计算时使用十进制类型,避免浮点误差。缺少回执时不能把费用记为零。

from decimal import Decimal
billing = result.get("bettertoken_image_billing")
if billing is None:
print("Billing receipt unavailable; check your usage records.")
else:
total = Decimal(billing["settled_amount"])
print(f"Total: {billing['currency']} {total}")
for output in billing.get("outputs", []):
print(
f"Image {output['index'] + 1}: "
f"{output['width']}x{output['height']}, "
f"{output['billing_resolution']}, "
f"{output['currency']} {output['amount']}"
)

响应流程

图生图接口是同步响应模式。客户端提交 POST /images/edits 后,应保持 HTTP 请求连接并等待服务端返回。成功时,每张图片都在同一响应的 data[].b64_json 中返回,并附有交付与计费明细。

图生图不会返回 task_id,也没有单独的状态查询接口或结果下载接口。不需要轮询任务状态,也不能通过额外的 /images/... URL 再获取结果。

超时、重试和计费

HTTP 客户端超时建议设置为数分钟。超时、断连或含义不明的 5xx 不能证明编辑是否执行或计费;结算后写回结果时连接也可能失败,因此存在重复计费风险。不要自动重复编辑 POST。先检查消费记录或请求日志,保留返回的 request ID,以及已收到时的 X-BetterToken-Image-Receipt 和 X-BetterToken-Billing-State 响应头。客户端生成的 request ID 不会让服务端具备幂等性;主动重发可能产生新请求和新费用。没有单独的状态查询接口。

先修正被拒绝的输入、认证或额度问题。只有确认 429 表示请求已被拒绝后,才可退避重试。处理前,BetterToken 可能按最高适用单价乘以 n 预授权上限。因此,余额可能足以支付实际交付的 1K 图片,却不足以通过预授权;此时请求返回 403,且 error.code=insufficient_user_quota。最终按实际交付图片结算,根级 bettertoken_image_billing 返回最终金额、币种、交付尺寸和分档。

接入检查清单

  • Base URL 是 https://bettertoken.ai/v1。
  • Header 包含 Authorization: Bearer sk-...。
  • 请求使用 multipart/form-data。
  • 根据当前请求选择可用模型:gpt-image-2、gpt-image-2.5-flare 或 gpt-image-2.5-sunburst。
  • 单参考图使用 image,多参考图使用重复的 image[]。
  • 按蒙版编辑时只提交一个 mask,并确认它与原图格式、尺寸相同且包含 Alpha 通道。
  • 使用 response_format=b64_json;output_format 是请求值,保存前按字节识别实际格式。
  • n 可设为 1 到 10;建议使用 1,实际返回数可能更少。
  • size 可省略、设为 auto 或填写符合约束的尺寸。
  • 客户端能处理数分钟级别的生成耗时。
  • 日志和报错截图中不会泄露 API Key 或完整 base64 图片内容。

相关文档

POST/v1/images/edits

授权

Authorizationstringheader必填

Use your BetterToken API Key as a bearer token. Do not expose API keys in frontend browser code, screenshots, logs, tickets, or Git repositories.

请求体 multipart/form-data

modelenum<string>默认值: gpt-image-2必填

GPT Image 模型 ID。一个 BetterToken API Key 可调用所有可用模型。

可用选项: gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst

示例:"gpt-image-2"
promptstring必填

图片编辑或参考图生成说明。

示例:"参考这张图片,生成一张更精致的方形产品主视觉,保持主体风格一致。"
imagestring<binary>

单张参考图字段名。单参考图时使用 image。

image[]string[]

多张参考图字段名。多参考图时重复提交 image[]。

maskstring<binary>

可选的单个蒙版文件。当前后端只读取一个 mask。蒙版必须含 Alpha 通道,并与原图格式、尺寸一致;每个文件必须小于 50 MB。为获得最佳兼容性,建议原图和 mask 都使用带 Alpha 通道的 PNG。透明区域允许模型重绘,不透明区域用于引导保留;提交多个 image[] 时,mask 作用于第一张输入图。可用性取决于模型和尺寸组合。mask 是生成引导,不保证区域外主体或像素保持不变;请验收结果。

ninteger | string默认值: 1

允许 1~10,建议先用 1。实际交付可能少于请求张数;遍历 data[] 并按交付结果结算。

示例:"1"
sizestring默认值: 1024x1024

省略或 auto 使用自动尺寸。WxH 的宽高必须为正数且均为 16 的倍数,单边不超过 3840,长短边比不超过 3:1,总像素为 655360~8294400。示例不是封闭枚举,例如 2080x2080 也符合几何约束。实际输出以解码尺寸为准;参数合法不保证有对应可用服务。

示例:"1024x1024"
示例: ["auto","1024x1024","2048x2048","2080x2080","3840x2160"]
response_formatenum<string>默认值: b64_json

推荐固定为 b64_json。

可用选项: b64_json

示例:"b64_json"
output_formatstring默认值: png

请求的输出格式,例如 png。保存时按实际图片字节识别 PNG、JPEG 或 WebP,再选择对应扩展名;需要固定编码时按需转码。

示例:"png"
qualityenum<string>默认值: auto

画质选项:gpt-image-2 使用 auto、low、medium、high;两款 2.5 模型还接受 xhigh、max。省略时使用模型默认值;JSON null 按未填写处理,multipart 必须填写非空字符串。参数合法不保证当前有对应模型、尺寸和编辑组合的可用服务。参数接受不保证画面质量随档位提高。

可用选项: auto, low, medium, high, xhigh, max

示例:"auto"

响应

200BetterToken 扩展计费信息。按实际交付图片的像素与计费档位结算;请求档位不保证等于计费档位。金额是十进制字符串,以响应为准。

OpenAI 兼容图片响应。遍历 data[],读取每张图片的 b64_json,并允许 revised_prompt 等额外字段。实际交付数量可能少于请求数量。

createdinteger
示例:1710000000
dataobject[]
Show child attributes

Base64-encoded image content.

示例:"iVBORw0KGgoAAAANSUhEUgAA...(truncated)"

Optional revised prompt.

BetterToken 扩展计费信息。按实际交付图片的像素与计费档位结算;请求档位不保证等于计费档位。金额是十进制字符串,以响应为准。

Show child attributes

本次结算币种,不应假定为固定币种。

本次实际结算总额,十进制字符串;计算时使用十进制类型。

实际交付图片的编号、真实尺寸、计费档位和单张金额。index 从 0 开始,对应 data[] 中的图片。

必填范围: x >= 0

必填范围: x >= 1

必填范围: x >= 1

可用选项: 1K, 2K, 4K

对应图片的实际结算金额,十进制字符串。

根据请求识别的尺寸档位,可能与实际计费档位不同。

示例
{
  "created": 1710000000,
  "data": [
    {
      "b64_json": "iVBORw0KGgoAAAANSUhEUgAA...(truncated)",
      "revised_prompt": "<string>"
    }
  ],
  "bettertoken_image_billing": {
    "currency": "<string>",
    "settled_amount": "<string>",
    "outputs": [
      {
        "index": 0,
        "width": 1,
        "height": 1,
        "billing_resolution": "1K",
        "currency": "<string>",
        "amount": "<string>"
      }
    ],
    "partial": false,
    "requested_resolution": "<string>"
  }
}
400请求格式错误、缺少参数、JSON 或 multipart 解析失败、尺寸格式错误。
errorobject
Show child attributes
示例:"invalid request"
示例:"invalid_request_error"
示例:"invalid_request"
messagestring
示例:"insufficient quota"
示例
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}
401API Key 缺失或无效。
errorobject
Show child attributes
示例:"invalid request"
示例:"invalid_request_error"
示例:"invalid_request"
messagestring
示例:"insufficient quota"
示例
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}
402额度或余额不足。
errorobject
Show child attributes
示例:"invalid request"
示例:"invalid_request_error"
示例:"invalid_request"
messagestring
示例:"insufficient quota"
示例
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}
403余额或令牌额度不足,error.code 为 insufficient_user_quota。也可能不足以预占最高档单价乘图片数量上限的额度;按实际交付结算。结合 error.code 判断,不要只按 403 认定为权限错误。
errorobject
Show child attributes
示例
{
  "error": {
    "code": "insufficient_user_quota",
    "message": "Insufficient balance or token quota."
  }
}
429触发限速、并发限制或上游繁忙。
errorobject
Show child attributes
示例:"invalid request"
示例:"invalid_request_error"
示例:"invalid_request"
messagestring
示例:"insufficient quota"
示例
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}
500网关或上游服务异常。
errorobject
Show child attributes
示例:"invalid request"
示例:"invalid_request_error"
示例:"invalid_request"
messagestring
示例:"insufficient quota"
示例
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}