Wan 2.6 Image
Wan 2.6 Image 图像编辑 API
wan2.6-image 通过参考图和文本指令完成图像编辑、多图融合、风格迁移、主体保持和图片文字生成。LoopToken 当前稳定提供同步图像编辑;图文混排与流式能力不在稳定合同内。
接口
路径为 POST /v1/images/generations,完整地址如下:
POST https://api.vibelab.me/v1/images/generations
Authorization: Bearer <your-api-key>
Content-Type: application/json请求采用 input.messages + parameters 结构。当前只传一条 role: "user" 消息;其 content 必须且只能有一个 text 对象,并在其后放 1~4 个 image 对象。采用文字在前、图片在后的固定写法,便于审查图片编号与 content 数组中的顺序。
Wan 2.7
wan2.7-image 和 wan2.7-image-pro 使用扁平扩展格式,支持文生图、编辑、参考图与序列生成,不使用下文 Wan 2.6 的 DashScope 消息结构。常用字段包括 prompt、image_urls、n、size / resolution、negative_prompt、watermark、seed、thinking_mode 和 enable_sequential。标准版最高 2K;Pro 版文生图最高 4K,编辑与序列生成最高 2K。
{
"model": "wan2.7-image-pro",
"prompt": "四季中的同一只橘猫,连续分镜",
"size": "2K",
"enable_sequential": true,
"n": 4
}Wan 2.7 按成功图片数计费,分辨率和宽高比不改变单张价格;响应统一为 OpenAI Images 格式。
能力边界
| 能力 | LoopToken 稳定支持 | 约束 |
|---|---|---|
| 图像编辑 | 是 | 1~4 张参考图,enable_interleave=false |
| 多图融合 | 是 | “图1”“图2”按图片对象出现顺序编号 |
| 多张输出 | 是 | parameters.n 为 1~4;建议显式传 1 |
| 图文混排与流式边界 | 否 | 模型服务要求流式专用请求头;当前网关不转发该头且缓冲响应 |
| 纯文生图 | 否 | 编辑模式至少需要一张图;请改用文生图模型 |
| Base64 输出 | 否 | 响应图片是 PNG 临时 URL,不返回 b64_json |
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
model | string | 是 | 固定为 wan2.6-image |
input.messages | array | 是 | 仅一条用户消息,不支持多轮 |
input.messages[0].content[].text | string | 是 | 一个且仅一个;中英文,最多 2000 字符,超出部分可能被截断 |
input.messages[0].content[].image | string | 是 | 1~4 个公网 URL 或 Base64 Data URL |
parameters.enable_interleave | boolean | 建议 | 固定传 false,选择同步图像编辑 |
parameters.n | integer | 否 | 1~4;模型服务文档默认 4,但 LoopToken 在省略或传非正数时按 1 预扣及兜底结算。请显式传值,低成本调用传 1 |
parameters.size | string | 否 | 1K(默认)、2K 或 宽*高 |
parameters.negative_prompt | string | 否 | 反向提示词,最多 500 字符 |
parameters.prompt_extend | boolean | 否 | 默认 true;仅编辑模式生效 |
parameters.watermark | boolean | 否 | 默认 false;true 添加“AI生成”水印 |
parameters.seed | integer | 否 | 0~2147483647;相同值不保证完全一致 |
输入图片限制
- 格式:JPEG、JPG、PNG(不支持透明通道)、BMP、WEBP。
- 单图宽、高均为 240~8000 像素;单图不超过 10 MB。
- 公网 URL 必须允许模型服务直接下载,支持 HTTP/HTTPS;不要使用需登录、短时签名已过期或内网地址。
- Base64 使用完整 Data URL:
data:image/png;base64,<base64-data>。后端最多读取请求体前 20 MiB;这不是带专用错误码的可靠限额合同,超出后通常会因 JSON 被截断而返回invalid_request。客户端应让编码后的整个 JSON 明显低于此边界。 - 多图时,提示词中的“图1”“图2”严格对应
content中图片对象的先后顺序。输出比例默认跟随最后一张输入图。
Wan 2.6 尺寸表
parameters.size | 像素规模 | 宽高比 |
|---|---|---|
1K | 接近 1280*1280 | 跟随最后一张输入图 |
2K | 接近 2048*2048 | 跟随最后一张输入图 |
| 像素值 | 768*768 至 2048*2048 总像素 | 1:4 至 4:1 |
像素值格式使用星号,例如 1280*720。实际宽高会调整为接近指定值的 16 的倍数。常用比例可选 1280*1280(1:1)、800*1200(2:3)、1200*800(3:2)、960*1280(3:4)、1280*960(4:3)、720*1280(9:16)、1280*720(16:9)和 1344*576(21:9)。
请求示例
最小 URL 引用
{
"model": "wan2.6-image",
"input": {
"messages": [{
"role": "user",
"content": [
{"text": "把背景改成夜晚的上海街景,保持人物不变"},
{"image": "https://example.com/source.jpg"}
]
}]
},
"parameters": {"enable_interleave": false, "n": 1}
}Base64 Data URL
{
"model": "wan2.6-image",
"input": {
"messages": [{
"role": "user",
"content": [
{"text": "移除桌面杂物,保留产品和阴影"},
{"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..."}
]
}]
},
"parameters": {"enable_interleave": false, "n": 1, "prompt_extend": false}
}多参考图、尺寸与数量
{
"model": "wan2.6-image",
"input": {
"messages": [{
"role": "user",
"content": [
{"text": "让图1的产品使用图2的配色,生成两张中文电商海报,标题为“夏日新色”"},
{"image": "https://example.com/product.png"},
{"image": "https://example.com/palette.jpg"}
]
}]
},
"parameters": {
"enable_interleave": false,
"n": 2,
"size": "2K",
"negative_prompt": "文字模糊,产品变形",
"prompt_extend": true,
"watermark": false,
"seed": 42
}
}完整 curl:上传本地图片并下载全部结果
IMAGE_DATA=$(base64 < source.png | tr -d '\n')
jq -n --arg image "data:image/png;base64,$IMAGE_DATA" '{
model: "wan2.6-image",
input: {messages: [{role: "user", content: [
{text: "把背景改成纯白摄影棚,保留主体细节"},
{image: $image}
]}]},
parameters: {enable_interleave: false, n: 1, size: "1K"}
}' > request.json
curl -sS https://api.vibelab.me/v1/images/generations \
-H "Authorization: Bearer $LOOPTOKEN_API_KEY" \
-H 'Content-Type: application/json' \
--data-binary @request.json > response.json
jq -e '.output.choices | type == "array"' response.json > /dev/null
jq -r '.output.choices[] | .message.content[] | select(.image) | .image' response.json |
while IFS= read -r url; do
index=$(( ${index:-0} + 1 ))
curl -L --fail --output "wan-$index.png" "$url"
done响应
{
"output": {
"choices": [{
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": [{
"image": "https://example.com/temporary-result.png",
"type": "image"
}]
}
}],
"finished": true
},
"usage": {"image_count": 1, "size": "1280*1280"}
}逐个遍历 output.choices[].message.content[],仅处理含 image 的项;结果按 choices 与 content 的顺序返回。图片是临时 PNG URL,请立即下载并持久化。不要依赖 usage.image_count 替代数组遍历。
Python:下载全部图片
import os
from pathlib import Path
from urllib.request import Request, urlopen, urlretrieve
import json
payload = {"model": "wan2.6-image", "input": {"messages": [{"role": "user", "content": [
{"text": "将图片改成水彩插画"}, {"image": "https://example.com/source.jpg"}
]}]}, "parameters": {"enable_interleave": False, "n": 1}}
request = Request("https://api.vibelab.me/v1/images/generations",
data=json.dumps(payload).encode(), headers={"Authorization": f"Bearer {os.environ['LOOPTOKEN_API_KEY']}", "Content-Type": "application/json"})
with urlopen(request) as response:
data = json.load(response)
index = 0
for choice in data["output"]["choices"]:
for item in choice["message"]["content"]:
if item.get("image"):
index += 1
urlretrieve(item["image"], Path(f"wan-{index}.png"))Node.js:下载全部图片
import { writeFile } from 'node:fs/promises';
const response = await fetch('https://api.vibelab.me/v1/images/generations', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.LOOPTOKEN_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ model: 'wan2.6-image', input: { messages: [{ role: 'user', content: [
{ text: '将图片改成水彩插画' }, { image: 'https://example.com/source.jpg' }
] }] }, parameters: { enable_interleave: false, n: 1 } }),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const data = await response.json();
let index = 0;
for (const choice of data.output.choices) {
for (const item of choice.message.content) {
if (!item.image) continue;
const image = await fetch(item.image);
if (!image.ok) throw new Error(`download failed: ${image.status}`);
await writeFile(`wan-${++index}.png`, Buffer.from(await image.arrayBuffer()));
}
}错误与计费
LoopToken 在鉴权、余额、模型、JSON 等本地检查失败时返回统一错误对象:
{"error":{"message":"invalid image generation request","type":"invalid_request","code":"invalid_request","request_id":"req_example"}}固定的本地状态包括:400 invalid_request(请求体无法读取、JSON 截断或格式错误、model 缺失)、401 API Key 缺失或无效、402 insufficient_credits、403 model_not_allowed、404 model_not_found,以及计费或请求构建异常时的 500 internal_error。参考图格式、数量、顺序、尺寸、输出数量和安全策略主要由模型服务校验;素材无效、参数不支持、内容拒绝或生成失败不会保留模型服务错误码。
模型服务终止性非 2xx 或网络失败通常返回 HTTP 502、code: "upstream_error"。当前没有可处理请求的服务资源时返回 HTTP 503、code: "no_available_channel";一次可重试失败后若也无法继续处理,同一次请求也可能最终返回 503。两者都会退款,客户端应把 502 和 503 都视为暂时不可完成,可采用带抖动的有限退避重试;不要依赖模型服务原始错误体。成功的 2xx 响应则原样返回,LoopToken 请求 ID 只位于 X-Request-Id 响应头。
本模型按图片计费,最终价格以模型列表为准。网关预扣时使用显式提交的正整数 parameters.n;省略或传非正数时,本地计费值回退为 1,但转发给模型服务的请求体不会因此补写 n: 1。正常 JSON 响应按 output.choices[].message.content[].image 中每张成功识别的输出图片结算;若 2xx 响应无法识别图片而得到 Count=0,网关使用上述本地计费值兜底结算。usage 只表示模型服务用量,不是 credit 金额。供应商文档所述默认输出 4 张与此本地回退值是两件事,因此务必显式设置 n,并完整保存响应用于排查。