Qwen-Image-2.1 图片生成 API
文生图 / 图生图(智能路由)· 原生透明通道 · 同步返回,OpenAI Images 协议兼容
独立服务,与视频生成 API 完全分离。
队列状态读取中…
队列上限:最多排队 50 张,超了直接拒绝。
服务同时最多跑 2 个任务,其余按提交顺序排队。排队数达到 50 时,新的请求会被立刻拒绝(HTTP 429,返回
error.type = "queue_full" 和当前排队数),不会进入队列。
提交成功时响应里有 queue_position 告诉你前面还有几个;
提交前也可以先 GET /health 看 queue.pending,快到 50 就放慢提交节奏。
| Base URL | http://47.111.83.139:13527 |
| 鉴权 | Authorization: Bearer <你的 API Key>
API Key 由管理员单独提供,不在此页面展示。 |
| 模型名 | qwen_image_2.1(GET /v1/models 可查) |
| 返回形态 | 同步:提交后直接返回 data[].url(OpenAI Images 协议兼容,不需要轮询)
队列较深、超过 1 小时仍未出图时会转为异步返回 task_id,见下方说明 |
| 队列 | 同时最多跑 2 个任务;排队上限 50,满了直接拒绝(429) |
快速开始
1. 文生图 —— 一次调用直接拿图
# 中文提示词请写进文件再提交(Windows 终端直接 -d '中文' 会编码错乱)
cat > body.json <<'EOF'
{"model":"qwen_image_2.1",
"prompt":"一只金色巨龙盘踞在崩塌的山巅,乌云翻涌,金色光柱自天而降,电影级质感",
"size":"1024x1024"}
EOF
curl -X POST http://47.111.83.139:13527/v1/images/generations \
-H "Authorization: Bearer <你的 API Key>" \
-H "Content-Type: application/json" \
--data-binary @body.json
{
"created": 1789959716,
"data": [
{ "url": "http://47.111.83.139:13527/images/qwen21/img_1101560001_00001_.png",
"filename": "img_1101560001_00001_.png", "width": 1024, "height": 1024 }
],
"task_id": "img_1101560001",
"status": "completed",
"elapsed_seconds": 19.6
}
响应直接就是 OpenAI Images 形态(created + data[].url),拿 data[0].url 下载即可。
一张 1024×1024 默认约 20 秒(5 步 Turbo;传 turbo=false 走原版 25 步约 85 秒),请求会一直等到出图再返回。
兼容 OpenAI Images 协议 —— 响应里的 created / data[].url / task_id 与 OpenAI 一致,
可以直接挂到按该协议解析的客户端上(如影策画布的 openai-images 协议插件),无需适配层。
2. 队列很深时会转异步(极少发生)
如果前面排了太多任务、1 小时内没能出图,响应会变成 202 并给 task_id(此时没有 data),
这时才需要改用轮询:
curl http://47.111.83.139:13527/v1/images/generations/<task_id> \
-H "Authorization: Bearer <你的 API Key>"
# status = completed 时 data[0].url 就是图
status 取值:pending(排队中,含 queue_position)→ running → completed / failed。
提交前可先 GET /health 看 queue.pending。
智能路由:不用指定模式
服务根据请求里
有没有参考图自动选模式,你不需要传模式参数:
| 请求里带 | 走哪个模式 | 出现字段 |
只有 prompt | 文生图 (t2i) | "mode": "t2i" |
另有 image / ref_images | 图生图 / 编辑 (edit) | "mode": "edit" |
edit 模式下尺寸怎么定?输出尺寸由第一张参考图 + resolution 决定,你传的 size 会被忽略(并回一条 warnings 提示)。
这是官方工作流的设计:用别的尺寸采样会让编辑跑偏。
端点一览
| 方法 | 路径 | 说明 | 鉴权 |
| POST | /v1/images/generations | 提交生成任务(JSON,智能路由) | 需要 |
| GET | /v1/images/generations/{id} | 查询任务状态 / 取结果 | 需要 |
| POST | /v1/images/edits | 提交编辑任务(multipart 上传,OpenAI 标准形式) | 需要 |
| POST | /v1/files/upload | 上传参考图,拿到可复用的 URL | 需要 |
| GET | /v1/models | 查询可用模型名 | 免 |
| GET | /health | 健康检查 + 实时队列长度 | 免 |
| GET | /stats.json | 任务统计 | 需要 |
| GET | /images/{file} | 下载生成的图片 | 免 |
| GET | /v1/files/{file} | 下载已上传的参考图 | 免 |
参数完整说明
标「默认」的参数都不用传 —— 不传就用默认值。只传 prompt 就能出图。
必填
| 参数 | 类型 | 说明 |
prompt 必填 | string | 图片描述。中文英文都可以。想要透明背景见 透明通道。 |
输入(决定模式)
| 参数 | 类型 | 说明 |
image | string | 单张参考图。http(s) URL 或 base64 data URI。传了就走 edit 模式。 |
images | array | OpenAI Images 协议形态:[{"image_url":"..."}]。数组元素也可以是纯字符串 URL。同样触发 edit 模式。 |
ref_images | string[] | 多张参考图,最多 10 张(官方上限)。可与上面两个并用,顺序为 image → images → ref_images。 |
mask | object | 当前未使用(会回 warnings)。本服务走官方 edit 工作流,参考图整体参与,不做蒙版合成。 |
输出尺寸
| 参数 | 类型 | 默认 | 说明 |
size | string | "1024x1024" | 三种写法都收:预设 1024x1024 / 1536x1024 / 1024x1536 / auto;任意 "宽x高";或比例 "16:9"(按总像素≈1024² 换算,见下)。 |
width / height | int | 1024 | 分开传尺寸,与 size 等价(后写的生效)。 |
resolution | int | 1024 | 仅 edit 模式生效:参考图缩放到约 resolution×resolution。写 0 = 保持每张参考图原尺寸。 |
尺寸限制:宽高都必须是 16 的倍数,且在 256~2048 之间(VAE 是 16 倍空间压缩)。
模型原生 2K,2048×2048 可直接出。超限或不是 16 的倍数会返回明确的 issues。
传比例时怎么换算(保持总像素 ≈ 1024²,各取 16 的倍数,所以不同比例的耗时相近):
| 你传 | 实际出图 | 你传 | 实际出图 |
1:1 | 1024×1024 | 9:16 | 768×1360 |
16:9 | 1360×768 | 3:2 | 1248×832 |
4:3 | 1184×880 | 2:3 | 832×1248 |
3:4 | 880×1184 | 21:9 | 1568×672 |
加速开关 turbo(默认开启)
| 参数 | 类型 | 默认 | 说明 |
turbo 选填 | bool | true | 默认走 Viggle Turbo v0.2 蒸馏(5 步),一张 1024×1024 约 20 秒。传 false 回退原版 25 步(约 85 秒)的保守档。 |
默认就是加速版,你什么都不用传。 turbo 只是留一个"想更稳时回原版"的开关:
{ "prompt": "……", "turbo": false } → 改走原版 25 步
两种模式下
文生图和图生图都生效。
采样(服务已固定,不接受自定义)
本服务的采样参数
由服务决定,不需要传、也不接受传:
| 固定项 | 值 |
采样步数 steps | 5(默认 Turbo)/ 25(turbo=false) |
CFG cfg | 1.0(本模型是 CFG-free) |
采样器 sampler_name | euler |
调度器 scheduler | Viggle Turbo σ 序列(turbo=false 时为 simple) |
去噪强度 denoise | 1.0 |
负面提示词 negative_prompt | 不生效,已拒绝(见下) |
传了上面任意一个会
直接报错并提示你删掉 —— 这是刻意的:避免你以为传了
steps=50 真的生效了。
negative_prompt 为什么被拒?
本服务 CFG=1.0,而 ComfyUI 在 CFG=1.0 时会走 cfg1 优化、直接跳过负向分支 ——
也就是说负面提示词从来没有参与过计算(这是它一直以来的行为,不是本次改动引入的)。
与其让你以为它在生效,不如明确告诉你它不生效。想排除某些内容,请改写进 prompt。
| 参数 | 类型 | 默认 | 说明 |
seed 选填 | int | 随机 | 不传就是随机种子。传了则固定,同 seed + 同参数 → 同结果,便于复现。 |
n | int | 1 | 只能是 1(或直接不传)。本服务一次只生成一张,传别的值会报错。 |
透明通道
| 参数 | 类型 | 默认 | 说明 |
background | string | "auto" | OpenAI 标准字段。写 "transparent" 输出带 alpha 的 PNG。 |
transparent | bool | false | 同上,简写别名。两个传一个就行。 |
output_format | string | "png" | png / jpeg。透明必须用 png(传 jpeg + transparent 会报错,因为 JPEG 没有 alpha 通道)。
jpeg 由服务端转码(透明区域铺白底);webp 暂不支持(服务端没有 webp 编码器,会明确报错)。 |
response_format | string | "url" | url 返回下载链接;b64_json 直接返回 base64(适合不想暴露 URL 的场景)。 |
模型是原生支援透明的(VAE 是 64 通道 RGBA 自编码器),不是抠图。服务会自动往 prompt 前面注入官方要求的 RGBA 指令。
适合做角色素材、贴纸、图层拆分。
其他 OpenAI 标准字段
| 参数 | 类型 | 说明 |
model | string | 不传默认 qwen_image_2.1。传了不存在的值会明确报错并列出可用模型。 |
negative_prompt | string | 不接受。本服务 CFG=1.0,负向条件从不参与计算,传了会报错。详见 采样那一节。 |
quality | string | 接受但不改变出图(本模型没有 quality 档位),会回 warnings。 |
style | string | 接受但不改变出图,风格请直接写进 prompt。 |
user | string | 接受并忽略,用于客户端自己标识用户。 |
完整示例
示例 1 · 文生图(固定种子,可复现)
curl -X POST http://47.111.83.139:13527/v1/images/generations \
-H "Authorization: Bearer <你的 API Key>" \
-H "Content-Type: application/json" \
-d '{
"prompt": "东方玄幻写实风格,不周山下崩塌山巅,万丈金色真龙盘踞,乌云紫雷,金色天缝倾泻金光",
"size": "1536x1024",
"seed": 20260921
}'
示例 2 · 单图编辑(改一处,其余保持)
curl -X POST http://47.111.83.139:13527/v1/images/generations \
-H "Authorization: Bearer <你的 API Key>" \
-H "Content-Type: application/json" \
-d '{
"prompt": "把背景换成黄昏的海边,人物保持不动",
"image": "http://47.111.83.139:13527/v1/files/my_photo.png",
"resolution": 1024
}'
示例 3 · 多图合成(最多 10 张)
curl -X POST http://47.111.83.139:13527/v1/images/generations \
-H "Authorization: Bearer <你的 API Key>" \
-H "Content-Type: application/json" \
-d '{
"prompt": "让图1的模特穿上图2的衣服、图3的鞋、戴图4的帽子,站在图5的场景里",
"ref_images": [
"https://example.com/model.png",
"https://example.com/coat.png",
"https://example.com/shoes.png",
"https://example.com/hat.png",
"https://example.com/scene.jpg"
]
}'
示例 4 · 透明背景 PNG(角色素材)
curl -X POST http://47.111.83.139:13527/v1/images/generations \
-H "Authorization: Bearer <你的 API Key>" \
-H "Content-Type: application/json" \
-d '{
"prompt": "一只可爱的卡通小龙贴纸,正面站立",
"background": "transparent",
"output_format": "png"
}'
示例 5 · 上传本地图再编辑
# 第一步:上传,拿回可复用的 URL / 文件名
curl -X POST http://47.111.83.139:13527/v1/files/upload \
-H "Authorization: Bearer <你的 API Key>" \
-F "image=@./my_photo.png"
# => {"data":[{"filename":"up_120000_000_png","url":".../v1/files/up_120000_000_png", ...}]}
# 第二步:用 upload 返回的 url 作为 image 提交编辑
curl -X POST http://47.111.83.139:13527/v1/images/generations \
-H "Authorization: Bearer <你的 API Key>" \
-H "Content-Type: application/json" \
-d '{"prompt":"改成水彩风格","image":"http://47.111.83.139:13527/v1/files/up_120000_000_png"}'
示例 6 · /v1/images/edits(OpenAI multipart 形式)
curl -X POST http://47.111.83.139:13527/v1/images/edits \
-H "Authorization: Bearer <你的 API Key>" \
-F "image=@./a.png" \
-F "image=@./b.png" \
-F "prompt=把两张图里的人合成到同一张合影里" \
-F "resolution=1024"
这个端点必须带图(否则 400)。它与 /v1/images/generations + ref_images 完全等价,选一个用即可。
示例 7 · Python(同步,一次调用拿图)
import requests
BASE = "http://47.111.83.139:13527"
H = {"Authorization": "Bearer <你的 API Key>"}
def generate(prompt, **kw):
# 同步:超时要给够(一张图 ~20 秒,排队时更久)
r = requests.post(f"{BASE}/v1/images/generations", headers=H,
json={"prompt": prompt, **kw}, timeout=900)
if r.status_code >= 400:
raise RuntimeError(r.json()) # 参数问题在这里能看到 issues
job = r.json()
if "data" not in job: # 队列太深时转异步
raise RuntimeError("转异步了,请轮询 task_id: " + job["task_id"])
return job["data"] # [{"url": ..., "width":..., "height":...}]
for img in generate("赛博朋克风格的城市夜景,霓虹倒影", size="1024x1024", seed=42):
print(img["url"])
# 用 OpenAI 官方 SDK 也行(记得调大超时):
# from openai import OpenAI
# c = OpenAI(base_url="http://47.111.83.139:13527/v1", api_key="<你的 API Key>", timeout=900)
# r = c.images.generate(model="qwen_image_2.1", prompt="...", size="1024x1024")
# print(r.data[0].url)
示例 8 · Node.js
const BASE = "http://47.111.83.139:13527";
const H = { "Authorization": "Bearer <你的 API Key>",
"Content-Type": "application/json" };
async function generate(prompt, extra = {}) {
const r = await fetch(`${BASE}/v1/images/generations`, {
method: "POST", headers: H, body: JSON.stringify({ prompt, ...extra }),
});
const job = await r.json();
if (!r.ok) throw new Error(JSON.stringify(job.error, null, 2));
while (true) {
const s = await (await fetch(`${BASE}/v1/images/generations/${job.id}`, { headers: H })).json();
if (s.status === "completed") return s.data;
if (s.status === "failed") throw new Error(s.error.message);
await new Promise(r => setTimeout(r, 3000));
}
}
console.log(await generate("一只在月球上弹吉他的猫", { background: "transparent" }));
关于 OpenAI SDK 兼容性:现在是同步返回了,OpenAI 官方 SDK 可以直接用 ——
images.generate() 拿到的就是 data[0].url。字段名(model / prompt / n /
size / response_format / background / output_format)也都是 OpenAI 的命名。
注意:SDK 的默认超时(多数是 60 秒)默认够用(一张图 ~20 秒),但排队时会更久,建议仍调到 300 秒以上。
内容规范
本服务设有敏感词过滤,命中会直接拒绝,不会生成。
禁止生成:色情/成人内容、儿童色情、暴力血腥、违法内容,以及隐私部位的露骨描写。
词表覆盖中、英、日、韩、俄、西、法、德、葡、意、阿、泰、越、印尼、土、波、荷等语言,
并会做归一化处理 —— 插空格、插符号、全角字符、换语言都绕不过去。
被拒绝时返回什么
HTTP 400
{
"error": {
"type": "content_filtered",
"code": "content_filtered",
"message": "提示词包含被禁止的内容,已拒绝生成。命中分类:色情;触发词:\"裸体\"(在 prompt 字段)。请修改后重试。",
"category": "色情",
"matched": "裸体",
"field": "prompt",
"issues": [
{ "field": "prompt", "code": "content_filtered", "message": "包含色情内容:「裸体」" }
]
}
}
会**明确告诉你命中了哪个词** —— 这是有意的:万一你的正常提示词被误伤(比如"裸体雕塑"这类美术场景),
你能立刻知道该改哪个词,而不是拿到一个莫名其妙的失败。
错误处理
所有参数错误都会逐条指出来,精确到字段名和第几个数组元素,不用猜。
参数错误(400)
{
"error": {
"type": "invalid_request_error",
"message": "参数有 3 处问题,逐条见 issues",
"issues": [
{ "field": "size", "code": "bad_format",
"message": "size 格式不对:收到 \"big\",应为 \"宽x高\"(如 \"1024x1024\"),或预设值 1024x1024 / 1024x1536 / 1536x1024 / auto" },
{ "field": "steps", "code": "out_of_range",
"message": "steps 需在 1~100 之间,收到 0" },
{ "field": "ref_images[3]","code": "too_many",
"message": "最多 10 张参考图(官方上限),当前给了 13 张" }
]
}
}
field 定位到具体字段(数组带下标);code 便于程序判断;message 是给人看的中文说明。
队列满(429)
{
"error": {
"type": "queue_full",
"message": "队列已满:当前排队 50 个,上限 50 个。请稍后重试(可在 GET /health 查看实时排队数)。",
"queue": { "pending": 50, "limit": 50 }
}
}
队列上限 50 是排队数(不含正在跑的那个)。想知道什么时候能提交,先 GET /health 看 queue.pending。
其他状态码
| 状态码 | type | 什么时候出现 |
| 400 | invalid_request_error | 参数有问题(见 issues) |
| 400 | content_filtered | 提示词命中敏感词(见下方「内容规范」) |
| 400 | invalid_json / empty_body | 请求体不是合法 JSON / 是空的 |
| 400 | missing_image | 调了 /v1/images/edits 但没传图 |
| 401 | invalid_api_key | Authorization 头缺失或 key 不对 |
| 404 | not_found | 任务 id 不存在(服务重启后清空)或端点写错 |
| 429 | queue_full | 排队已满 50 |
| 429 | rate_limited | 30 秒内请求超过 200 次(防刷,与队列无关) |
| 500 | internal_error | 服务内部错误,已记日志 |
任务本身失败(不是参数问题)时,HTTP 仍是 200,看 body 的 status: "failed" 和 error.message,里面带 ComfyUI 的具体报错节点。
查询模型
curl http://47.111.83.139:13527/v1/models # 免鉴权
{
"object": "list",
"data": [{
"id": "qwen_image_2.1",
"object": "model",
"owned_by": "qwen",
"modes": ["t2i", "edit"],
"mode_routing": "自动:请求带 image/ref_images 走 edit,否则走 t2i",
"max_ref_images": 10,
"native_size": "1024x1024(原生支持到 2048x2048)",
"transparency": "支持,background=transparent(PNG)"
}]
}
健康检查 / 队列
curl http://47.111.83.139:13527/health # 免鉴权
{
"status": "ok",
"backend": { "reachable": true, "busy": false },
"queue": { "pending": 3, "limit": 50, "running": 0 }
}
使用须知
| 项 | 说明 |
| 并发 | 同时最多跑 2 个任务,其余按提交顺序排队。一张 1024×1024 约 30~90 秒。 |
| 任务有效期 | 任务状态存在内存里,服务重启后清空。图片文件本身留在磁盘上,URL 仍可下载。 |
| 参考图上限 | 10 张。这是模型官方上限,不是服务限制。 |
| 写实文字 | 本模型对画面内文字渲染较好,可以尝试在 prompt 里写要显示的文字。 |
| 透明图用途 | 角色素材、贴纸、商品图、后期合成图层。 |
此API仅供内部、工作学习及研究使用,禁止第三方使用,严禁用于违法生产和转发