Tutoriale
API reference-to-video vidu-q3-ad: curl, Python e una richiesta eseguibile
Cosa costruirai
Avvia una chiamata reference-to-video sull'API asincrona /v1/tasks di hiapi per trasformare da 1 a 7 immagini statiche di prodotto in un breve video pubblicitario con audio nativo. vidu-q3-ad/reference-to-video è il livello di Vidu Q3 pensato per la pubblicità: carichi le immagini di riferimento del prodotto, scrivi una descrizione della scena e il modello restituisce un MP4 da 3 a 15 secondi, con montaggio intelligente, movimenti di camera ed effetti sonori generati automaticamente — nessuna traccia audio separata da fornire.
Devi inviare una sola POST, poi eseguire il polling (o ricevere un callback) finché l'attività non è completata, quindi scaricare l'MP4. Ottieni prima la chiave dalla console hiapi; ogni richiesta qui sotto usa Authorization: Bearer sk-....
Tre elementi da copiare alla lettera:
- Endpoint di invio:
POST https://api.hiapi.ai/v1/tasks - Endpoint di polling:
GET https://api.hiapi.ai/v1/tasks/{taskId} - ID modello:
vidu-q3-ad/reference-to-video— né la barra né il suffisso-adpossono essere omessi;vidu-q3-mixevidu-q4-previewsono endpoint diversi.
Schema di input (rilevato in tempo reale)
| Campo | Obbligatorio | Tipo | Descrizione |
|---|---|---|---|
prompt |
Sì | string | Descrizione della scena; indica i prodotti con un numero, ad esempio “l'orologio nell'immagine di riferimento 1” |
reference_image_urls |
Sì | array, 1–7 | URL pubblici delle immagini statiche di prodotto (recuperati dal server) |
duration |
Sì | integer, 3–15 | Numero di secondi; deve essere un intero (4.5 viene rifiutato) |
size |
No | enum (10 valori) | Determina insieme le proporzioni e il livello 720/1080; predefinito 1280*720 |
Il validatore è molto rigoroso — qualsiasi campo al di fuori dell'elenco sopra viene rifiutato direttamente. Due tipi di rifiuto meritano attenzione, perché fanno inciampare chiunque migri da altri modelli video di hiapi:
aspect_ratioeresolutionvengono entrambi rifiutati. Quasi tutti gli altri endpoint video di hiapi usano questi due campi; q3-ad no. Le dimensioni si controllano solo tramitesize.reference_audio_urlsviene anch'esso rifiutato. A differenza del livello reference-to-video di Vidu Q4 (che accetta frammenti vocali), q3-ad non ha input audio — la sua colonna sonora è generata nativamente. (Come l'ho confermato, vedi la sezione di verifica qui sotto.)
Come scegliere size
size è una stringa width*height presa da un insieme fisso. Puoi leggerla come una griglia di cinque proporzioni × due livelli di qualità:
| Proporzioni | Livello 720 | Livello 1080 |
|---|---|---|
| 16:9 orizzontale | 1280*720 |
1920*1080 |
| 9:16 verticale | 720*1280 |
1080*1920 |
| 1:1 quadrato | 1280*1280 |
1808*1808 |
| 4:3 | 1280*960 |
1920*1440 |
| 3:4 | 960*1280 |
1440*1920 |
Scegli la riga in base alla destinazione (per Reels e TikTok usa il verticale 720*1280 / 1080*1920, per i pre-roll di YouTube la riga orizzontale) e la colonna in base al compromesso tra qualità e budget. La fatturazione si basa sui secondi di output e il livello determina il prezzo al secondo — dettagli nella pagina dei prezzi; il minimo fatturabile è una clip da 3 secondi.
Richiesta minima (curl)
Due passaggi: invio, poi polling.
# 1) Invia — restituisce un 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) Esegui il polling finché data.status diventa "success" o "fail"
curl -s https://api.hiapi.ai/v1/tasks/THE_TASK_ID \
-H "Authorization: Bearer sk-your-key"
# Successo -> data.status == "success", e data.output[0].url è l'MP4
Gli URL delle immagini di riferimento devono essere accessibili pubblicamente — l'attività li recupera sul server, quindi localhost o URL firmati che scadono dopo pochi secondi non vanno bene.
Python: invio, polling, download
import time
import requests # oppure urllib/subprocess per zero dipendenze
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", # verticale 1080p, per 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}") # un 400 finisce qui
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 # scarica subito — gli URL di output scadono
open("ad.mp4", "wb").write(mp4)
Il rendering di Q3-ad di solito si completa in uno o due minuti; un intervallo di polling di 5 secondi è più che sufficiente. Gli URL di output sono temporanei (con expireAt), quindi dopo il successo dell'attività scarica subito i byte invece di collegarlo direttamente in una pagina.
Pattern per la produzione
Usa i callback invece del polling. In uno scenario server-side, configura un callback di primo livello per evitare di mantenere un ciclo di polling:
{
"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 supporta solo "final" — l'hook si attiva una volta quando l'attività entra nello stato finale, e il suo corpo della richiesta è lo stesso payload restituito da GET /v1/tasks/{taskId}. Gli hook possono essere ritentati, quindi deduplica per taskId e mantieni un polling lento come fallback nel caso una consegna vada persa.
Ramifica sul corpo della risposta, non sul codice di stato HTTP. Un rendering fallito restituisce comunque HTTP 200; le informazioni di fallimento si trovano in data.status == "fail", con i dettagli in data.error. Solo i rifiuti a livello di richiesta (campo errato, chiave mancante, non autenticato) usano 4xx, restituendo {"code":400,"error_code":"INVALID_REQUEST","message":"...","data":null}.
Idempotenza. Ogni invio crea una nuova attività fatturata, quindi salva il taskId nel momento stesso in cui lo ricevi e, in caso di retry, ripeti il polling su quell'ID. Non inviare mai di nuovo solo perché una singola richiesta di polling è andata in timeout.
Cosa ho verificato
Ho sondato l'endpoint live con valori non validi, che vengono rifiutati gratuitamente in fase di validazione — nessuna attività creata, nessuna fatturazione (i valori non validi falliscono prima che inizi qualsiasi rendering, il che è più sicuro di omettere un campo). Le risposte reali sono lo schema:
- Corpo quasi vuoto →
reference_image_urls: missing required field ...; duration: missing required field .... Quindiprompt,reference_image_urlsedurationsono tutti obbligatori. duration: 99999→maximum: got 99,999, want 15;duration: 1→minimum: got 1, want 3;duration: 4.5→got number, want integer. Duration è un intero da 3 a 15.reference_image_urlscon 8 elementi →maxItems: got 8, want 7. Il massimo è 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_ratioeresolution→ entrambi restituisconoadditional properties ... not allowed. Non sono campi di q3-ad; usasize.reference_audio_urlspassato come array ben formato →additional properties 'reference_audio_urls' not allowed. (Se passato come non-array, scatta prima un controllo media separato — “must be an array” — il che è fuorviante: il campo non è davvero nello schema.) Questo livello non ha input di riferimento vocale; l'audio è generato nativamente.
Questa è una guida all'integrazione, quindi non contiene affermazioni sulla qualità — non ho eseguito rendering a pagamento per questo articolo. Per sapere come appare un output[0].url riuscito, la pagina del modello qui sotto ospita l'esempio fornito dall'endpoint stesso: un MP4 reale con traccia audio.
Guide correlate
- Pagina del modello Vidu Q3 Ad reference-to-video — specifiche, prompt pubblicitari di esempio e casella di prova online.
- Guida all'API Vidu Q4 reference-to-video — livello superiore: fino a 4K, da 1 a 15 immagini di riferimento e il campo vocale
reference_audio_urlsche q3-ad non ha. - Guida all'API Seedance 2.5 reference-to-video — un altro endpoint reference-to-video, utile per confrontare i modelli.
- Prompt per movimenti di camera video AI — linguaggio cinematografico adatto al campo
prompt. - Guida rapida hiapi e prezzi.
Domande frequenti
Come rendo la clip verticale o orizzontale? Tramite size, non aspect_ratio. Per il verticale usa 720*1280 o 1080*1920, per l'orizzontale 1280*720 o 1920*1080.
Posso fornire un doppiaggio o un riferimento sonoro? Con questo livello no — reference_audio_urls viene rifiutato. Q3-ad genera da sé l'audio nativo. Se hai bisogno di guidare l'audio con un frammento di riferimento, usa il livello reference-to-video di Vidu Q4.
Quante immagini di prodotto posso inviare? Da una a sette, in reference_image_urls, e nel prompt riferiscile con un numero (“la bottiglia nell'immagine di riferimento 2”).
La mia attività ha restituito 200 ma nessun video — perché? Guarda data.status. "fail" restituisce HTTP 200, con la causa in data.error; solo le richieste malformate ottengono 4xx.
Quanto costa? La fatturazione si basa sui secondi di output; il livello di size (classe 720 vs classe 1080) determina il prezzo al secondo. Il minimo è una clip da 3 secondi. Le tariffe attuali sono nella pagina dei prezzi.
Articoli correlati
Vedi tutti gli articoli →-
Tutoriale
Come chiamare hailuo-2.3-fast/image-to-video tramite l'API HiAPI: pratica con curl e Python
La prima richiesta funzionante per il livello image-to-video veloce ed economico — dall'ID del modello al download di un MP4
-
Tutoriale
Come chiamare hailuo-2.3/text-to-video tramite l'API HiAPI: curl, Python ed esempi di richiesta eseguibili
-
Tutoriale
Utilizzare Kandinsky 6.0 Pro su HiAPI per la generazione di video da testo: tutorial con curl e Python
Dimostrazione pratica guidata dalla richiesta: costruire la chiamata da prompt a clip video, inviare la richiesta, monitorare lo stato di completamento e scaricare il risultato