Appearance
FLUX.2 图生图编辑
网关地址:
https://ai.ospreyai.cn(公网) 模型:flux-2-klein-9b-kv-fp8无需后端 Bearer Token
概述
使用 FLUX.2-klein-9b-kv-fp8 模型,通过 Reference Conditioning 技术实现图片编辑,支持换装、换背景、局部修改。仅需 4 步生成,速度极快。任务异步执行:提交工作流 → 轮询状态 → 下载结果。任务状态查询、结果下载等通用接口见 任务管理。
前置条件: 需先通过 /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. 上传图片
图1=主体,图2=服装参考(自我编辑时图1图2用同一张)。
bash
# 上传图1(主体)
curl -H "Authorization: Bearer $API_KEY" -X POST "$GW/api/v1/upload" \
-F "image=@/path/to/man.png" \
-F "type=input"
# 返回: {"name": "man.png", "subfolder": "", "type": "input"}
# 上传图2(服装参考)
curl -H "Authorization: Bearer $API_KEY" -X POST "$GW/api/v1/upload" \
-F "image=@/path/to/outfit.png" \
-F "type=input"
# 返回: {"name": "outfit.png", "subfolder": "", "type": "input"}2. 提交编辑工作流
bash
curl -H "Authorization: Bearer $API_KEY" -X POST "$GW/api/v1/ai/image/generate" \
-H "Content-Type: application/json" \
-d '{
"prompt": {
"122": {"class_type": "KSamplerSelect", "inputs": {"sampler_name": "euler"}},
"126": {"class_type": "UNETLoader", "inputs": {"unet_name": "flux-2-klein-9b-kv-fp8.safetensors", "weight_dtype": "default"}},
"133": {"class_type": "CLIPLoader", "inputs": {"clip_name": "qwen_3_8b_fp8mixed.safetensors", "type": "flux2", "device": "default"}},
"138": {"class_type": "CFGGuider", "inputs": {"model": ["139", 0], "positive": ["132_121", 0], "negative": ["132_119", 0], "cfg": 1.0}},
"127": {"class_type": "VAELoader", "inputs": {"vae_name": "flux2-vae.safetensors"}},
"135": {"class_type": "CLIPTextEncode", "inputs": {"clip": ["133", 0], "text": "Have the man put on the clothes from Figure 2, keep same posture"}},
"139": {"class_type": "FluxKVCache", "inputs": {"model": ["126", 0]}},
"123": {"class_type": "SamplerCustomAdvanced", "inputs": {"noise": ["125", 0], "guider": ["138", 0], "sampler": ["122", 0], "sigmas": ["137", 0], "latent_image": ["129", 0]}},
"125": {"class_type": "RandomNoise", "inputs": {"noise_seed": 720512742793301}},
"124": {"class_type": "VAEDecode", "inputs": {"samples": ["123", 0], "vae": ["127", 0]}},
"94": {"class_type": "SaveImage", "inputs": {"images": ["124", 0], "filename_prefix": "Result"}},
"685": {"class_type": "ConditioningZeroOut", "inputs": {"conditioning": ["135", 0]}},
"137": {"class_type": "Flux2Scheduler", "inputs": {"width": ["128", 0], "height": ["128", 1], "steps": 4}},
"129": {"class_type": "EmptyFlux2LatentImage", "inputs": {"width": ["128", 0], "height": ["128", 1], "batch_size": 1}},
"128": {"class_type": "GetImageSize", "inputs": {"image": ["130", 0]}},
"130": {"class_type": "ImageScaleToTotalPixels", "inputs": {"image": ["76", 0], "upscale_method": "lanczos", "megapixels": 1.0, "resolution_steps": 1}},
"131": {"class_type": "ImageScaleToTotalPixels", "inputs": {"image": ["81", 0], "upscale_method": "lanczos", "megapixels": 1.0, "resolution_steps": 1}},
"76": {"class_type": "LoadImage", "inputs": {"image": "man.png"}},
"81": {"class_type": "LoadImage", "inputs": {"image": "outfit.png"}},
"134_116": {"class_type": "ReferenceLatent", "inputs": {"conditioning": ["685", 0], "latent": ["134_117", 0]}},
"134_117": {"class_type": "VAEEncode", "inputs": {"pixels": ["130", 0], "vae": ["127", 0]}},
"134_118": {"class_type": "ReferenceLatent", "inputs": {"conditioning": ["135", 0], "latent": ["134_117", 0]}},
"132_119": {"class_type": "ReferenceLatent", "inputs": {"conditioning": ["134_116", 0], "latent": ["132_120", 0]}},
"132_120": {"class_type": "VAEEncode", "inputs": {"pixels": ["131", 0], "vae": ["127", 0]}},
"132_121": {"class_type": "ReferenceLatent", "inputs": {"conditioning": ["134_118", 0], "latent": ["132_120", 0]}}
}
}'响应:
json
{"prompt_id": "a1b2c3d4-...", "number": 100, "node_errors": {}}关键节点参数
| 节点 | 字段 | 说明 | 推荐值 |
|---|---|---|---|
| 76 | image | 主体图片文件名(需先上传) | 上传返回的 name |
| 81 | image | 服装/参考图片文件名 | 可与 76 相同(自我编辑) |
| 135 | text | 编辑提示词(英文,Figure 1/2 指代图片) | — |
| 125 | noise_seed | 随机种子 | 任意整数 |
| 137 | steps | 采样步数 | 4 |
| 94 | filename_prefix | 输出文件名前缀 | — |
提示词技巧
- 换装:
"Have the man in Figure 1 put on the clothes from Figure 2, keep same posture" - 改背景:
"Change background to African savannah, keep person unchanged" - 局部修改:将图1图2设为同一张,写
"Remove the outer jacket, keep inner clothing only"
缓存坑:若提交的工作流与历史完全相同(尤其 seed 相同),ComfyUI 会命中
execution_cached直接返回,outputs可能为空。提交时换个随机noise_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. 上传图片(用 poster.encode/multipart)
# 略 —— 参考「任务管理」页的上传示例
# 2. 提交工作流
nodes = {
"122": {"class_type": "KSamplerSelect", "inputs": {"sampler_name": "euler"}},
"126": {"class_type": "UNETLoader", "inputs": {"unet_name": "flux-2-klein-9b-kv-fp8.safetensors", "weight_dtype": "default"}},
# ...其余节点同上 curl 示例...
}
nodes["135"]["inputs"]["text"] = "Have the man put on the clothes from Figure 2, keep same posture"
nodes["76"]["inputs"]["image"] = "man.png"
nodes["81"]["inputs"]["image"] = "outfit.png"
nodes["125"]["inputs"]["noise_seed"] = 123456 # 避免缓存
req = urllib.request.Request(
f"{GW}/api/v1/ai/image/generate",
data=json.dumps({"prompt": nodes}).encode(),
headers=HEADERS, method="POST",
)
prompt_id = json.loads(urllib.request.urlopen(req, timeout=30).read())["prompt_id"]
# 3. 轮询
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)
# 4. 下载
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 |
| 404 / 节点报错 | 输入图片未上传 | 先 POST /api/v1/upload,文件名填入 LoadImage 节点 |
任务 success 但 outputs 为空 | 命中 ComfyUI 缓存 | 换随机 noise_seed 重提 |
| 编辑后人物姿态变化 | 提示词未强调保持姿态 | 加 keep same posture / keep person unchanged |
详细文档见 ComfyUI FLUX.2 编辑 Skill。