Tutoriel
Comment utiliser kling-3.0-omni/image-to-video via l'API HiAPI : guide curl et Python
Ce que fait le point de terminaison image-to-video
La génération de vidéo n'est pas un appel synchrone. Sur HiAPI, kling-3.0-omni/image-to-video suit le modèle soumettre puis interroger : vous envoyez une requête HTTP décrivant la tâche, l'API accepte la requête et renvoie un identifiant de tâche, puis vous interrogez cette tâche jusqu'à ce que la génération de la vidéo soit terminée.
Cette structure en deux étapes a une raison d'être solide. Rendre une vidéo à partir d'une image fixe prend du temps — bien plus longtemps qu'une requête HTTP typique ne devrait rester ouverte. Si le point de terminaison bloquait jusqu'à ce que le fichier soit prêt, vous subiriez à chaque appel des dépassements de délai de passerelle et des coupures de connexion. En renvoyant immédiatement un handle de tâche, l'API laisse votre code décider combien de temps attendre, à quelle fréquence vérifier et comment gérer les erreurs.
Une tâche typique comporte trois parties logiques :
- Média d'entrée — l'image (ou l'ensemble d'images) qui ancre la prise de vue.
- Paramètres de génération — texte du prompt, options liées au mouvement, choix audio et de résolution.
- Cycle de vie — la réponse de soumission contenant l'ID de tâche, suivie d'une vérification de statut qui aboutit finalement à l'URL de la vidéo produite ou à la raison de l'échec.
Il est utile de concevoir ce point de terminaison comme une file d'attente avec un reçu. L'appel de soumission correspond au dépôt de votre bon de travail ; le reçu est l'ID de tâche ; l'appel d'interrogation correspond à votre demande au guichet pour savoir si la commande est prête. Aucune vidéo n'est renvoyée lors de la soumission, donc tout client que vous écrivez doit dès le départ s'organiser autour de ces deux phases.
Deux conséquences en découlent. Premièrement, votre gestion des erreurs doit être séparée : un corps de requête rejeté est un problème au moment de la soumission, corrigeable dans le code ; tandis qu'un échec de rendu est un problème au niveau de la tâche, qu'aucun nombre de nouvelles tentatives du même corps de requête ne résoudra. Deuxièmement, vous avez besoin d'un endroit pour stocker l'ID de tâche — une ligne de journal, une ligne de base de données, une variable dans le script — car c'est votre seul handle sur le travail en cours.
Une fois ce modèle mental établi, le reste de ce guide relève surtout de la plomberie : construire la requête, puis l'attendre correctement.
Construire une requête curl fonctionnelle
Commencez par la plus petite requête fonctionnelle possible, confirmez qu'elle est acceptée, puis ajoutez des options. Les noms exacts des champs JSON et le chemin du point de terminaison sont définis sur la page de référence de ce modèle sur HiAPI — consultez cette page pour obtenir le schéma actuel, plutôt que de faire confiance à des extraits d'articles de blog (y compris celui-ci).
L'appel de soumission a une structure prévisible. Vous vous authentifiez avec votre clé d'API HiAPI dans l'en-tête Authorization, déclarez Content-Type: application/json et envoyez un corps JSON. Conceptuellement, le corps ressemble à ceci :
{
"model": "kling-3.0-omni/image-to-video",
"input": {
"image": "https://your-cdn.example.com/frame-first.jpg",
"prompt": "A slow dolly-in as morning light crosses the room"
}
}
La structure compte plus que les valeurs littérales : l'identifiant du modèle, un objet d'entrée portant une référence à l'image source et le prompt, et un espace pour les options de génération. Avant de coder en dur chaque clé, vérifiez-la par rapport à la documentation actuelle.
L'appel curl équivalent suit le modèle courant :
curl -sS -X POST "$HIAPI_BASE_URL/v1/video/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d @request.json
Conserver le corps de requête dans request.json plutôt qu'en ligne facilite grandement les itérations — vous modifiez un fichier, pas une entrée de l'historique du shell.
Lire la réponse
Une soumission réussie est volontairement banale. Attendez-vous à un identifiant de tâche et à un statut indiquant que la requête a été acceptée mais n'est pas terminée. Analysez-la, affichez-la et sauvegardez-la :
curl -sS -X POST "$HIAPI_BASE_URL/v1/video/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d @request.json | tee submit.json
Vérifiez d'abord le code de statut HTTP. 4xx signifie que la requête elle-même est rejetée — mauvaise clé, JSON mal formé, option non prise en charge, URL d'image invalide. 2xx signifie que la tâche est entrée dans le système et, à partir de ce moment, le signal utile provient du statut de la tâche, et non du code de statut HTTP.
Avant d'écrire le moindre code d'interrogation, exécutez une soumission manuellement une fois. Confirmez que vous voyez l'ID de tâche dans la sortie. Cet aller-retour manuel permet de détecter la plupart des erreurs de configuration dès le début.
Gérer les entrées de première et de dernière image
L'image que vous envoyez n'est pas qu'une référence — elle contraint le point de départ de la prise de vue. Cette distinction dicte la plupart des décisions de conception de cette section.
Première image uniquement
Lorsque vous fournissez une seule image, traitez-la comme l'image d'ouverture. Le prompt décrit alors ce qui doit se produire à partir de cette image : mouvement de caméra, action du sujet, changements de lumière, rythme. Comme le modèle doit créer tout ce qui suit la première image, un prompt décrivant une trajectoire fonctionne mieux qu'un prompt décrivant une scène statique. « Reste immobile et reste beau » ne donne au modèle rien à animer ; « elle se tourne vers la fenêtre et la lumière se réchauffe en même temps » lui donne une direction.
Ajouter une dernière image
L'entrée de dernière image transforme la tâche en problème d'interpolation. Vous fournissez deux extrémités et le modèle génère le chemin entre elles. C'est très puissant pour des transitions maîtrisées — un produit qui pivote de la vue de face à la vue de dos, un personnage qui passe d'une pose à une autre — parce que le point final est fixé, et non imaginé.
Trois remarques pratiques :
- Gardez les deux images compatibles. Un cadrage, une perspective et une échelle de sujet similaires rendent l'interpolation crédible. Des compositions très différentes forcent le modèle à inventer un pont qui pourrait ne pas exister.
- Réécrivez le prompt. Avec deux images, votre texte doit décrire le mouvement entre elles, et non les points d'arrivée. Nommer un style de mouvement et une durée est plus naturel que de raconter l'état final que vous avez déjà fourni.
- Attendez-vous à ce que la structure de la requête change. La dernière image est un champ d'entrée distinct, donc votre corps de requête gagne une clé. Construisez l'objet de requête de façon à pouvoir ajouter des champs optionnels sans tout refactoriser.
Dans le code, traitez les images comme un petit ensemble d'entrées nommées, plutôt qu'une collection d'URL en vrac :
inputs = {"image": first_frame_url}
if last_frame_url:
inputs["last_frame"] = last_frame_url
Ce test conditionnel garde les appels à une ou deux images sur le même chemin de code, ce qui devient important dès que vous commencez à générer des variantes.
Enfin, hébergez les images à un endroit fiable et accessible. Une URL qui expire en cours de tâche échouera après la soumission, et l'erreur ressemblera à un échec de génération plutôt qu'à un problème de ressource.
Configurer l'audio et la résolution de sortie
L'audio et la résolution sont des choix au niveau de la requête, pas des paramètres globaux. Vous les décidez par tâche, ce qui signifie qu'ils doivent vivre dans le constructeur de corps de requête, à côté du prompt, plutôt que dans une constante de configuration définie une fois pour toutes.
Audio
Les options audio vous permettent généralement de demander une bande-son avec la vidéo, ou de l'omettre. Traitez cela comme une décision de modélisation liée au cas d'usage : un clip social court peut tirer parti d'un audio généré, tandis qu'un extrait que vous comptez sonoriser dans un éditeur ne devrait probablement pas transporter d'audio. Demander un audio que vous n'utiliserez jamais gaspille du temps de génération sans aucun bénéfice.
Comme le comportement audio est l'un des domaines les plus susceptibles d'évoluer, ne codez pas en dur d'hypothèses sur le contenu de la piste ou sur sa relation avec le prompt. Lisez la documentation actuelle du modèle, puis validez la sortie avec une vraie tâche avant de concevoir un quelconque flux en aval autour d'elle.
Résolution
Une résolution plus élevée signifie plus de pixels par image et nettement plus de calcul. Un flux de travail pratique consiste à itérer à une résolution modérée pendant que vous ajustez le prompt et le choix des images, puis à régénérer la configuration gagnante à la résolution finale. Régénérer un bon résultat coûte bien moins cher que de découvrir à la fin que votre meilleur résultat a été produit avec les mauvais paramètres.
Quelques habitudes à adopter :
- Validez avant de soumettre. Si le modèle ne prend pas en charge la résolution que vous passez, vous voulez un rejet clair au moment de la soumission, et non un échec déroutant au niveau de la tâche plusieurs minutes plus tard.
- Stockez les paramètres avec la tâche. Lorsque vous comparez plusieurs résultats, vous devez savoir quelle résolution et quels choix audio ont produit chacun.
- Ne supposez pas l'équivalence entre les images. Une tâche à deux images utilisant une grande image source peut se comporter différemment d'une tâche à une seule image ; testez les deux chemins.
Où placer tout cela dans le code
Regroupez les options de génération dans leur propre objet, pour rendre l'intention évidente et vous permettre de remplacer les valeurs par défaut en un seul endroit :
options = {
"resolution": "1080p", # confirm supported values in the model docs
"audio": True,
}
Ajoutez des commentaires aux lignes qui dépendent de valeurs documentées. Vous du futur — ou un collègue — devriez pouvoir distinguer immédiatement quels champs sont sûrs et lesquels doivent être vérifiés par rapport à la page de référence avant publication. En cas de doute, la documentation du modèle sur HiAPI est la source de vérité, et non un exemple de corps de requête.
Interroger l'état d'achèvement en Python
Le code d'interrogation est l'endroit où la plupart des intégrations deviennent discrètement fragiles. L'objectif est de construire un petit client réutilisable qui soumet une tâche et l'attend avec des limites raisonnables, plutôt qu'un script copié-collé et modifié à chaque fois.
Structure minimale du client
import os, time, requests
BASE = os.environ["HIAPI_BASE_URL"]
KEY = os.environ["HIAPI_API_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}
def submit(payload: dict) -> str:
r = requests.post(f"{BASE}/v1/video/generations",
headers=HEADERS, json=payload, timeout=30)
r.raise_for_status()
return r.json()["id"]
def wait(task_id: str, interval: float = 5.0, max_wait: float = 600.0) -> dict:
deadline = time.monotonic() + max_wait
while time.monotonic() < deadline:
r = requests.get(f"{BASE}/v1/video/generations/{task_id}",
headers=HEADERS, timeout=30)
r.raise_for_status()
job = r.json()
if job["status"] in ("succeeded", "failed"):
return job
time.sleep(interval)
raise TimeoutError(f"task {task_id} not finished in {max_wait}s")
Quatre détails de ce code portent l'essentiel du poids :
- Un délai d'expiration explicite sur chaque appel HTTP. Une requête suspendue est pire qu'une requête échouée.
- Un temps d'attente maximal. Une boucle sans borne transforme une tâche bloquée en service bloqué.
- La vérification des états terminaux. Ne vous arrêtez que lorsque le statut est réellement final ; traitez tout le reste comme encore en cours, y compris les statuts que vous ne connaissez pas.
- Le retour de l'objet de tâche complet. L'appelant a généralement besoin de l'URL de sortie et de tout détail d'erreur, pas seulement d'un booléen.
Rythme d'interrogation
Pour les tâches vidéo, cinq secondes est une valeur par défaut raisonnable. Interroger toutes les 200 ms consomme du quota sans aucun bénéfice, puisque le rendu prend de toute façon plusieurs minutes. Si vous soumettez de nombreuses tâches, placez la boucle d'interrogation dans un worker plutôt que dans le gestionnaire de requêtes, et recourez à un léger backoff pour les tâches de longue durée.
Assembler le tout
payload = {
"model": "kling-3.0-omni/image-to-video",
"input": {"image": first_frame_url, "prompt": prompt},
"options": options,
}
job = wait(submit(payload))
if job["status"] == "failed":
raise RuntimeError(job.get("error") or "generation failed")
print(job["output"]["url"])
Comme submit renvoie une simple chaîne et que wait renvoie un dict, vous pouvez tester chaque moitié indépendamment : simulez la réponse de soumission pour tester la logique d'interrogation, appelez submit seul pour vérifier le corps de requête contre l'API en direct.
Déboguer les défaillances courantes
Les défaillances se concentrent à trois niveaux, et identifier le niveau constitue l'essentiel du diagnostic.
Niveau 1 : rejet à la soumission
Ces rejets apparaissent en réponses 4xx avant que la moindre tâche existe. Causes courantes :
- Authentification — en-tête manquant, token bearer mal formé, clé non exportée dans l'environnement que vous croyez.
- Structure du corps de requête — champ mal orthographié, chaîne là où un tableau est attendu, options imbriquées au mauvais niveau.
- Valeurs non prises en charge — résolution ou combinaison audio que le modèle n'accepte pas.
- Problèmes de ressource — URL de fichier inaccessible, expirée ou qui n'est pas une image.
Lisez le corps de la réponse d'erreur. L'API indique généralement le champ problématique, et le correctif le plus rapide est souvent celui suggéré par le message. Reproduisez l'appel échoué dans curl pour confirmer que le problème vient du corps de requête et non du code client.
Niveau 2 : problèmes de transport
Le réseau se situe entre votre code et le cycle de vie de la tâche. Les dépassements de délai et les réinitialisations de connexion sur l'appel de soumission sont ambigus : la tâche a peut-être été créée, ou peut-être pas. Si vous réessayez aveuglément, vous risquez de produire des tâches en double.
Le modèle sûr consiste à ne réessayer que les opérations idempotentes et sûres, et à journaliser chaque tentative de soumission avec sa réponse. Si vous ne pouvez vraiment pas déterminer si la soumission a réussi, consultez l'historique des tâches avant de soumettre à nouveau. Côté interrogation, un échec de vérification de statut n'équivaut pas à un échec de tâche — capturez l'exception, attendez, redemandez.
Niveau 3 : échecs au niveau de la tâche
Ceux-ci arrivent avec un état terminal sur une tâche par ailleurs acceptée. Ils signifient généralement que le contenu ne peut pas être généré comme spécifié : les deux images sont trop différentes pour être interpolées, le prompt ne peut pas être concilié avec l'image source, ou une erreur interne se produit pendant le rendu.
Distinguez-les clairement dans le code, car les remèdes diffèrent. 4xx signifie corriger la requête. Une tâche échouée signifie changer les entrées ou réessayer — si le même corps de requête échoue deux fois, arrêtez de réessayer et changez quelque chose : simplifiez le prompt, choisissez des images plus proches, réduisez la résolution.
Liste de triage rapide
- Le statut HTTP est-il
4xx? Corrigez le corps de requête ou les identifiants ; n'interrogez pas. - La soumission a-t-elle réussi mais la tâche ne se termine jamais ? Votre limite d'attente est trop courte ou la tâche est bloquée — enregistrez l'ID de tâche et enquêtez, plutôt que de boucler indéfiniment.
- La tâche a-t-elle échoué ? Lisez les détails de l'erreur, puis ajustez les entrées, plutôt que de resoumettre à l'identique.
- Succès mais la vidéo est incorrecte ? C'est un problème de prompt et de choix d'images, pas un problème d'API.
Mise en production : liste de contrôle
Avant d'exposer cela aux utilisateurs, renforcez les parties qui échouent silencieusement.
Configuration. Conservez l'URL de base et la clé d'API dans des variables d'environnement ou un gestionnaire de secrets, jamais dans le code source. Si l'une des deux manque, échouez rapidement au démarrage, et non à la première requête utilisateur.
Délais d'expiration et nouvelles tentatives. Chaque appel sortant a besoin d'un délai d'expiration explicite. Ne réessayez la soumission que là où les doublons sont tolérables, et considérez les nouvelles tentatives d'interrogation comme sûres — lectures de statut idempotentes. Limitez le temps d'attente total et exposez un délai d'expiration clair à l'appelant.
L'ID de tâche est l'enregistrement. Persistez l'ID de tâche avec le corps de requête soumis : images, prompt, résolution, choix audio et horodatage. Quand quelqu'un demandera deux semaines plus tard pourquoi la vidéo semble incorrecte, cette ligne sera toute la réponse.
La sortie est temporaire. Considérez l'URL de vidéo renvoyée comme temporaire. Dès qu'une tâche réussit, téléchargez et stockez la vidéo dans votre propre stockage persistant, et enregistrez l'emplacement de stockage sur la tâche.
Conscience des coûts. La génération vidéo est facturée à la sortie générée, donc la résolution, la durée et le nombre de générations sont les leviers importants. Itérez à basse résolution, générez les versions finales de manière réfléchie, et journalisez les paramètres pour pouvoir attribuer les dépenses à un cas d'usage, plutôt que de les découvrir sur la facture.
Observabilité. Émettez des lignes de journal au moment de la soumission et au moment de l'état terminal, avec l'ID de tâche, la latence et le statut. Une simple métrique de taux de réussite par modèle vous indiquera quand un changement de prompt ou un ajustement d'options commence à faire échouer les tâches.
Validez par rapport à la documentation, pas par rapport aux exemples. Avant chaque publication impliquant l'audio, la résolution ou les entrées d'images, confirmez les noms de champs et les valeurs acceptées sur la page de référence du modèle, car ce sont les paramètres les plus susceptibles de dériver.
Avec le client, la boucle d'interrogation et ces garde-fous, kling-3.0-omni/image-to-video devient un composant prévisible, plutôt qu'un script dont vous priez qu'il fonctionne encore.
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