用户指南
视频模型

万相 2.7 视频生成

通过统一视频任务接口调用万相 2.7 文生视频、图生视频、参考生视频和视频编辑模型。

  • 提交路由:POST /v1/videos
  • 任务查询:GET /v1/videos/{task_id}
  • 内容下载:GET /v1/videos/{task_id}/content

生成视频为异步任务。提交后先拿到 task_id,再轮询查询接口;任务成功后请尽快通过内容下载接口保存视频。万相 2.7 上游结果链接通常保留 24 小时,过期后需要重新发起任务。

支持的模型

模型场景主要输入
wan2.7-t2v文生视频prompt
wan2.7-i2v图生视频、首尾帧、视频续写promptmediaimage/images
wan2.7-r2v参考生视频、多主体参考、参考音色promptmedia
wan2.7-videoedit视频编辑promptmedia 中的 video

公共请求字段

字段类型说明
modelstring必填。wan2.7-r2v 用于参考生视频。
promptstring文本提示词。wan2.7-r2v 必填,最长 5000 字符。中文提示词中用“图1”“视频1”指代素材;英文提示词中用 “Image 1”“Video 1”。
mediaarray结构化素材列表。wan2.7-r2v 必填,至少包含一个 reference_imagereference_video
negative_promptstring反向提示词,最长 500 字符。
resolutionstring分辨率档位。720P1080P,默认 1080P;费用会随分辨率变化。
ratiostring宽高比。支持 16:99:161:14:33:4,默认 16:9wan2.7-r2v 传入 first_frame 时会忽略该字段,并按首帧近似比例输出。
durationnumber视频时长,单位秒,默认 5wan2.7-r2v 含参考视频时范围为 210;不含参考视频时范围为 215
secondsstringduration 等价的字符串形式;推荐新接入优先使用 duration
metadataobject扩展参数。wan2.7-r2v 常用:prompt_extendwatermarkseed

wan2.7-r2vmedia

media 每一项至少包含 typeurl。数组顺序决定提示词中的引用编号:第一个 reference_image 是“图1”,第一个 reference_video 是“视频1”。图片和视频分别计数。

type是否可用说明
reference_image必填组合之一参考图像,可作为人物、动物、物体或场景参考。支持公网 URL、OSS 临时 URL、Base64 Data URL。
reference_video必填组合之一参考视频,建议包含单一主体角色,可同时提供动作和音色参考。支持公网 URL、OSS 临时 URL。
first_frame可选首帧图像,最多 1 张。传入后 ratio 会被忽略,输出比例以首帧为准。

reference_imagereference_video 合计最多 5 个;如果参考素材是主体角色,官方建议每个素材只包含单一角色。reference_imagereference_video 可携带 reference_voice,用于指定该主体音色。

素材限制

素材格式限制
reference_image / first_frameJPEG、JPG、PNG、BMP、WEBP宽高范围 [240, 8000],宽高比 1:88:1,文件不超过 20MB;PNG 不支持透明通道。
reference_videoMP4、MOV时长 130 秒,宽高范围 [240, 4096],宽高比 1:88:1,文件不超过 100MB。
reference_voiceWAV、MP3时长 110 秒,文件不超过 15MB;只参考音色,不决定说话内容。

参考生视频

多主体参考示例,包含参考图、参考视频和参考音色:

curl --request POST \
  --url https://api.magickapi.com/v1/videos \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "wan2.7-r2v",
    "prompt": "视频1抱着图3,在图4的椅子上弹奏一支舒缓的乡村民谣,并说道:“今天的阳光真好。”图1手中拿着图2,路过视频1,把手中的图2放到视频1旁边的桌子上,并说道:“真好听,能不能再唱一遍”。",
    "media": [
      {
        "type": "reference_image",
        "url": "https://example.com/girl.jpg",
        "reference_voice": "https://example.com/girl-voice.mp3"
      },
      {
        "type": "reference_video",
        "url": "https://example.com/boy-role.mp4",
        "reference_voice": "https://example.com/boy-voice.mp3"
      },
      {
        "type": "reference_image",
        "url": "https://example.com/prop.png"
      },
      {
        "type": "reference_image",
        "url": "https://example.com/chair.png"
      }
    ],
    "resolution": "720P",
    "ratio": "16:9",
    "duration": 10,
    "metadata": {
      "prompt_extend": false,
      "watermark": false,
      "seed": 7
    }
  }'

如果只传一张多宫格故事板参考图,也使用 reference_image

{
  "model": "wan2.7-r2v",
  "prompt": "参考图片,3D 卡通冒险电影风,保持角色与森林场景一致。分镜:全景展示森林,小男孩拨开藤蔓,小机器人扫描前方,最后两人发现宝箱。",
  "media": [
    {
      "type": "reference_image",
      "url": "https://example.com/storyboard.png"
    }
  ],
  "resolution": "720P",
  "duration": 10,
  "metadata": {
    "prompt_extend": false,
    "watermark": false
  }
}

需要首帧约束时,可以额外传 first_frame

{
  "model": "wan2.7-r2v",
  "prompt": "视频1中的角色从图1的房间门口走入画面,与图2中的角色交谈。",
  "media": [
    {
      "type": "first_frame",
      "url": "https://example.com/first-frame.png"
    },
    {
      "type": "reference_video",
      "url": "https://example.com/role.mp4"
    },
    {
      "type": "reference_image",
      "url": "https://example.com/second-role.png"
    }
  ],
  "resolution": "720P",
  "duration": 8
}

其他 Wan 2.7 场景

文生视频:

curl --request POST \
  --url https://api.magickapi.com/v1/videos \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "wan2.7-t2v",
    "prompt": "一只纸飞机在阳光下缓慢飞过书桌,镜头稳定,画面简洁。",
    "resolution": "720P",
    "ratio": "16:9",
    "duration": 5
  }'

图生视频:

{
  "model": "wan2.7-i2v",
  "prompt": "让画面中的小猫抬头看向镜头,镜头轻微推进。",
  "image": "https://example.com/first-frame.png",
  "resolution": "720P",
  "duration": 5
}

视频编辑:

{
  "model": "wan2.7-videoedit",
  "prompt": "保留主体动作,把背景替换为夜晚的赛博朋克街道。",
  "media": [
    {
      "type": "video",
      "url": "https://example.com/source.mp4"
    },
    {
      "type": "reference_image",
      "url": "https://example.com/style-reference.png"
    }
  ],
  "resolution": "720P",
  "duration": 5,
  "metadata": {
    "audio_setting": "origin",
    "watermark": false
  }
}

响应、查询与下载

提交成功后返回任务对象:

{
  "id": "task_01KXYZ1234567890ABCDE",
  "task_id": "task_01KXYZ1234567890ABCDE",
  "object": "video",
  "model": "wan2.7-r2v",
  "status": "queued",
  "progress": 0,
  "created_at": 1712345678
}

查询任务状态:

curl https://api.magickapi.com/v1/videos/task_01KXYZ1234567890ABCDE \
  -H 'Authorization: Bearer YOUR_API_KEY'

状态可能为 queuedin_progresscompletedfailed。成功后响应的 metadata.url 是上游临时视频地址,建议直接使用内容下载接口保存文件:

curl -L https://api.magickapi.com/v1/videos/task_01KXYZ1234567890ABCDE/content \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  --output wan2-7-r2v-output.mp4

轮询示例

import { writeFile } from "node:fs/promises";

const baseUrl = "https://api.magickapi.com";
const apiKey = "YOUR_API_KEY";

const submitResp = await fetch(`${baseUrl}/v1/videos`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "wan2.7-r2v",
    prompt: "Image 1 sits by the cafe window playing guitar. Video 1 walks into the frame and talks with Image 1.",
    media: [
      {
        type: "reference_image",
        url: "https://example.com/character.png",
        reference_voice: "https://example.com/voice.mp3",
      },
      {
        type: "reference_video",
        url: "https://example.com/action.mp4",
      },
    ],
    resolution: "720P",
    ratio: "16:9",
    duration: 10,
    metadata: {
      prompt_extend: false,
      watermark: false,
    },
  }),
});

if (!submitResp.ok) {
  throw new Error(await submitResp.text());
}

const task = await submitResp.json();
const taskId = task.id || task.task_id;

while (true) {
  const queryResp = await fetch(`${baseUrl}/v1/videos/${taskId}`, {
    headers: { Authorization: `Bearer ${apiKey}` },
  });
  const status = await queryResp.json();

  if (status.status === "completed") {
    const downloadResp = await fetch(`${baseUrl}/v1/videos/${taskId}/content`, {
      headers: { Authorization: `Bearer ${apiKey}` },
    });
    const buffer = Buffer.from(await downloadResp.arrayBuffer());
    await writeFile("wan2-7-r2v-output.mp4", buffer);
    break;
  }

  if (status.status === "failed") {
    throw new Error(status.error?.message || "video generation failed");
  }

  await new Promise((resolve) => setTimeout(resolve, 15000));
}

最后更新于

目录