HiAPI
Blog

Tutorial

Cómo usar la API de referencia a video de vidu-q4-preview (curl + Python)

Oct 19, 2026
Cómo usar la API de referencia a video de vidu-q4-preview (curl + Python)

Lo que vas a construir

Realiza una llamada de referencia a video en la API asíncrona /v1/tasks de hiapi, fusionando varias imágenes de referencia fijas —y opcionalmente clips de audio— en una toma de 3 a 16 segundos y hasta 4K. Solo envías un POST, luego consultas repetidamente (o recibes un callback) hasta que la tarea termina, y descargas el MP4.

Primero obtén tu clave desde la consola de hiapi; cada petición a continuación usa Authorization: Bearer sk-<your-key>.

Referencia a video vs. imagen a video. Este endpoint fusiona de 1 a 15 imágenes fijas —pasa una imagen de una persona, una de un escenario y una de un objeto, y las combinará en una sola toma. Si solo tienes un único primer fotograma que necesita cobrar movimiento, usa mejor vidu-q4-preview/image-to-video; este recibe un único image_url y rechaza reference_image_urls.

Petición mínima funcional (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"
    }
  }'

Ese POST devuelve un id de tarea, no el video:

{ "code": 200, "data": { "taskId": "task_abc123" } }

Consulta repetidamente GET /v1/tasks/<taskId> hasta que data.status sea success, y luego lee el MP4 desde data.output[0].url:

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 }
    ]
  }
}

La URL de salida es temporal —incluye expireAt (expira en unos días)—, así que descarga los bytes de inmediato; no hagas hotlinking.

Python: enviar → consultar → descargar

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")

Hay un punto que debes interiorizar: un render fallido sigue devolviendo HTTP 200, con el motivo en data.status: "fail" y data.error.code / data.error.message. Un fallo de generación no es un error HTTP, así que ramifica según el cuerpo de la respuesta, no según el código de estado.

Añadir una referencia de voz

El campo de voz es reference_audio_urls —un arreglo de hasta 3 clips de audio. El audio define el timbre; tu prompt sigue llevando el texto y dirigiendo la sincronización labial.

{
  "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
  }
}

Trampa de nombre de campo: el intuitivo voice_reference_urls es rechazado (el validador solo admite reference_audio_urls). Consulta la tabla de pruebas más abajo.

Producción: callbacks e idempotencia

Para flujos de trabajo en servidor, normalmente no querrás mantener un bucle de consulta activo. Adjunta un callback de nivel superior (al mismo nivel que input, no dentro de él) y hiapi enviará por POST la tarea completada a tu URL:

{
  "model": "vidu-q4-preview/reference-to-video",
  "input": { "prompt": "...", "reference_image_urls": ["..."] },
  "callback": { "url": "https://your-app.com/hooks/vidu", "when": "final" }
}
  • when solo admite "final" —recibirás una única notificación en el estado terminal (éxito o fallo), nunca notificaciones de progreso intermedio.
  • El cuerpo del callback es el mismo payload que devuelve GET /v1/tasks/<id>.
  • La entrega se reintenta varias veces y puede duplicarse, así que deduplica por taskId y haz que tu manejador sea idempotente.
  • Mantén la consulta repetida como respaldo para cubrir las ventanas en que tu endpoint no sea accesible momentáneamente.

Guarda el taskId en el momento en que lo obtengas. Si tu consultador sufre un error de red temporal, vuelve a consultar el id guardado —nunca reenvíes, o pagarás por un segundo render.

Lo que verifiqué (contrato de esquema)

Probé el endpoint en vivo con valores deliberadamente inválidos (gratis —las peticiones rechazadas no se cobran, y los valores inválidos nunca crean tareas). El validador es estricto y devuelve un formato plano { "code": 400, "error_code": "INVALID_REQUEST", "message": ... }:

Lo que envías Lo que se devuelve
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
Cuatro reference_audio_urls reference_audio_urls: maxItems: got 4, want 3
Omitir reference_image_urls missing required field "reference_image_urls"

Por tanto, la estructura de entrada confirmada es:

Campo Obligatorio Valores
prompt Sí Texto
reference_image_urls Sí 1–15 URL de imágenes
reference_audio_urls No Hasta 3 URL de audio (campo de voz)
resolution No 540p / 720p / 1080p / 2k / 4k
duration No Entero 3–16 (segundos)
aspect_ratio No 16:9 / 9:16 / 1:1 / 4:3 / 3:4

duration es un entero (5), no una cadena —a diferencia de otros modelos de video en hiapi que esperan "6". Enviar claves adicionales es un error grave (additional properties ... not allowed), así que no copies campos del esquema de imagen a video.

Advertencias del lado de la salida antes de integrar la descarga

  • Todo clip incluye una pista de audio AAC, incluso si no enviaste reference_audio_urls. El vocabulario sonoro del prompt dirige la pista de ambiente, así que no asumas que "sin referencia de voz = archivo silencioso".
  • La salida 4K de Vidu Q4 Preview se entrega en HEVC/H.265. Se reproduce en la mayoría de reproductores nativos, pero muchos navegadores no pueden reproducir MP4 H.265 en línea dentro de una etiqueta <video> —si vas a incrustar en una página web, recodifica a H.264. Los niveles inferiores devuelven H.264 estándar.

Modelo de vista previa — trata los enums como una instantánea

vidu-q4-preview/reference-to-video es un modelo de vista previa: se puede llamar hoy, pero no aparece en /v1/models, y el esquema de vista previa puede cambiar. Antes de procesar en lote, vuelve a ejecutar las pruebas con valores inválidos (como en la tabla anterior) para confirmar que los enums siguen siendo válidos. La especificación autoritativa son las reglas que aplica realmente el validador, junto con la página del modelo.

Relacionado

Preguntas frecuentes

¿Referencia a video es lo mismo que imagen a video? No. Referencia a video fusiona de 1 a 15 imágenes fijas (opcionalmente con hasta 3 clips de audio) en una toma compuesta; imagen a video anima un único primer fotograma. Son endpoints independientes con entradas distintas —referencia a video incluso rechaza el campo image_url de imagen a video, y viceversa.

¿Cómo añado voz? Adjunta reference_audio_urls (hasta 3 clips) e indícalo en el prompt ("…con la voz de la referencia de audio 1"). El nombre del campo debe ser exactamente reference_audio_urls; voice_reference_urls y otros nombres se rechazan.

¿Cuál es el clip más largo que puedo solicitar? 16 segundos. duration es un entero de 3 a 16.

¿Es obligatorio consultar repetidamente? No —adjunta callback: { "url": ..., "when": "final" } y recibirás una notificación en el estado terminal. Deduplica por taskId y mantén la consulta repetida como respaldo.

¿Cuánto cuesta un clip en 4K? Se cobra por segundo, con tarifas que aumentan según la resolución, siendo 4K el nivel más alto —consulta Precios de hiapi. El flujo de trabajo práctico es iterar primero en 720p y volver a renderizar en 4k solo las versiones finales que conserves.

Artículos relacionados

Ver todos los artículos →

Empieza a crear con artefactos de IA persistentes

Consigue tu API key y llama a modelos de imagen, vídeo y audio a través de una única API basada en tasks.

Leer la documentación de la API