教程
如何使用 vidu-q4-preview 参考生视频 API(curl + Python)
你将构建的内容
在 hiapi 的异步 /v1/tasks API 上发起一次参考生视频调用,将多张参考静帧——以及可选的音频片段——融合成一段 3–16 秒、最高 4K 的画面。你只需提交一个 POST,然后轮询(或接收回调)直到任务完成,再下载 MP4。
先从 hiapi 控制台获取密钥;下方每个请求都使用 Authorization: Bearer sk-<your-key>。
参考生视频 vs 图生视频。 此端点会融合 1–15 张静帧——传入一张人物静帧、一张场景静帧、一张道具静帧,它就能将它们合成为一个镜头。如果你只有单张首帧需要动起来,请改用 vidu-q4-preview/image-to-video;它接收单个
image_url并拒绝reference_image_urls。
最小可运行请求(curl)
curl -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-<your-key>" \
-H "Content-Type: application/json" \
-d '{
"model": "vidu-q4-preview/reference-to-video",
"input": {
"prompt": "参考图 1 中的人物走过参考图 2 中的咖啡馆,温暖的晨光,缓慢推镜",
"reference_image_urls": [
"https://your-cdn.com/person.jpg",
"https://your-cdn.com/cafe.jpg"
],
"resolution": "1080p",
"duration": 5,
"aspect_ratio": "16:9"
}
}'
该 POST 返回的是任务 id,而不是视频:
{ "code": 200, "data": { "taskId": "task_abc123" } }
轮询 GET /v1/tasks/<taskId> 直到 data.status 为 success,然后从 data.output[0].url 读取 MP4:
curl https://api.hiapi.ai/v1/tasks/task_abc123 \
-H "Authorization: Bearer sk-<your-key>"
{
"code": 200,
"data": {
"status": "success",
"output": [
{ "url": "https://temp.hiapi.ai/....mp4", "expireAt": 1760000000 }
]
}
}
输出 URL 是临时的——它带有 expireAt(几天后过期)——所以请立即下载字节内容,不要热链。
Python:提交 → 轮询 → 下载
import time
import requests
BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {
"Authorization": "Bearer sk-<your-key>",
"Content-Type": "application/json",
}
def submit() -> str:
payload = {
"model": "vidu-q4-preview/reference-to-video",
"input": {
"prompt": (
"参考图 1 中的人物走过参考图 2 中的咖啡馆,"
"温暖的晨光,缓慢推镜"
),
"reference_image_urls": [
"https://your-cdn.com/person.jpg",
"https://your-cdn.com/cafe.jpg",
],
"resolution": "1080p",
"duration": 5,
"aspect_ratio": "16:9",
},
}
r = requests.post(BASE, json=payload, headers=HEADERS, timeout=60)
r.raise_for_status()
body = r.json()
task_id = (body.get("data") or {}).get("taskId")
if not task_id:
raise RuntimeError(f"submit rejected: {body}") # 400 错误会落到这里
return task_id
def wait(task_id: str, timeout_s: int = 600, interval: int = 5) -> str:
deadline = time.time() + timeout_s
while time.time() < deadline:
r = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=40)
task = r.json().get("data") or {}
status = task.get("status")
if status == "success":
return task["output"][0]["url"]
if status == "fail":
raise RuntimeError(f"task failed: {task.get('error')}")
time.sleep(interval)
raise TimeoutError(task_id)
def download(url: str, path: str) -> None:
with requests.get(url, stream=True, timeout=120) as r:
r.raise_for_status()
with open(path, "wb") as f:
for chunk in r.iter_content(1 << 16):
f.write(chunk)
task_id = submit()
url = wait(task_id)
download(url, "out.mp4")
有一点需要内化:失败的渲染仍然以 HTTP 200 返回,原因在 data.status: "fail" 和 data.error.code / data.error.message 中。生成失败不是 HTTP 错误,所以要基于响应体分支,而不是状态码。
添加语音参考
语音字段是 reference_audio_urls——最多 3 个音频片段组成的数组。音频设定音色;你的 prompt 仍然承载文字并驱动口型同步。
{
"model": "vidu-q4-preview/reference-to-video",
"input": {
"prompt": "参考图 1 中的主播用参考音频 1 的声音说:'欢迎回到频道。'",
"reference_image_urls": ["https://your-cdn.com/presenter.jpg"],
"reference_audio_urls": ["https://your-cdn.com/voice.mp3"],
"resolution": "1080p",
"duration": 8
}
}
字段名陷阱:直观的 voice_reference_urls 会被拒绝(校验器只允许 reference_audio_urls)。参见下方探针表。
生产环境:回调与幂等性
对于服务器工作流,你通常不希望一直保持轮询循环。附加一个顶层 callback(与 input 同级,而非在它内部),hiapi 就会将完成的任务 POST 到你的 URL:
{
"model": "vidu-q4-preview/reference-to-video",
"input": { "prompt": "...", "reference_image_urls": ["..."] },
"callback": { "url": "https://your-app.com/hooks/vidu", "when": "final" }
}
when仅支持"final"——你只会在终态(成功或失败)收到一次通知,绝不会收到中间进度通知。- 回调体与
GET /v1/tasks/<id>返回的负载相同。 - 投递会重试几次且可能重复,所以请按
taskId去重,并让处理器具备幂等性。 - 保留轮询作为兜底,以覆盖你的端点短暂不可达的窗口。
拿到 taskId 的那一刻就保存它。如果你的轮询器遇到临时网络错误,请重新轮询已保存的 id——绝不要重新提交,否则你会为第二次渲染付费。
我验证了什么(schema 契约)
我用故意无效的值探测了实时端点(免费——被拒绝的请求不计费,且无效值永远不会创建任务)。校验器很严格,返回扁平的 { "code": 400, "error_code": "INVALID_REQUEST", "message": ... }:
| 你发送的内容 | 返回的内容 |
|---|---|
resolution: "9999p" |
resolution: value must be one of '540p', '720p', '1080p', '2k', '4k' |
duration: 999 |
duration: maximum: got 999, want 16 |
aspect_ratio: "banana" |
aspect_ratio: value must be one of '16:9', '9:16', '1:1', '4:3', '3:4' |
voice_reference_urls: [...] |
additional properties 'voice_reference_urls' not allowed |
四个 reference_audio_urls |
reference_audio_urls: maxItems: got 4, want 3 |
省略 reference_image_urls |
missing required field "reference_image_urls" |
因此确认的输入结构为:
| 字段 | 必填 | 取值 |
|---|---|---|
prompt |
是 | 文本 |
reference_image_urls |
是 | 1–15 个图片 URL |
reference_audio_urls |
否 | 最多 3 个音频 URL(语音字段) |
resolution |
否 | 540p / 720p / 1080p / 2k / 4k |
duration |
否 | 整数 3–16(秒) |
aspect_ratio |
否 | 16:9 / 9:16 / 1:1 / 4:3 / 3:4 |
duration 是整数(5),不是字符串——与 hiapi 上其他一些期望 "6" 的视频模型不同。传入额外键是硬错误(additional properties ... not allowed),所以不要从图生视频 schema 中复制字段过来。
接入下载前的输出侧注意事项
- 即使你没有发送
reference_audio_urls,每个片段也带有 AAC 音轨。 prompt 中的声音词汇会驱动环境音轨,所以不要假设“无语音参考 = 静音文件”。 - Vidu Q4 Preview 的 4K 输出以 HEVC/H.265 交付。 它在大多数原生播放器中可播放,但许多浏览器无法在
<video>标签内内联播放 H.265 MP4——如果要嵌入网页,请重新编码为 H.264。较低档位返回标准 H.264。
预览模型——将枚举视为快照
vidu-q4-preview/reference-to-video 是一个预览模型:它今天可以调用,但未列在 /v1/models 中,且预览 schema 可能变动。在大批量处理前,重新运行一次无效值探针(如上方表格)以确认枚举仍然有效。权威规范是校验器实际执行的规则加上模型页面。
相关
- vidu-q4-preview/reference-to-video 模型页面——实时规范和每请求成本。
- Vidu Q4 Preview 参考生视频 prompt 配方——五个可直接复制的 prompt 及它们实际生成的片段,为你提供在
prompt中放什么的思路(本指南覆盖调用;那页覆盖prompt)。 - vidu-q4-preview/image-to-video——单帧动画端点;当你只有一张静帧而非一组需要融合的图时使用它。
- hiapi 定价——参考生视频按秒计费,并随分辨率提升而增加。
常见问题
参考生视频和图生视频一样吗?
不一样。参考生视频将 1–15 张静帧(可选加最多 3 个音频片段)融合成一个合成镜头;图生视频则让单个首帧动起来。它们是独立端点,输入不同——参考生视频甚至拒绝图生视频的 image_url 字段,反之亦然。
如何添加语音?
附加 reference_audio_urls(最多 3 个片段),并在 prompt 中指明(“……用参考音频 1 的声音”)。字段名必须正好是 reference_audio_urls;voice_reference_urls 及其他名称会被拒绝。
我可以请求的最长片段是多少?
16 秒。duration 是 3 到 16 的整数。
必须轮询吗?
不必——附加 callback: { "url": ..., "when": "final" },即可在终态收到一次通知。按 taskId 去重,并保留轮询作为兜底。
一个 4K 片段要多少钱?
按秒计费,费率随分辨率上升,4K 是最高档——参见 hiapi 定价。实用的工作流是先在 720p 迭代,仅对最终保留的版本以 4k 重新渲染。