Tutoriel
Comment utiliser omnihuman-1.5 via l'API HiAPI : tutoriel curl et Python
Démonstration complète de requête pour la génération de vidéo de personne numérique à partir d'audio, interrogation asynchrone et téléchargement de la sortie
Fonctionnalités et cas d'usage de l'API omnihuman-1.5
omnihuman-1.5 transforme un fichier audio et une image de portrait en une vidéo d'une personne numérique en train de parler : le visage de l'image est animé de sorte que les mouvements de la bouche et de la tête suivent la parole fournie. Sur HiAPI, ce modèle est proposé sous forme de point de terminaison audio vers vidéo — vous envoyez l'audio, une image de référence et quelques paramètres de génération, l'API renvoie une tâche, puis vous interrogez cette tâche pour récupérer la vidéo finale.
Les avantages de l'API par rapport aux outils manuels
Les outils navigateur conviennent pour un montage ponctuel. Lorsque la génération vidéo est une étape d'un système plus vaste, l'API est le bon choix :
- Pipelines par lots — générer de nombreux clips de personnes numériques à partir de files de scripts et de pistes audio, sans intervention manuelle.
- Fonctionnalités produit — voix off intégrée à une application, vidéos d'introduction localisées ou messages personnalisés, avec un audio et un portrait différents à chaque rendu.
- Automatisation backend — un workflow de contenu génère la vidéo puis la transmet à un CMS, à un bucket de stockage ou à un service de diffusion.
Structure de la requête
Chaque appel à omnihuman-1.5 sur HiAPI suit la même forme : un POST soumet la tâche, les requêtes suivantes en vérifient l'état. Le rendu n'étant pas instantané, le schéma d'intégration est soumettre → interroger → télécharger, et non soumettre → recevoir la vidéo dans la même réponse. Le reste du tutoriel construit d'abord ce flux avec curl, puis l'implémente en Python.
Prérequis et vos identifiants HiAPI
Avant le premier appel, vérifiez trois choses.
1. Compte et clé d'API
Vous avez besoin d'un compte HiAPI et d'une clé d'API créée dans la console. Considérez la clé comme un secret : ne la placez pas dans le contrôle de version, le code client ou les journaux. En développement, chargez-la depuis une variable d'environnement ; en production, depuis le gestionnaire de secrets de votre plateforme.
export HIAPI_API_KEY="your-api-key-here"
2. Accès réseau et outils de requête
Avec curl, n'importe quel shell récent suffit. Pour la version Python, seule la bibliothèque requests est nécessaire — aucun SDK spécifique à un fournisseur n'est requis, car cette API n'est que du HTTPS classique avec un corps de requête JSON.
pip install requests
3. Entrées requises par le modèle
Préparez les éléments suivants avant d'écrire la requête :
- Audio — la piste vocale qui pilote l'animation de la bouche, fournie sous forme d'URL lisible par l'API ou de référence à un fichier déjà téléversé, selon le format d'entrée accepté par le point de terminaison.
- Image de portrait — le visage à animer. Une photo nette, de face et où la bouche est visible produit les résultats les plus prévisibles.
- Paramètres de génération — les options de résolution, de durée ou de qualité exposées par le modèle. N'envoyez que les champs réellement nécessaires ; pour un premier test, les valeurs par défaut sont généralement raisonnables.
Chaque requête transmet la clé via l'en-tête Authorization sous la forme Bearer <your-key>. Si le premier appel renvoie 401, vérifiez d'abord cet en-tête.
Lancer la requête avec curl
L'appel de soumission est un POST avec un corps JSON. Le chemin exact et les noms de champs d'omnihuman-1.5 figurent sur la page de référence API de ce modèle ; la structure ci-dessous montre la forme de l'appel et les champs que vous allez remplir.
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"
}'
Explication champ par champ
Authorization— porte la clé d'API. Sans elle, la requête est rejetée avant même de commencer le moindre travail.Content-Type: application/json— le corps est du JSON ; omettre cet en-tête est une cause fréquente d'erreurs de validation déroutantes.audio_url— la piste vocale. Utilisez une URL lisible publiquement ou autrement accessible par l'API, et privilégiez un emplacement stable plutôt qu'un lien signé qui expire en cours de rendu.image_url— le portrait à animer. Les mêmes règles d'accessibilité s'appliquent.
Ce qui est renvoyé
Une soumission réussie ne renvoie pas de vidéo, mais un objet tâche contenant un identifiant (généralement un champ id) et un état tel que queued ou processing. Conservez cet identifiant ; c'est le handle que vous utiliserez à chaque vérification d'état ultérieure.
{
"id": "job_abc123",
"status": "queued"
}
Vous pouvez confirmer la réussite de la soumission en vérifiant le code d'état HTTP et la présence de l'identifiant de tâche. Si la réponse contient des messages de validation, ils pointent vers les champs en erreur — généralement une URL manquante ou mal formée.
Implémenter la même requête en Python
L'appel curl se transpose directement en Python. La version ci-dessous est conçue pour être intégrée telle quelle dans un service : la clé provient d'une variable d'environnement, le payload est un dictionnaire construit dynamiquement, et les erreurs sont levées plutôt qu'étouffées.
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"]
Pourquoi cette écriture
json=payloadlaisserequestssérialiser le corps et définir le type de contenu, vous évitant d'oublier l'en-tête JSON.**optionsgarde la fonction flexible : ajoutez des paramètres de génération en arguments nommés sans modifier le littéral du payload.timeout=60empêche une connexion bloquée de bloquer indéfiniment le worker. La soumission est un appel rapide ; les longues attentes doivent se trouver à l'étape d'interrogation, pas ici.raise_for_status()convertit les réponses non 2xx en exceptions capturables et journalisables, avec accès au corps de la réponse pour le diagnostic.
Conservez l'identifiant de tâche renvoyé et transmettez-le à la fonction d'assistance d'interrogation — la section suivante la construit.
Gérer le cycle de vie asynchrone : interroger jusqu'à la fin
La génération vidéo prend du temps, c'est pourquoi l'API est asynchrone par conception. Après la soumission, vous interrogez à plusieurs reprises l'état de la tâche jusqu'à ce qu'elle atteigne un état terminal.
Boucle d'interrogation
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")
Déterminer quand s'arrêter
Trois résultats mettent fin à la boucle, et votre code doit gérer chacun d'eux :
- Succès — la tâche signale un état terminé et contient une référence à la vidéo de sortie. Sortez de la boucle et passez au téléchargement.
- Échec — la tâche signale un état d'erreur. Ne réessayez pas aveuglément ; examinez d'abord le message d'erreur, car les échecs proviennent souvent d'URL d'entrée illisibles ou d'audio non pris en charge.
- Délai dépassé — votre propre limite de temps réel est atteinte. Traitez-la différemment d'un échec : la tâche peut encore se terminer côté serveur, décidez donc consciemment de continuer à interroger, de prolonger la fenêtre ou d'abandonner.
Bonnes pratiques d'interrogation
Utilisez un intervalle raisonnable plutôt qu'une boucle serrée. Pour le rendu vidéo, quelques secondes entre chaque vérification suffisent et rendent le volume de requêtes prévisible. Si une file d'attente longue est attendue, augmentez progressivement le délai, et fixez toujours une limite pour qu'un worker bloqué n'interroge pas indéfiniment. En production, préférez un worker en arrière-plan ou une file de tâches plutôt qu'une interrogation dans le gestionnaire de requête web.
Télécharger et stocker la vidéo de sortie
Une fois l'interrogation revenue avec la tâche terminée, la réponse porte une référence vidéo — généralement un champ URL dans l'objet résultat. Récupérez-la et persistez-la dans votre propre stockage, sans dépendre de ce lien à long terme.
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)
Points d'attention qui font gagner du temps de débogage
- Téléchargement en flux. Les vidéos sont volumineuses ; l'écriture par blocs évite de charger tout le fichier en mémoire, ce qui compte dans un worker à mémoire limitée.
- Nom de fichier déterministe. Dérivez-le de l'identifiant de tâche plus un horodatage, afin que les exécutions soient traçables et que les relances ne se chevauchent pas.
- Télécharger d'abord dans un fichier temporaire, puis déplacer. Écrivez dans un chemin temporaire et renommez une fois terminé, afin qu'un téléchargement partiel ne soit jamais pris pour un fichier complet.
- Considérer l'URL renvoyée comme temporaire. Copiez les octets dans votre propre bucket ou système de fichiers, et enregistrez l'identifiant de tâche avec l'objet stocké pour le retrouver plus tard.
- Vérifier avant de déclarer le succès. Avant de marquer la tâche comme terminée en base, vérifiez que le fichier téléchargé n'est pas vide et que sa taille est raisonnable.
Diagnostiquer les pannes courantes de requête et d'interrogation
La plupart des problèmes d'intégration se rangent en quelques catégories. Passez-les en revue dans l'ordre.
Erreurs d'authentification et de requête
401 Unauthorized— clé manquante, mal formée ou non envoyée comme jetonBearer. Vérifiez attentivement l'en-tête, y compris l'espace aprèsBearer.403— la clé est valide mais n'a pas accès à ce point de terminaison ; vérifiez qu'elle appartient au projet prévu.- Erreurs de validation
422/400— lisez le message. Les causes courantes incluent unaudio_urlmanquant, unimage_urlmanquant, une URL illisible ou un format audio non pris en charge. - HTML inattendu dans la réponse — vous avez atteint le mauvais hôte ou le mauvais chemin. Vérifiez l'URL de base dans la référence API au lieu de la reconstruire de mémoire.
Tâche en échec ou qui ne se termine jamais
- L'API ne peut pas accéder à l'URL d'entrée — un lien qui fonctionne dans le navigateur peut être bloqué par un réseau privé, une signature expirée ou une protection contre le hotlinking. Testez d'abord avec une URL publique stable.
- Audio et image incompatibles — une piste silencieuse, extrêmement longue ou dans un format non pris en charge peut bloquer ou faire échouer le rendu. Validez d'abord le pipeline avec un court extrait au format standard.
- Interrogation trop fréquente — une boucle serrée peut déclencher des limites de débit et produire des erreurs qui ressemblent à un échec de tâche. Ralentissez et ajoutez un backoff.
- Délai d'interrogation trop court — abandonner une tâche en file après quelques secondes produit de faux délais dépassés. Fixez un temps d'attente maximal réaliste et consignez l'état observé avant d'arrêter.
- États terminaux non gérés — si la boucle ne vérifie que le succès, un échec tournera à vide jusqu'au délai dépassé. Traitez explicitement la branche des états d'échec.
Réflexe de validation minimal
En cas de problème, réduisez à un test minimal : un court extrait audio, un petit portrait, une soumission et une vérification d'état quelques secondes plus tard. Si cela fonctionne, la panne se situe dans votre payload, votre logique d'interrogation ou l'hébergement des entrées — pas dans l'appel API lui-même.
Articles similaires
Voir tous les articles →-
Tutoriel
Comment appeler hailuo-2.3-fast/image-to-video via l'API HiAPI : curl et Python en pratique
La première requête exploitable du palier image-vers-vidéo rapide et économique — de l'ID du modèle au téléchargement du MP4
-
Tutoriel
Comment appeler hailuo-2.3/text-to-video via l'API HiAPI : curl, Python et exemples de requêtes exécutables
-
Tutoriel
Utiliser Kandinsky 6.0 Pro texte-vers-vidéo sur HiAPI : tutoriel curl et Python
Démonstration pratique axée sur la requête : construire l'appel du prompt au clip vidéo, soumettre la requête, interroger l'état d'achèvement et télécharger le résultat