HiAPI
Blog

Tutoriale

Come usare omnihuman-1.5 tramite l'API HiAPI: tutorial curl e Python

Procedura completa di richiesta, polling asincrono e download dell'output per la generazione di digital human da audio a video

Nov 3, 2026
深棕与燕麦色宽带交织的扁平编织纹理封面图,点缀克制黄铜色调,几何秩序感强

Funzionalità e scenari d'uso dell'API omnihuman-1.5

omnihuman-1.5 converte un file audio e un'immagine ritratto in un video di un digital human che parla: il volto nell'immagine viene animato in modo che i movimenti della bocca e della testa seguano il parlato fornito. Su HiAPI il modello è disponibile come endpoint audio-to-video: invii l'audio, un'immagine di riferimento e alcuni parametri di generazione, l'API restituisce un job e poi esegui il polling di quel job per ottenere il video finale.

I vantaggi dell'API rispetto agli strumenti manuali

Gli strumenti nel browser vanno bene per montaggi occasionali. Quando la generazione video è un passaggio all'interno di un sistema più ampio, l'API è la scelta corretta:

  • Pipeline batch — generare molti clip di digital human da script e code di tracce audio, senza intervento manuale.
  • Funzionalità di prodotto — voce fuori campo in-app, video di onboarding localizzati o messaggi personalizzati, con audio e ritratto diversi a ogni rendering.
  • Automazione backend — i flussi di lavoro dei contenuti generano il video e poi lo passano a un CMS, a un bucket di archiviazione o a un servizio di distribuzione.

La struttura della richiesta

Ogni chiamata a omnihuman-1.5 su HiAPI segue la stessa forma: un POST invia il job, le richieste successive ne controllano lo stato. Poiché il rendering non è istantaneo, il modello di integrazione è invia → polling → scarica, non invia → ricevi il video nella stessa risposta. Il resto del tutorial costruisce prima questo flusso con curl, poi lo implementa in Python.

Prerequisiti e credenziali HiAPI

Prima della prima chiamata, verifica tre cose.

1. Account e chiave API

Ti servono un account HiAPI e una chiave API creata nella console. Tratta la chiave come un segreto: non inserirla nel controllo di versione, nel codice client o nei log. In sviluppo caricala da una variabile d'ambiente, in produzione dal gestore di segreti della piattaforma.

export HIAPI_API_KEY="your-api-key-here"

2. Accesso alla rete e strumenti di richiesta

Con curl va bene qualsiasi shell recente. Per la versione Python serve solo la libreria requests: nessun SDK specifico del fornitore, perché l'API è semplice HTTPS con corpo JSON.

pip install requests

3. Input richiesti dal modello

Prepara quanto segue prima di scrivere la richiesta:

  • Audio — la traccia vocale che guida l'animazione della bocca, fornita come URL leggibile dall'API o come riferimento a un file caricato, a seconda del formato di input accettato dall'endpoint.
  • Immagine ritratto — il volto da animare. Una foto nitida, frontale e con la bocca visibile produce i risultati più prevedibili.
  • Parametri di generazione — qualsiasi opzione di risoluzione, durata o qualità esposta dal modello. Invia solo i campi che ti servono davvero; per i primi test i valori predefiniti sono di solito ragionevoli.

Ogni richiesta trasmette la chiave tramite l'header Authorization nel formato Bearer <your-key>. Se la prima chiamata restituisce 401, controlla subito questo header.

Inviare la richiesta con curl

La chiamata di invio è un POST con corpo JSON. Il percorso esatto e i nomi dei campi di omnihuman-1.5 sono indicati nella pagina di riferimento API del modello; la struttura seguente mostra la forma della chiamata e i campi da compilare.

curl -X POST "https://api.hiapi.ai/v1/omnihuman-1.5/generate" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "audio_url": "https://your-bucket.example.com/speech.mp3",
    "image_url": "https://your-bucket.example.com/portrait.jpg"
  }'

Descrizione campo per campo

  • Authorization — trasporta la chiave API. Senza di essa, la richiesta viene rifiutata prima di iniziare qualsiasi lavoro.
  • Content-Type: application/json — il corpo è JSON; omettere questo header è una causa comune di errori di validazione poco chiari.
  • audio_url — la traccia vocale. Usa un URL pubblicamente leggibile o comunque accessibile all'API e preferisci una posizione stabile a un link firmato che scade a metà rendering.
  • image_url — il ritratto da animare. Valgono le stesse regole di accessibilità.

Cosa viene restituito

Un invio riuscito non restituisce il video, bensì un oggetto job con un identificatore (di solito il campo id) e uno stato come queued o processing. Salva quell'identificatore: è il riferimento che userai per ogni successivo controllo di stato.

{
  "id": "job_abc123",
  "status": "queued"
}

Puoi confermare che l'invio è riuscito controllando il codice di stato HTTP e la presenza dell'identificatore del job. Se la risposta contiene messaggi di validazione, indicano i campi errati — di solito URL mancanti o malformati.

Implementare la stessa richiesta in Python

La chiamata curl si traduce direttamente in Python. La versione seguente è pensata per essere inserita direttamente in un servizio: la chiave proviene da una variabile d'ambiente, il payload è un dizionario costruito dinamicamente e gli errori vengono sollevati invece di essere ignorati.

import os
import requests

API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = "https://api.hiapi.ai/v1"

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

def submit_omnihuman_job(audio_url: str, image_url: str, **options) -> str:
    payload = {
        "audio_url": audio_url,
        "image_url": image_url,
    }
    payload.update(options)

    response = requests.post(
        f"{BASE_URL}/omnihuman-1.5/generate",
        headers=HEADERS,
        json=payload,
        timeout=60,
    )
    response.raise_for_status()

    data = response.json()
    return data["id"]

Perché è scritto così

  • json=payload fa sì che requests serializzi il corpo e imposti il content type, così non puoi dimenticare l'header JSON.
  • **options mantiene la funzione flessibile: aggiungi parametri di generazione passandoli come argomenti keyword, senza modificare il letterale del payload.
  • timeout=60 impedisce che una connessione bloccata blocchi indefinitamente il worker. L'invio è una chiamata rapida; le attese lunghe vanno nel passaggio di polling, non qui.
  • raise_for_status() converte le risposte non 2xx in eccezioni catturabili e registrabili, con il corpo della risposta disponibile per la diagnosi.

Conserva l'identificatore del job restituito e passalo alla funzione ausiliaria di polling — la sezione successiva la costruisce.

Gestire il ciclo di vita asincrono: polling fino al completamento

La generazione video richiede tempo, quindi l'API è asincrona per progettazione. Dopo l'invio, interroghi ripetutamente lo stato del job finché non raggiunge uno stato terminale.

Ciclo di polling

import time

def wait_for_job(job_id: str, interval: int = 5, max_wait: int = 600) -> dict:
    waited = 0
    while waited < max_wait:
        response = requests.get(
            f"{BASE_URL}/omnihuman-1.5/jobs/{job_id}",
            headers=HEADERS,
            timeout=30,
        )
        response.raise_for_status()
        job = response.json()
        status = job["status"]

        if status == "succeeded" or status == "completed":
            return job
        if status == "failed" or status == "error":
            raise RuntimeError(f"Job {job_id} failed: {job}")

        time.sleep(interval)
        waited += interval

    raise TimeoutError(f"Job {job_id} did not finish within {max_wait}s")

Decidere quando fermarsi

Tre esiti chiudono il ciclo e il tuo codice deve gestirli tutti:

  • Successo — il job riporta uno stato di completamento e contiene un riferimento al video di output. Esci e passa al download.
  • Fallimento — il job riporta uno stato di errore. Non riprovare alla cieca; controlla prima il messaggio di errore, perché i fallimenti sono spesso causati da URL di input non leggibili o audio non supportati.
  • Timeout — viene raggiunto il tuo limite di tempo reale. Trattalo come un caso diverso dal fallimento: il job potrebbe comunque completarsi sul server, quindi decidi consapevolmente se continuare il polling, estendere la finestra o abbandonare.

Buone maniere nel polling

Usa un intervallo ragionevole invece di un ciclo stretto. Per il rendering video, pochi secondi tra un controllo e l'altro sono sufficienti e rendono prevedibile il volume di richieste. Se prevedi code lunghe, applica un backoff progressivo e imposta sempre un limite, così un worker bloccato non esegue polling per sempre. In produzione, preferisci un worker in background o una coda di task al polling all'interno di un handler di richieste web.

Scaricare e archiviare il video di output

Dopo che il polling restituisce il job completato, la risposta contiene un riferimento al video — di solito un campo URL all'interno dell'oggetto risultato. Recuperalo e salvalo nel tuo archivio, invece di dipendere a lungo da quel link.

def download_video(job: dict, destination: str) -> None:
    video_url = job.get("output_url") or job.get("result", {}).get("video_url")
    if not video_url:
        raise ValueError(f"No video reference in job payload: {job}")

    with requests.get(video_url, stream=True, timeout=120) as response:
        response.raise_for_status()
        with open(destination, "wb") as file:
            for chunk in response.iter_content(chunk_size=8192):
                file.write(chunk)

Accortezze che fanno risparmiare tempo nel debug

  • Download in streaming. I video sono grandi; la scrittura a blocchi evita di caricare l'intero file in memoria, cosa importante nei worker con memoria limitata.
  • Nomi file deterministici. Derivali dall'identificatore del job più un timestamp, così le esecuzioni sono tracciabili e le ripetizioni non si sovrascrivono.
  • Scarica prima su file temporaneo, poi sposta. Scrivi su un percorso temporaneo e rinomina al termine, così un download parziale non venga mai scambiato per un file completo.
  • Considera temporaneo l'URL restituito. Copia i byte nel tuo bucket o filesystem e registra l'identificatore del job insieme all'oggetto archiviato, per ritrovarlo in seguito.
  • Verifica prima di dichiarare il successo. Prima di contrassegnare il job come completato nel database, controlla che il file scaricato non sia vuoto e abbia una dimensione ragionevole.

Diagnosticare i problemi comuni di richiesta e polling

La maggior parte dei problemi di integrazione rientra in poche categorie. Esaminale in ordine.

Errori di autenticazione e richiesta

  • 401 Unauthorized — chiave mancante, malformata o non inviata come token Bearer. Controlla attentamente l'header, incluso lo spazio dopo Bearer.
  • 403 — la chiave è valida ma non ha accesso a questo endpoint; verifica che appartenga al progetto previsto.
  • Errori di validazione 422 / 400 — leggi il messaggio. Le cause comuni includono audio_url mancante, image_url mancante, URL non leggibile o formato audio non supportato.
  • HTML inatteso nella risposta — hai raggiunto l'host o il percorso sbagliato. Verifica il base URL dalla documentazione API, invece di ricostruirlo a memoria.

Job falliti o che non terminano mai

  • L'API non riesce ad accedere all'URL di input — un link che funziona nel browser può essere bloccato da rete privata, firma scaduta o protezione anti-hotlink. Prova prima con un URL pubblico stabile.
  • Audio e immagine non compatibili — tracce mute, estremamente lunghe o in formati non supportati possono bloccare o far fallire il rendering. Verifica la pipeline prima con un frammento breve in formato standard.
  • Polling troppo frequente — un ciclo stretto può attivare limiti di frequenza e generare errori che sembrano fallimenti del job. Rallenta e aggiungi backoff.
  • Tempo di polling troppo breve — abbandonare dopo pochi secondi un job in coda produce timeout errati. Imposta un tempo massimo di attesa realistico e registra lo stato visto prima di fermarti.
  • Stati terminali non gestiti — se il ciclo controlla solo il successo, i fallimenti girano a vuoto fino al timeout. Ramifica esplicitamente sugli stati di fallimento.

Abitudine di verifica minimalista

Quando qualcosa non funziona, riduci al test minimo: un frammento audio breve, un piccolo ritratto, un invio e un controllo di stato dopo pochi secondi. Se questo riesce, il problema è nel payload, nella logica di polling o nell'hosting dell'input — non nella chiamata API stessa.

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