HiAPI
Blog

Tutoriale

Come usare l'API reference-to-video di vidu-q4-preview (curl + Python)

Oct 19, 2026
Come usare l'API reference-to-video di vidu-q4-preview (curl + Python)

Cosa costruirai

Avvia una chiamata reference-to-video sull'API asincrona /v1/tasks di hiapi, fondendo più fotogrammi di riferimento statici — e facoltativamente brevi clip audio — in un'unica scena da 3 a 16 secondi fino a 4K. Invierai una sola POST, poi eseguirai il polling (o riceverai un callback) finché l'attività non è completata, quindi scaricherai l'MP4.

Inizia ottenendo una chiave dalla console hiapi; ogni richiesta qui sotto usa Authorization: Bearer sk-<your-key>.

Reference-to-video vs image-to-video. Questo endpoint fonde da 1 a 15 fotogrammi statici — passa una foto di una persona, una di un ambiente e una di un oggetto, e le unirà in un'unica inquadratura. Se hai solo un singolo primo fotogramma da animare, usa invece vidu-q4-preview/image-to-video; accetta un singolo image_url e rifiuta reference_image_urls.

Richiesta minima funzionante (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"
    }
  }'

La POST restituisce un id attività, non il video:

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

Esegui il polling di GET /v1/tasks/<taskId> finché data.status non diventa success, poi leggi l'MP4 da 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 }
    ]
  }
}

L'URL di output è temporaneo — porta un expireAt (scade dopo qualche giorno) — quindi scarica subito i byte, non fare hotlinking.

Python: invio → polling → download

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

Un punto da interiorizzare: un rendering fallito viene comunque restituito con HTTP 200, con la causa in data.status: "fail" e data.error.code / data.error.message. Una generazione fallita non è un errore HTTP, quindi dirama in base al corpo della risposta, non al codice di stato.

Aggiungere un riferimento vocale

Il campo vocale è reference_audio_urls — un array di massimo 3 clip audio. L'audio imposta il timbro; il tuo prompt continua a trasportare il testo e a guidare il lip-sync.

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

Trappola sul nome del campo: l'intuitivo voice_reference_urls viene rifiutato (il validatore consente solo reference_audio_urls). Vedi la tabella di verifica qui sotto.

Produzione: callback e idempotenza

Per i flussi di lavoro server-side, di solito non vuoi mantenere attivo un ciclo di polling. Allega un callback di primo livello (allo stesso livello di input, non al suo interno) e hiapi invierà via POST l'attività completata al tuo URL:

{
  "model": "vidu-q4-preview/reference-to-video",
  "input": { "prompt": "...", "reference_image_urls": ["..."] },
  "callback": { "url": "https://your-app.com/hooks/vidu", "when": "final" }
}
  • when supporta solo "final" — riceverai una sola notifica allo stato terminale (successo o fallimento), mai notifiche di avanzamento intermedie.
  • Il corpo del callback è lo stesso payload restituito da GET /v1/tasks/<id>.
  • La consegna viene ritentata più volte e può duplicarsi, quindi deduplica per taskId e rendi il tuo handler idempotente.
  • Mantieni il polling come fallback per coprire le finestre in cui il tuo endpoint è temporaneamente irraggiungibile.

Salva il taskId nel momento in cui lo ottieni. Se il tuo poller incontra un errore di rete temporaneo, esegui nuovamente il polling usando l'id salvato — non reinviare mai, altrimenti pagherai per un secondo rendering.

Cosa ho verificato (contratto dello schema)

Ho sondato l'endpoint live con valori deliberatamente non validi (gratuito — le richieste rifiutate non vengono addebitate e i valori non validi non creano mai attività). Il validatore è severo e restituisce un oggetto piatto { "code": 400, "error_code": "INVALID_REQUEST", "message": ... }:

Cosa invii Cosa ricevi
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
quattro reference_audio_urls reference_audio_urls: maxItems: got 4, want 3
reference_image_urls omesso missing required field "reference_image_urls"

Quindi la struttura di input confermata è:

Campo Obbligatorio Valori
prompt Sì Testo
reference_image_urls Sì Da 1 a 15 URL di immagini
reference_audio_urls No Massimo 3 URL audio (campo vocale)
resolution No 540p / 720p / 1080p / 2k / 4k
duration No Intero da 3 a 16 (secondi)
aspect_ratio No 16:9 / 9:16 / 1:1 / 4:3 / 3:4

duration è un intero (5), non una stringa — a differenza di alcuni altri modelli video su hiapi che si aspettano "6". Inviare chiavi extra è un errore bloccante (additional properties ... not allowed), quindi non copiare campi dallo schema image-to-video.

Note lato output prima di collegare il download

  • Ogni clip porta una traccia audio AAC, anche se non hai inviato reference_audio_urls. Il vocabolario sonoro nel prompt guida la traccia ambientale, quindi non dare per scontato che "nessun riferimento vocale = file muto".
  • L'output 4K di Vidu Q4 Preview viene consegnato in HEVC/H.265. È riproducibile nella maggior parte dei player nativi, ma molti browser non riescono a riprodurre inline un MP4 H.265 all'interno di un tag <video> — se devi incorporarlo in una pagina web, ricodificalo in H.264. Le fasce inferiori restituiscono H.264 standard.

Modello di anteprima — tratta le enumerazioni come snapshot

vidu-q4-preview/reference-to-video è un modello in anteprima: è chiamabile oggi, ma non è elencato in /v1/models e lo schema di anteprima può cambiare. Prima di elaborazioni su larga scala, riesegui una volta la verifica con valori non validi (come la tabella sopra) per confermare che le enumerazioni siano ancora valide. La specifica autorevole è costituita dalle regole effettivamente applicate dal validatore più la pagina del modello.

Correlati

Domande frequenti

Reference-to-video è uguale a image-to-video? No. Il reference-to-video fonde da 1 a 15 fotogrammi statici (facoltativamente più fino a 3 clip audio) in un'unica inquadratura composita; l'image-to-video anima un singolo primo fotogramma. Sono endpoint separati con input diversi — il reference-to-video rifiuta persino il campo image_url dell'image-to-video, e viceversa.

Come aggiungo la voce? Allega reference_audio_urls (massimo 3 clip) e indicalo nel prompt ("...con la voce del riferimento audio 1"). Il nome del campo deve essere esattamente reference_audio_urls; voice_reference_urls e altri nomi vengono rifiutati.

Qual è la clip più lunga che posso richiedere? 16 secondi. duration è un intero da 3 a 16.

Devo per forza fare polling? No — allega callback: { "url": ..., "when": "final" } e riceverai una notifica allo stato terminale. Deduplica per taskId e mantieni il polling come fallback.

Quanto costa una clip 4K? La fatturazione è al secondo e la tariffa cresce con la risoluzione, con il 4K come fascia massima — vedi prezzi hiapi. Il flusso di lavoro pratico è iterare prima a 720p e ri-renderizzare a 4k solo le versioni finali che mantieni.

Inizia a creare con artefatti IA persistenti

Ottieni la tua chiave API e chiama modelli di immagini, video e audio tramite un'unica API basata sui task.

Leggi la documentazione API