图片生成
POST /v1/images/generations
OpenAI 兼容的图片生成接口,当前主力模型为 gpt-image-2。支持同步与异步两种模式:
- 同步:一次请求阻塞到出图,直接返回图片(适合低并发、即时场景)。
- 异步:提交后立即拿到任务 ID,再轮询取结果(适合大批量、避免长连接超时)。
可用模型
| 模型 | 分辨率档位 | 说明 |
|---|---|---|
gpt-image-2 |
1K / 2K / 4K | 主力模型,通用生图与编辑。 |
gpt-image-2.5 |
1K | 仅 1K 档位。 |
gpt-image-2.5-flare |
1K / 2K / 4K | 日常生图,出图更快。 |
gpt-image-2.5-sunburst |
1K / 2K / 4K | 精准编辑,擅长按指令改图。 |
flux-3-image |
768 / 1K / 1.5K / 2K / 4K | 文生图与参考图编辑,默认 1.5K,按成功请求计费。见 FLUX.3 接入指南。 |
以上模型均支持两种用法:
- 文生图:
POST /v1/images/generations(同步)或POST /v1/images/generations/async(异步)。 - 图生图:
POST /v1/images/edits(同步)或POST /v1/images/edits/async(异步),以 multipart 形式上传image与prompt,尺寸/分辨率参数与文生图完全一致。
兼容写法:
gpt-image-2-2K/gpt-image-2-4K这两个模型名仍然可用,便于已有集成继续调用,它们分别等价于gpt-image-2搭配resolution为2K/4K。新接入建议统一使用gpt-image-2+ 参数的写法。
下文的分辨率对照表、默认 1K 和参考图限制主要适用于 GPT 图片模型。
flux-3-image默认 1.5K、最多 10 张参考图、不支持mask,尺寸规则与按请求计费方式请参见 FLUX.3 接入指南。
如何选择分辨率档位
gpt-image-2 支持 1K / 2K / 4K 三个分辨率档位——用同一个模型名,通过参数选择,不需要换模型。有两种等价写法:
resolution(推荐):直接指定档位1K/2K/4K;画幅比例另用size指定,或不传(默认方图 1:1)。size:传该档位对应的像素尺寸(见下方对照表),网关据此同时确定档位与画幅比例。
| 目标 | 请求体写法 |
|---|---|
| 1K(默认) | 不传尺寸参数,或 "resolution": "1K" |
| 2K 方图 | "resolution": "2K",或 "size": "2048x2048" |
| 2K 横图 16:9 | "resolution": "2K", "size": "2560x1440",或直接 "size": "2560x1440" |
| 4K 方图 | "resolution": "4K",或 "size": "2880x2880" |
| 4K 横图 16:9 | "resolution": "4K", "size": "3840x2160",或直接 "size": "3840x2160" |
gpt-image-2.5-flare / gpt-image-2.5-sunburst 用法完全相同;gpt-image-2.5 仅支持 1K。
同步:POST /v1/images/generations
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
model |
string | 是 | 模型 ID,如 gpt-image-2。 |
prompt |
string | 是 | 图片描述提示词。 |
n |
integer | 否 | 生成数量,当前仅支持 1(默认 1)。 |
size |
string | 否 | 图片尺寸,格式为 宽x高,如 1024x1024、2560x1440、3840x2160,也可传 auto。它同时决定画幅比例与分辨率档位(见下方档位对照表)。不在对照表中的尺寸按像素面积归入档位:≤ 2,000,000 归为 1K;≤ 5,000,000 归为 2K;≤ 9,000,000 归为 4K;更大则返回 400。 |
resolution |
string | 否 | 分辨率档位,取值 1K / 2K / 4K(大小写不敏感;也接受别名 image_size)。优先级高于 size 隐含的档位;与 size 搭配使用可固定画幅比例、单独指定档位。若指定的档位该模型不支持,返回 400。 |
quality |
string | 否 | 画质档。gpt-image-2.5 系列取值为 low / medium / high / xhigh / max / auto;gpt-image-2 可选传入,当前不改变出图效果。该参数不影响分辨率档位。 |
response_format |
string | 否 | 返回形式:b64_json(默认,图片以 base64 内联在 JSON 里)或 url(返回一个约 2 小时有效的下载链接,见下文「响应」)。传其他值返回 400。 |
档位优先级:resolution > size 隐含的档位 > 默认 1K。
提示:图片较大(2K/4K)或并发较高时,建议传
"response_format": "url",响应体只有几百字节,客户端按需下载图片即可。
分辨率档位对照表
| 画幅比例 | 1K | 2K | 4K |
|---|---|---|---|
| 1:1 | 1024×1024 | 2048×2048 | 2880×2880 |
| 16:9 | 1280×720 | 2560×1440 | 3840×2160 |
| 9:16 | 720×1280 | 1440×2560 | 2160×3840 |
| 3:2 | 1248×832 | 2496×1664 | 3504×2336 |
| 2:3 | 832×1248 | 1664×2496 | 2336×3504 |
| 4:3 | 1152×864 | 2304×1728 | 3264×2448 |
| 3:4 | 864×1152 | 1728×2304 | 2448×3264 |
| 5:4 | 1120×896 | 2240×1792 | 3200×2560 |
| 4:5 | 896×1120 | 1792×2240 | 2560×3200 |
| 21:9 | 1456×624 | 3024×1296 | 3696×1584 |
模型按所选档位与画幅比例的原生分辨率出图,因此返回图片的实际像素尺寸可能与请求的
size略有出入。
计费说明
图片生成的计费单位与单价以你所在站点的「定价说明」和 Portal 定价页为准。响应中的 usage 反映本次生成的 token 用量,可作为对账参考;档位越高,生成的图片越大,费用也相应更高。
请求示例
cURL
curl https://api.modeltap.net/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-image-2",
"prompt": "a red fox running in snow, studio lighting",
"n": 1
}'cURL(用 size 指定 16:9 的 2K)
curl https://api.modeltap.net/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-image-2",
"prompt": "a red fox running in snow, studio lighting",
"size": "2560x1440",
"n": 1
}'cURL(用 resolution 单独指定档位)
curl https://api.modeltap.net/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-image-2.5-flare",
"prompt": "a red fox running in snow, studio lighting",
"size": "1024x1024",
"resolution": "2K",
"n": 1
}'Python
import openai
client = openai.OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.modeltap.net/v1",
)
resp = client.images.generate(
model="gpt-image-2",
prompt="a red fox running in snow, studio lighting",
n=1,
)
b64 = resp.data[0].b64_json # base64 编码的 PNGOpenAI SDK 没有 resolution 这个原生字段,通过 extra_body 传入即可:
resp = client.images.generate(
model="gpt-image-2",
prompt="a red fox running in snow, studio lighting",
size="1024x1024",
n=1,
extra_body={"resolution": "2K"},
)图生图:POST /v1/images/edits
以 multipart/form-data 形式上传原图与提示词,返回格式与同步文生图相同(base64 内联)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
image |
file | 是 | 输入图片,PNG / JPEG / WEBP,单张不超过 25 MB,整个请求合计不超过 32 MB。多张参考图时重复传 image[](或多个 image),最多 8 张。 |
prompt |
string | 是 | 编辑指令,描述要怎么改。 |
model |
string | 是 | 模型 ID,如 gpt-image-2、gpt-image-2.5-sunburst(擅长按指令改图)。 |
n |
integer | 否 | 生成数量,当前仅支持 1。 |
size / resolution / quality |
string | 否 | 与文生图语义一致,见上文参数表与档位对照表。 |
暂不支持
mask(蒙版)参数,传入会返回错误;请用prompt描述要修改的区域。图生图单次通常需要 1–3 分钟,高峰期可能更久。客户端读超时建议不低于 15 分钟,否则可能在出图前主动断开;也可以改用下文的异步图生图接口。
参考图也可以直接传图片链接或 data URL(JSON 写法,不用上传文件),同步和异步接口都支持,详见文末「用链接传参考图」一节。
cURL(单张图)
curl https://api.modeltap.net/v1/images/edits \
-H "Authorization: Bearer YOUR_API_KEY" \
-F image=@input.png \
-F model=gpt-image-2.5-sunburst \
-F prompt="turn the sky into a starry night, keep the fox unchanged" \
-F resolution=2KcURL(多张参考图,16:9 横图)
curl https://api.modeltap.net/v1/images/edits \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "image[]=@product.png" \
-F "image[]=@background.jpg" \
-F model=gpt-image-2 \
-F prompt="place the product from the first image onto the scene in the second image" \
-F size=2560x1440Python
import base64
import openai
client = openai.OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.modeltap.net/v1",
timeout=900, # 图生图耗时较长,读超时至少 15 分钟
)
with open("input.png", "rb") as f:
resp = client.images.edit(
model="gpt-image-2.5-sunburst",
image=f, # 多张参考图传列表: image=[f1, f2]
prompt="turn the sky into a starry night, keep the fox unchanged",
extra_body={"resolution": "2K"},
)
with open("output.png", "wb") as out:
out.write(base64.b64decode(resp.data[0].b64_json))响应
返回 base64 内联的图片:
{
"created": 1730000000,
"data": [
{
"b64_json": "iVBORw0KGgoAAAANSUhEUgAA...",
"revised_prompt": "..."
}
],
"usage": {
"input_tokens": 18,
"input_tokens_details": {
"image_tokens": 0,
"text_tokens": 18
},
"output_tokens": 7024,
"output_tokens_details": {
"image_tokens": 7024,
"text_tokens": 0
},
"total_tokens": 7042
}
}前端展示时加前缀:data:image/png;base64,<b64_json>。
传 "response_format": "url" 时,返回下载链接而不是 base64:
{
"created": 1730000000,
"data": [
{
"url": "https://<bucket>.r2.cloudflarestorage.com/...&X-Amz-Signature=...",
"revised_prompt": "..."
}
],
"usage": { "...": "与上面相同" }
}链接约 2 小时有效,请在有效期内下载或转存;图片在 48 小时后删除。图片已生成但链接暂时无法生成时(极少见),返回 502 且不计费,可以直接重试。
异步:POST /v1/images/generations/async
请求体与同步文生图完全一致(model / prompt / n / size / resolution / quality,语义与上文相同),但立即返回任务 ID,不阻塞出图。适合批量生成或客户端不希望长连接等待的场景。
本节是异步文生图。异步图生图见文末「异步图生图」一节。
1. 提交任务
curl https://api.modeltap.net/v1/images/generations/async \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-image-2",
"prompt": "a red fox running in snow",
"size": "2560x1440",
"n": 1
}'返回 202 Accepted:
{
"id": "nximg_xxxxxxxx",
"status": "queued",
"created": 1730000000,
"object": "image.generation.async"
}2. 轮询结果:GET /v1/images/generations/async/{job_id}
curl https://api.modeltap.net/v1/images/generations/async/nximg_xxxxxxxx \
-H "Authorization: Bearer YOUR_API_KEY"status 取值:queued → processing → succeeded(或 failed)。建议每 1–2 秒轮询一次,通常数秒到数十秒完成。
进行中:
{ "id": "nximg_xxxxxxxx", "status": "processing", "created": 1730000000 }完成:
{
"id": "nximg_xxxxxxxx",
"status": "succeeded",
"created": 1730000000,
"data": [
{
"url": "https://<bucket>.r2.cloudflarestorage.com/...&X-Amz-Signature=...",
"revised_prompt": "..."
}
],
"usage": {
"input_tokens": 18,
"input_tokens_details": {
"image_tokens": 0,
"text_tokens": 18
},
"output_tokens": 7024,
"output_tokens_details": {
"image_tokens": 7024,
"text_tokens": 0
},
"total_tokens": 7042
}
}失败:
{
"id": "nximg_xxxxxxxx",
"status": "failed",
"created": 1730000000,
"error": { "type": "upstream_error", "message": "generation failed", "code": "..." }
}关于
url:与同步返回内联 base64 不同,异步成功时返回一个带签名的下载链接(有效期约 2 小时)。请在有效期内下载/转存,过期需重新生成。失败任务不计费。
参数说明
| 字段 | 说明 |
|---|---|
id |
任务 ID(nximg_ 前缀),用于轮询。与你的 API Key 所属组织绑定,他人无法访问。 |
status |
queued / processing / succeeded / failed。 |
data[].url |
成功时的图片下载链接(presigned,约 2h 有效)。 |
data[].revised_prompt |
模型改写后的提示词(可能为空)。 |
usage |
成功时返回,结构与同步一致。 |
异步图生图:POST /v1/images/edits/async
同步图生图 POST /v1/images/edits 的异步版本。请求格式完全相同(multipart/form-data 上传文件,或 JSON 写法传图片链接,参数见上文「图生图」一节),但立即返回任务 ID,出图后再轮询取结果。图生图耗时较长(通常 1–3 分钟),批量或不想长时间保持连接时推荐使用。
与同步图生图的区别:
- 输入图片最多 8 张,单张不超过 25 MB,整个请求合计不超过 32 MB。
- 不支持
mask,传入会直接返回 400。 - 成功时返回带签名的下载链接(约 2 小时有效),不是内联 base64。
1. 提交任务
curl https://api.modeltap.net/v1/images/edits/async \
-H "Authorization: Bearer YOUR_API_KEY" \
-F image=@input.png \
-F model=gpt-image-2 \
-F prompt="turn the sky into a starry night, keep the fox unchanged" \
-F resolution=2K多张参考图时重复传 image[](或多个 image),与同步接口一致。
返回 202 Accepted:
{
"id": "nximg_xxxxxxxx",
"status": "queued",
"created": 1730000000,
"object": "image.edit.async"
}2. 轮询结果:GET /v1/images/edits/async/{job_id}
curl https://api.modeltap.net/v1/images/edits/async/nximg_xxxxxxxx \
-H "Authorization: Bearer YOUR_API_KEY"返回格式与异步文生图完全相同(queued → processing → succeeded / failed,成功时 data[].url 为下载链接,并附 usage)。建议每 2–5 秒轮询一次。异步文生图和异步图生图的任务 ID 通用,也可以用 GET /v1/images/generations/async/{job_id} 查询。
Python 示例
import time
import requests
API = "https://api.modeltap.net/v1"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}
# 1. 提交任务(多张参考图: files=[("image[]", f1), ("image[]", f2)])
with open("input.png", "rb") as f:
job = requests.post(
f"{API}/images/edits/async",
headers=HEADERS,
files=[("image", ("input.png", f, "image/png"))],
data={
"model": "gpt-image-2",
"prompt": "turn the sky into a starry night, keep the fox unchanged",
"resolution": "2K",
},
timeout=120,
).json()
# 2. 轮询结果
while True:
r = requests.get(f"{API}/images/edits/async/{job['id']}", headers=HEADERS, timeout=30).json()
if r["status"] in ("succeeded", "failed"):
break
time.sleep(3)
if r["status"] == "succeeded":
img = requests.get(r["data"][0]["url"], timeout=120).content # 链接约 2 小时有效
open("output.png", "wb").write(img)
else:
print(r["error"])用链接传参考图(JSON 写法)
适用于 POST /v1/images/edits(同步)和 POST /v1/images/edits/async(异步)。图片已经在对象存储、CDN 或图床上时,不必先下载再上传,直接把链接放进 JSON 请求体即可。
工作方式:网关收到请求后先下载并校验每一张参考图,全部合格才会开始出图。任何一张有问题,都会在出图前返回 400,不计费。这样可以避免「链接失效,却生成了一张和参考图无关的图并被收费」的情况。
请求格式
- 请求头:
Content-Type: application/json(不能与 multipart 混用,一个请求只能用一种写法)。 - 请求体参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
model |
string | 是 | 模型 ID,如 gpt-image-2。 |
prompt |
string | 是 | 编辑指令。多张参考图时,可以用「第一张图」「第二张图」指代,顺序与 images 数组一致。 |
images |
array | 是 | 参考图列表,最多 8 张,每一项的写法见下表。 |
size / resolution / quality |
string | 否 | 与文生图语义一致,见上文参数表与档位对照表。 |
response_format |
string | 否 | b64_json(默认)或 url。仅同步接口有效;异步接口始终返回链接。 |
n |
integer | 否 | 当前仅支持 1。 |
不支持 mask,传入会返回 400。
images 每一项的写法
以下写法都可以,也可以在同一个数组里混用:
| 写法 | 示例 |
|---|---|
| 图片链接(字符串) | "https://cdn.example.com/product.png" |
| data URL(字符串) | "data:image/png;base64,iVBORw0KGgo..." |
| OpenAI 风格对象 | {"image_url": "https://cdn.example.com/product.png"} |
| OpenAI 风格嵌套对象 | {"image_url": {"url": "https://cdn.example.com/product.png"}} |
也可以用 image 字段代替 images,值可以是单个字符串或数组。
链接要求
| 项目 | 要求 |
|---|---|
| 协议与端口 | 只支持 https://,且必须是默认端口 443;不支持 http://,也不支持在链接里写端口号。 |
| 地址 | 必须是公网可直接访问的域名;不能是 IP 地址、localhost 或内网地址。 |
| 访问权限 | 网关下载时不带任何 Cookie、登录态或自定义请求头。需要登录才能看的图片、开启了防盗链(校验 Referer)的图片都会下载失败;私有对象请提供带签名的临时链接(如 S3 / OSS / COS / R2 的预签名 URL)。 |
| 重定向 | 不跟随重定向。短链、需要跳转的分享链接会被拒绝,请提供跳转后的最终图片地址。 |
| 格式 | 只接受 PNG / JPEG / WEBP。按文件内容判断格式,不看链接后缀和对方返回的 Content-Type;GIF、HEIC、SVG、BMP 会被拒绝。 |
| 大小 | 单张不超过 25 MB,所有参考图合计不超过 64 MB。 |
| 下载超时 | 连接 5 秒,单张图片下载总时长 30 秒;超时即报错。 |
| 签名链接有效期 | 同步接口:请求发出时有效即可。异步接口:提交任务时就会下载参考图,所以链接只需在提交时有效,不必覆盖整个排队和出图时间。 |
建议:参考图尽量先压缩再传,每张控制在 2 MB 以内(例如转成长边不超过 2048 像素的 JPEG)。图片越小,提交越快、出图成功率越高,高峰期尤其明显。
data URL 要求
- 格式必须是
data:image/png;base64,...、data:image/jpeg;base64,...或data:image/webp;base64,...。 - base64 必须合法,声明的类型必须与实际内容一致(例如声明
image/png但内容是 JPEG,会被拒绝)。 - data URL 计入整个请求 32 MB 的上限,base64 编码会让体积增大约 1/3,所以单张原图最好不超过约 20 MB;大图建议改用链接。
把本地文件转成 data URL:
import base64
def to_data_url(path: str) -> str:
data = open(path, "rb").read()
if data.startswith(b"\x89PNG"):
mime = "image/png"
elif data.startswith(b"\xff\xd8\xff"):
mime = "image/jpeg"
elif data[:4] == b"RIFF" and data[8:12] == b"WEBP":
mime = "image/webp"
else:
raise ValueError("只支持 PNG / JPEG / WEBP")
return f"data:{mime};base64,{base64.b64encode(data).decode()}"示例
cURL:同步,两张参考图(一张链接,一张 data URL),返回链接
curl https://api.modeltap.net/v1/images/edits \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-image-2",
"prompt": "把第一张图里的产品放到第二张图的场景中,保持产品外观不变",
"images": [
"https://cdn.example.com/product.png",
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."
],
"size": "2560x1440",
"response_format": "url"
}'Python:同步
import requests
API = "https://api.modeltap.net/v1"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}
r = requests.post(
f"{API}/images/edits",
headers=HEADERS,
json={
"model": "gpt-image-2",
"prompt": "把天空改成星空,其余保持不变",
"images": ["https://cdn.example.com/photo.jpg"],
"response_format": "url",
},
timeout=900, # 图生图耗时较长,读超时至少 15 分钟
)
d = r.json()
if r.status_code != 200:
raise RuntimeError(d["error"]["message"]) # 例如 "images[0]: host cdn.example.com answered HTTP 404"
img = requests.get(d["data"][0]["url"], timeout=120).content # 链接约 2 小时有效
open("output.png", "wb").write(img)Python:异步
import time
import requests
API = "https://api.modeltap.net/v1"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}
r = requests.post(
f"{API}/images/edits/async",
headers=HEADERS,
json={
"model": "gpt-image-2",
"prompt": "把天空改成星空,其余保持不变",
"images": ["https://cdn.example.com/photo.jpg"],
},
timeout=120,
)
job = r.json()
if r.status_code != 202: # 参考图有问题时,提交阶段就返回 400
raise RuntimeError(job["error"]["message"])
while True:
res = requests.get(f"{API}/images/edits/async/{job['id']}", headers=HEADERS, timeout=30).json()
if res["status"] in ("succeeded", "failed"):
break
time.sleep(3)报错对照
参考图有问题时,返回 HTTP 400,error.type 为 invalid_request_error。针对某一张图的错误,message 以 images[序号]: 开头(序号从 0 开始,对应 images 数组中的位置),后面是具体原因;针对整个请求的错误(如张数超限、传了 mask、没有传图片)没有序号前缀。报错里只会出现域名,不会回显完整链接。
message 中的原因 |
含义 | 处理方法 |
|---|---|---|
only https:// URLs are accepted |
链接不是 https | 改用 https 链接 |
only the default https port 443 is allowed |
链接里带了端口号 | 去掉端口,使用标准 https 地址 |
URL host must be a domain name, not an IP |
链接里是 IP 地址 | 改用域名 |
URL host is not a public hostname / resolves to a non-public address |
是 localhost、内网域名,或域名解析到了内网地址 | 使用公网可访问的地址 |
could not resolve host ... |
域名无法解析 | 检查域名拼写 |
answered with a redirect (3xx) |
链接发生了跳转 | 改用跳转后的最终地址 |
answered HTTP 403 / answered HTTP 404 等 |
对方拒绝访问或文件不存在(常见于防盗链、需要登录、签名链接已过期) | 确认链接可以匿名直接打开;私有文件请用未过期的预签名链接 |
timed out fetching from host ... / could not fetch from host ... |
下载超时或连接失败 | 确认对方服务可用、下载速度足够,或改用 data URL |
content is not a PNG, JPEG or WebP image |
下载到的内容不是支持的图片(例如 HTML 页面、GIF、HEIC) | 确认链接直接指向图片文件,并转换为 PNG / JPEG / WEBP |
image larger than ... bytes / images exceed ... bytes in total |
单张超过 25 MB,或合计超过 64 MB | 压缩图片或减少张数 |
data URL must be data:image/(png|jpeg|webp);base64, / data URL is not valid base64 / data URL content is not a valid image/... |
data URL 格式不对、base64 不合法,或声明类型与内容不符 | 按上文「data URL 要求」生成 |
too many images (max 8) |
参考图超过 8 张 | 减少到 8 张以内 |
mask is not supported with a JSON body |
传了 mask |
去掉 mask,用 prompt 描述要修改的区域 |
images is required (a list of image URLs or data URLs) |
没有传图片,或 images 为空数组 |
至少传一张参考图 |
计费
- 参考图校验失败:不出图,不计费。
- 校验通过后出图成功:与上传文件的写法计费完全相同。