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 URLhttp://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图片描述。中文英文都可以。想要透明背景见 透明通道。

输入(决定模式)

参数类型说明
imagestring单张参考图。http(s) URL 或 base64 data URI。传了就走 edit 模式。
imagesarrayOpenAI Images 协议形态:[{"image_url":"..."}]。数组元素也可以是纯字符串 URL。同样触发 edit 模式。
ref_imagesstring[]多张参考图,最多 10 张(官方上限)。可与上面两个并用,顺序为 image → images → ref_images。
maskobject当前未使用(会回 warnings)。本服务走官方 edit 工作流,参考图整体参与,不做蒙版合成。

输出尺寸

参数类型默认说明
sizestring"1024x1024"三种写法都收:预设 1024x1024 / 1536x1024 / 1024x1536 / auto;任意 "宽x高";或比例 "16:9"(按总像素≈1024² 换算,见下)。
width / heightint1024分开传尺寸,与 size 等价(后写的生效)。
resolutionint1024仅 edit 模式生效:参考图缩放到约 resolution×resolution。写 0 = 保持每张参考图原尺寸。
尺寸限制:宽高都必须是 16 的倍数,且在 256~2048 之间(VAE 是 16 倍空间压缩)。 模型原生 2K,2048×2048 可直接出。超限或不是 16 的倍数会返回明确的 issues。

传比例时怎么换算(保持总像素 ≈ 1024²,各取 16 的倍数,所以不同比例的耗时相近):

你传实际出图你传实际出图
1:11024×10249:16768×1360
16:91360×7683:21248×832
4:31184×8802:3832×1248
3:4880×118421:91568×672

加速开关 turbo(默认开启)

参数类型默认说明
turbo 选填booltrue默认走 Viggle Turbo v0.2 蒸馏(5 步),一张 1024×1024 约 20 秒。传 false 回退原版 25 步(约 85 秒)的保守档。
默认就是加速版,你什么都不用传。 turbo 只是留一个"想更稳时回原版"的开关:
{ "prompt": "……", "turbo": false }   → 改走原版 25 步
两种模式下文生图和图生图都生效。

采样(服务已固定,不接受自定义)

本服务的采样参数由服务决定,不需要传、也不接受传:
固定项值
采样步数 steps5(默认 Turbo)/ 25(turbo=false)
CFG cfg1.0(本模型是 CFG-free)
采样器 sampler_nameeuler
调度器 schedulerViggle Turbo σ 序列(turbo=false 时为 simple)
去噪强度 denoise1.0
负面提示词 negative_prompt不生效,已拒绝(见下)
传了上面任意一个会直接报错并提示你删掉 —— 这是刻意的:避免你以为传了 steps=50 真的生效了。
negative_prompt 为什么被拒? 本服务 CFG=1.0,而 ComfyUI 在 CFG=1.0 时会走 cfg1 优化、直接跳过负向分支 —— 也就是说负面提示词从来没有参与过计算(这是它一直以来的行为,不是本次改动引入的)。 与其让你以为它在生效,不如明确告诉你它不生效。想排除某些内容,请改写进 prompt。
参数类型默认说明
seed 选填int随机不传就是随机种子。传了则固定,同 seed + 同参数 → 同结果,便于复现。
nint1只能是 1(或直接不传)。本服务一次只生成一张,传别的值会报错。

透明通道

参数类型默认说明
backgroundstring"auto"OpenAI 标准字段。写 "transparent" 输出带 alpha 的 PNG。
transparentboolfalse同上,简写别名。两个传一个就行。
output_formatstring"png"png / jpeg。透明必须用 png(传 jpeg + transparent 会报错,因为 JPEG 没有 alpha 通道)。
jpeg 由服务端转码(透明区域铺白底);webp 暂不支持(服务端没有 webp 编码器,会明确报错)。
response_formatstring"url"url 返回下载链接;b64_json 直接返回 base64(适合不想暴露 URL 的场景)。
模型是原生支援透明的(VAE 是 64 通道 RGBA 自编码器),不是抠图。服务会自动往 prompt 前面注入官方要求的 RGBA 指令。 适合做角色素材、贴纸、图层拆分。

其他 OpenAI 标准字段

参数类型说明
modelstring不传默认 qwen_image_2.1。传了不存在的值会明确报错并列出可用模型。
negative_promptstring不接受。本服务 CFG=1.0,负向条件从不参与计算,传了会报错。详见 采样那一节。
qualitystring接受但不改变出图(本模型没有 quality 档位),会回 warnings。
stylestring接受但不改变出图,风格请直接写进 prompt。
userstring接受并忽略,用于客户端自己标识用户。

完整示例

示例 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什么时候出现
400invalid_request_error参数有问题(见 issues)
400content_filtered提示词命中敏感词(见下方「内容规范」)
400invalid_json / empty_body请求体不是合法 JSON / 是空的
400missing_image调了 /v1/images/edits 但没传图
401invalid_api_keyAuthorization 头缺失或 key 不对
404not_found任务 id 不存在(服务重启后清空)或端点写错
429queue_full排队已满 50
429rate_limited30 秒内请求超过 200 次(防刷,与队列无关)
500internal_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仅供内部、工作学习及研究使用,禁止第三方使用,严禁用于违法生产和转发