HiAPI
博客

教程

vidu-q3-ad reference-to-video API:curl、Python 与一次可运行的请求

2026年11月3日
vidu-q3-ad reference-to-video API:curl、Python 与一次可运行的请求

你将构建什么

在 hiapi 的异步 /v1/tasks API 上发起一次 reference-to-video 调用,把 1–7 张产品静图变成一段带原生音频的短视频广告。vidu-q3-ad/reference-to-video 是 Vidu Q3 面向广告的档位:你上传产品参考图、写一段镜头描述,模型就返回一段 3–15 秒的 MP4,自带智能剪辑、运镜和生成的音效——没有单独的音轨需要你提供。

你只需提交一次 POST,然后轮询(或接收回调)直到任务完成,再下载 MP4。请先从 hiapi 控制台 获取密钥;下面每个请求都使用 Authorization: Bearer sk-...。

需要原样照抄的三项:

  • 提交端点:POST https://api.hiapi.ai/v1/tasks
  • 轮询端点:GET https://api.hiapi.ai/v1/tasks/{taskId}
  • 模型 ID:vidu-q3-ad/reference-to-video——斜杠和 -ad 后缀都不可省略;vidu-q3-mix 和 vidu-q4-preview 是不同的端点。

输入 schema(实时探测所得)

字段 是否必填 类型 说明
prompt 是 string 镜头描述;用序号指代产品,例如“参考图 1 中的手表”
reference_image_urls 是 array,1–7 产品静图的公开 URL(由服务端抓取)
duration 是 integer,3–15 秒数;必须是整数(4.5 会被拒绝)
size 否 enum(10 个值) 同时决定宽高比和 720/1080 档位;默认为 1280*720

校验器非常严格——上述列表之外的任何字段都会被直接拒绝。有两类拒绝值得特别指出,因为它们会让所有从其他 hiapi 视频模型迁移过来的人踩坑:

  • aspect_ratio 和 resolution 都会被拒绝。几乎所有其他 hiapi 视频端点都用这两个字段;q3-ad 不用。尺寸只能通过 size 控制。
  • reference_audio_urls 也会被拒绝。与 Vidu Q4 的 reference-to-video 档位(可接收语音片段)不同,q3-ad 没有音频输入——它的配乐是原生生成的。(我是如何确认这一点的,见下面的验证章节。)

如何选择 size

size 是来自固定集合的 width*height 字符串。可以把它读作五种宽高比 × 两个质量档位的网格:

宽高比 720 档 1080 档
16:9 横屏 1280*720 1920*1080
9:16 竖屏 720*1280 1080*1920
1:1 方形 1280*1280 1808*1808
4:3 1280*960 1920*1440
3:4 960*1280 1440*1920

按投放位置选行(Reels 和 TikTok 用竖屏 720*1280 / 1080*1920,YouTube 贴片广告用横屏行),按画质与预算的权衡选列。计费按输出秒数计算,档位决定每秒单价——详见 定价;最低计费为 3 秒片段。

最小请求(curl)

两步:提交,然后轮询。

# 1) 提交——返回一个 taskId
curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "vidu-q3-ad/reference-to-video",
    "input": {
      "prompt": "A product ad of the titanium smartwatch from reference image 1: it rotates slowly on a dark reflective pedestal while a hard strip of light sweeps across the brushed case from left to right, the screen stays dark, the camera holds a low hero angle. Commercial lighting, high contrast, macro detail.",
      "reference_image_urls": [
        "https://your-cdn.com/watch-front.png",
        "https://your-cdn.com/watch-side.png"
      ],
      "duration": 5,
      "size": "1280*720"
    }
  }'
# -> {"data":{"taskId":"..."}}

# 2) 轮询直到 data.status 为 "success" 或 "fail"
curl -s https://api.hiapi.ai/v1/tasks/THE_TASK_ID \
  -H "Authorization: Bearer sk-your-key"
# 成功 -> data.status == "success",且 data.output[0].url 就是 MP4

参考图 URL 必须可公开访问——任务会在服务端抓取它们,所以 localhost 或几秒后就过期的签名 URL 都不可用。

Python:提交、轮询、下载

import time
import requests  # 或使用 urllib/subprocess 保持零依赖

API = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": "Bearer sk-your-key", "Content-Type": "application/json"}

def submit():
    payload = {
        "model": "vidu-q3-ad/reference-to-video",
        "input": {
            "prompt": "Ad shot of the sneaker from reference image 1 spinning on a lit turntable, "
                      "slow push-in, soft rim light, product-hero framing.",
            "reference_image_urls": ["https://your-cdn.com/sneaker.png"],
            "duration": 5,
            "size": "1080*1920",   # 竖屏 1080p,用于 Reels / TikTok
        },
    }
    body = requests.post(API, headers=HEADERS, json=payload, timeout=60).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, timeout_s=600, interval=5):
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        data = requests.get(f"{API}/{task_id}", headers=HEADERS, timeout=30).json().get("data") or {}
        status = data.get("status")
        if status == "success":
            return data["output"][0]["url"]
        if status == "fail":
            raise RuntimeError(f"task failed: {data.get('error')}")
        time.sleep(interval)
    raise TimeoutError(task_id)

url = wait(submit())
mp4 = requests.get(url, timeout=120).content   # 立即下载——输出 URL 会过期
open("ad.mp4", "wb").write(mp4)

Q3-ad 渲染通常在一两分钟内完成;5 秒的轮询间隔完全够用。输出 URL 是临时的(带有 expireAt),所以任务成功后要立刻下载字节,而不是把它热链接进页面。

生产环境模式

用回调代替轮询。 在服务端场景中,挂一个顶层 callback,这样就不必保持轮询循环:

{
  "model": "vidu-q3-ad/reference-to-video",
  "input": { "prompt": "...", "reference_image_urls": ["..."], "duration": 5 },
  "callback": { "url": "https://your-app.com/hooks/hiapi", "when": "final" }
}

when 仅支持 "final"——任务进入终态时钩子触发一次,其请求体与 GET /v1/tasks/{taskId} 返回的负载相同。钩子可能被重试,所以要按 taskId 去重,并保留一个慢速轮询作为兜底,以防某次投递丢失。

基于响应体分支,而非 HTTP 状态码。 渲染失败仍会返回 HTTP 200;失败信息位于 data.status == "fail",详情在 data.error。只有请求级拒绝(字段错误、缺少密钥、未认证)才使用 4xx,且返回 {"code":400,"error_code":"INVALID_REQUEST","message":"...","data":null}。

幂等性。 每次提交都会创建一个新的计费任务,所以收到 taskId 的瞬间就要保存它,重试时重新轮询该 ID。绝不要因为单次轮询请求超时就重新提交。

我验证了什么

我用非法的值探测了线上端点,这些值会在校验阶段免费被拒绝——不会创建任务,也不计费(非法值会在任何渲染开始前失败,这比漏掉字段更安全)。真实响应就是 schema:

  • 近乎空的请求体 → reference_image_urls: missing required field ...; duration: missing required field ...。因此 prompt、reference_image_urls 和 duration 都是必填的。
  • duration: 99999 → maximum: got 99,999, want 15;duration: 1 → minimum: got 1, want 3;duration: 4.5 → got number, want integer。Duration 是 3–15 的整数。
  • reference_image_urls 传入 8 个条目 → maxItems: got 8, want 7。上限为 7。
  • size: "9000p" → value must be one of '1280*720', '1280*960', '1280*1280', '960*1280', '720*1280', '1920*1080', '1920*1440', '1808*1808', '1440*1920', '1080*1920'。
  • aspect_ratio 和 resolution → 两者都返回 additional properties ... not allowed。它们不是 q3-ad 的字段;请使用 size。
  • reference_audio_urls 以格式正确的数组传入 → additional properties 'reference_audio_urls' not allowed。(如果以非数组传入,会先触发单独的媒体检查——“must be an array”——这有误导性:该字段确实不在 schema 中。)此档位没有语音参考输入;音频是原生生成的。

这是一份集成参考,因此不包含画质声明——我没有为本文运行付费渲染。关于成功的 output[0].url 是什么样子,下面的模型页面托管了该端点自带的示例:一个真实带音轨的 MP4。

相关指南

常见问题

如何让片段变成竖屏或横屏? 通过 size,而不是 aspect_ratio。竖屏用 720*1280 或 1080*1920,横屏用 1280*720 或 1920*1080。

我可以提供配音或声音参考吗? 此档位不行——reference_audio_urls 会被拒绝。Q3-ad 会自行生成原生音频。如果你需要用参考片段驱动音频,请使用 Vidu Q4 的 reference-to-video 档位。

我可以发送多少张产品图片? 一到七张,放在 reference_image_urls 中,并在提示词里用序号引用(“参考图 2 中的瓶子”)。

我的任务返回了 200 但没有视频——为什么? 看 data.status。"fail" 会返回 HTTP 200,原因在 data.error 中;只有格式错误的请求才会得到 4xx。

费用是多少? 按输出秒数计费,size 档位(720 级 vs 1080 级)决定每秒单价。最低为 3 秒片段。当前费率见 定价。

立即开始构建持久 AI 产物

获取 API 密钥,通过一个基于任务(task)的 API 调用图像、视频和音频模型。

阅读 API 文档