Appearance
Qwen-Image-Edit 编辑
网关地址:
https://ai.ospreyai.cn(公网) 模型:qwen_image_edit_2511_bf16无需后端 Bearer Token
概述
使用 Qwen-Image-Edit-2511 模型,支持 Turbo 4步(Lightning LoRA)和 Native 40步两种模式,可做高质量图片编辑(换装、改背景、物体替换)。任务异步执行:提交工作流 → 轮询状态 → 下载结果。任务状态查询、结果下载等通用接口见 任务管理。
前置条件: 需先通过 /api/v1/upload 上传输入图片。
bash
export GW="https://ai.ospreyai.cn"
export API_KEY="sk-your-api-key"接口清单
| 用途 | 方法 | 路径 |
|---|---|---|
| 上传输入图片 | POST | /api/v1/upload |
| 提交编辑任务 | POST | /api/v1/ai/image/generate |
| 查询任务状态 | GET | /api/v1/ai/tasks/{prompt_id} |
| 下载结果文件 | GET | /api/v1/ai/image/view/ |
| 查询队列 | GET | /api/v1/ai/queue |
提交图片编辑任务
POST /api/v1/ai/image/generate
Content-Type: application/json
Authorization: Bearer sk-xxx1. 上传图片
bash
curl -H "Authorization: Bearer $API_KEY" -X POST "$GW/api/v1/upload" \
-F "image=@/path/to/input.png" \
-F "type=input"
# 返回: {"name": "input.png", "subfolder": "", "type": "input"}2. 提交 Turbo 模式编辑(4步,推荐)
bash
curl -H "Authorization: Bearer $API_KEY" -X POST "$GW/api/v1/ai/image/generate" \
-H "Content-Type: application/json" \
-d '{
"prompt": {
"41": {"inputs": {"image": "input.png"}, "class_type": "LoadImage"},
"83": {"inputs": {"image": "input.png"}, "class_type": "LoadImage"},
"170:160": {"inputs": {"image": ["41", 0]}, "class_type": "FluxKontextImageScale"},
"170:161": {"inputs": {"unet_name": "qwen_image_edit_2511_bf16.safetensors", "weight_dtype": "default"}, "class_type": "UNETLoader"},
"170:162": {"inputs": {"clip_name": "qwen_2.5_vl_7b_fp8_scaled.safetensors", "type": "qwen_image", "device": "default"}, "class_type": "CLIPLoader"},
"170:146": {"inputs": {"vae_name": "qwen_image_vae.safetensors"}, "class_type": "VAELoader"},
"170:145": {"inputs": {"shift": 3.1, "model": ["170:161", 0]}, "class_type": "ModelSamplingAuraFlow"},
"170:152": {"inputs": {"strength": 1.0, "model": ["170:145", 0]}, "class_type": "CFGNorm"},
"170:156": {"inputs": {"pixels": ["170:160", 0], "vae": ["170:146", 0]}, "class_type": "VAEEncode"},
"170:168": {"inputs": {"value": false}, "class_type": "PrimitiveBoolean"},
"170:165": {"inputs": {"value": 4}, "class_type": "PrimitiveInt"},
"170:166": {"inputs": {"value": 40}, "class_type": "PrimitiveInt"},
"170:154": {"inputs": {"value": 1.0}, "class_type": "PrimitiveFloat"},
"170:155": {"inputs": {"value": 4.0}, "class_type": "PrimitiveFloat"},
"170:149": {"inputs": {"prompt": "", "clip": ["170:162", 0], "vae": ["170:146", 0], "image1": ["170:160", 0], "image2": ["83", 0]}, "class_type": "TextEncodeQwenImageEditPlus"},
"170:147": {"inputs": {"reference_latents_method": "index_timestep_zero", "conditioning": ["170:149", 0]}, "class_type": "FluxKontextMultiReferenceLatentMethod"},
"170:151": {"inputs": {"prompt": "Remove the jacket, keep the T-shirt underneath", "clip": ["170:162", 0], "vae": ["170:146", 0], "image1": ["170:160", 0], "image2": ["83", 0]}, "class_type": "TextEncodeQwenImageEditPlus"},
"170:148": {"inputs": {"reference_latents_method": "index_timestep_zero", "conditioning": ["170:151", 0]}, "class_type": "FluxKontextMultiReferenceLatentMethod"},
"170:153": {"inputs": {"lora_name": "Qwen-Image-Edit-2511-Lightning-4steps-V1.0-bf16.safetensors", "strength_model": 1.0, "model": ["170:152", 0]}, "class_type": "LoraLoaderModelOnly"},
"170:163": {"inputs": {"switch": ["170:168", 0], "on_false": ["170:152", 0], "on_true": ["170:153", 0]}, "class_type": "ComfySwitchNode"},
"170:164": {"inputs": {"switch": ["170:168", 0], "on_false": ["170:154", 0], "on_true": ["170:155", 0]}, "class_type": "ComfySwitchNode"},
"170:167": {"inputs": {"switch": ["170:168", 0], "on_false": ["170:166", 0], "on_true": ["170:165", 0]}, "class_type": "ComfySwitchNode"},
"170:169": {"inputs": {"seed": 1234567890, "steps": ["170:167", 0], "cfg": ["170:164", 0], "sampler_name": "euler", "scheduler": "simple", "denoise": 1.0, "model": ["170:163", 0], "positive": ["170:148", 0], "negative": ["170:147", 0], "latent_image": ["170:156", 0]}, "class_type": "KSampler"},
"170:158": {"inputs": {"samples": ["170:169", 0], "vae": ["170:146", 0]}, "class_type": "VAEDecode"},
"9": {"inputs": {"filename_prefix": "Qwen_Edit_2511", "images": ["170:158", 0]}, "class_type": "SaveImage"}
},
"extra_data": {}
}'响应:
json
{"prompt_id": "e5f6g7h8-...", "number": 101, "node_errors": {}}关键节点参数
| 节点 | 字段 | 说明 | 推荐值 |
|---|---|---|---|
| 41 | image | 输入图片文件名(需先上传) | 上传返回的 name |
| 83 | image | 参考图片文件名(可同 41 = 自我编辑) | 上传返回的 name |
| 170:151 | prompt | 编辑提示词(英文) | — |
| 170:168 | value | Turbo 模式开关(false=Native 40步) | false |
| 170:165 | value | Turbo 步数 | 4 |
| 170:169 | seed | 随机种子 | 任意整数 |
| 9 | filename_prefix | 输出文件名前缀 | — |
Turbo vs Native
| 模式 | 步数 | CFG | 速度 | 质量 |
|---|---|---|---|---|
| Turbo (Lightning LoRA) | 4 | 1.0 | ~2-6s | 好 |
| Native | 40 | 4.0 | ~15-20s | 更好 |
切换方式:将节点
170:168的value改为true(启用 Turbo / Lightning LoRA)。
提示词推荐
- 换装:
"Have the person in image 1 wear the clothes from image 2" - 改背景:
"Change the background of image 1 to a sunny beach" - 去除物体:
"Remove the jacket, keep the T-shirt underneath" - 物体替换:
"Replace the red wine with flowers"
缓存坑:若提交的工作流与历史完全相同(尤其 seed 相同),ComfyUI 会命中
execution_cached直接返回,outputs可能为空。提交时换个随机seed可避免。
Python 调用示例
python
import json, time, urllib.request
GW = "https://ai.ospreyai.cn"
API_KEY = "sk-your-api-key"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
# 1. 上传图片(参考「任务管理」页上传示例)
# 2. 提交 Turbo 编辑工作流
nodes = {
"41": {"inputs": {"image": "input.png"}, "class_type": "LoadImage"},
"83": {"inputs": {"image": "input.png"}, "class_type": "LoadImage"},
# ...其余节点同上 curl 示例...
}
nodes["170:151"]["inputs"]["prompt"] = "Remove the jacket, keep the T-shirt underneath"
nodes["170:169"]["inputs"]["seed"] = 1234567890 # 避免缓存
req = urllib.request.Request(
f"{GW}/api/v1/ai/image/generate",
data=json.dumps({"prompt": nodes, "extra_data": {}}).encode(),
headers=HEADERS, method="POST",
)
prompt_id = json.loads(urllib.request.urlopen(req, timeout=30).read())["prompt_id"]
# 3. 轮询 + 4. 下载(同文生图流程)
while True:
r = urllib.request.Request(f"{GW}/api/v1/ai/tasks/{prompt_id}", headers=HEADERS)
task = json.loads(urllib.request.urlopen(r, timeout=15).read())[prompt_id]
if task["status"].get("completed"):
break
time.sleep(5)
for out in task["outputs"].values():
for img in out.get("images", []):
url = f"{GW}/api/v1/ai/image/view/?filename={img['filename']}&type={img['type']}&subfolder={img.get('subfolder','')}"
req = urllib.request.Request(url, headers=HEADERS)
open(img["filename"], "wb").write(urllib.request.urlopen(req, timeout=120).read())常见问题
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 401 Unauthorized | API Key 错误/未传 | 检查 Authorization: Bearer sk-xxx |
| 编辑效果不如预期 | 用了 Turbo 模式 | 切 Native 40 步(170:168=false) |
任务 success 但 outputs 为空 | 命中 ComfyUI 缓存 | 换随机 seed 重提 |
详细文档见 ComfyUI Qwen 图片编辑 Skill。