Tutoriel
Comment utiliser kling-4.0/text-to-video via l'API HiAPI : curl, Python et un exemple de requête fonctionnel
Guide pratique pour les développeurs : prompts cinématographiques, audio synchronisé, interrogation asynchrone et téléchargement des sorties
Fonctionnalités et cas d'usage de kling-4.0/text-to-video
kling-4.0/text-to-video est un modèle de génération vidéo proposé via l'API unifiée HiAPI. Vous lui fournissez un prompt textuel et il renvoie un clip vidéo — le mouvement, les mouvements de caméra et la composition de la scène dépendent entièrement de votre description. Il s'agit d'un point de terminaison text-to-video : aucune image source à animer, donc le modèle dispose d'une liberté totale sur le cadrage et l'apparence du sujet.
Cas d'usage :
- Vous devez générer des clips cinématographiques courts à partir d'un script ou d'un modèle de prompt — b-roll, bandes-annonces, storyboards, vidéos pour réseaux sociaux.
- Vous souhaitez que l'audio synchronisé soit généré avec la vidéo, plutôt que d'obtenir un fichier muet à sonoriser en post-production.
- Vous construisez un pipeline où la génération vidéo n'est qu'une étape parmi d'autres (écriture du script, préparation des assets, publication), ce qui nécessite une API HTTP plutôt qu'une interface web.
En revanche, si vous avez besoin d'un contrôle précis image par image sur un sujet réel spécifique (les modèles image-to-video ou d'édition y excellent), ou si vous devez obtenir une réponse synchrone dans la requête utilisateur, ce modèle n'est pas adapté — la génération vidéo prend du temps, donc ce point de terminaison est asynchrone par conception.
Comme toutes les requêtes passent par HiAPI, les identifiants, le format requête/réponse et le cycle de vie des tâches sont identiques quel que soit le modèle utilisé sur la plateforme. Cette cohérence est la raison pratique de construire sur cette base : ajouter ou remplacer un modèle plus tard ne nécessite pas de réécrire la couche d'authentification ou d'interrogation.
Prérequis et authentification sur HiAPI
Avant d'envoyer votre première requête, assurez-vous de disposer de :
- Un compte HiAPI et une clé API de projet. Traitez-la comme un secret — ne la commitez jamais dans un dépôt, ne la placez jamais dans du code client.
- Le client HTTP de votre choix. Les exemples ci-dessous utilisent
curletrequestsde Python 3. - L'identifiant du modèle, exactement tel qu'il figure dans le catalogue :
kling-4.0/text-to-video. Une faute de frappe dans le nom du modèle est la cause la plus fréquente d'échec du premier appel.
Les identifiants sont envoyés sous forme d'en-tête HTTP dans chaque requête (y compris les requêtes d'interrogation). Le schéma habituel sur HiAPI est le jeton bearer :
export HIAPI_API_KEY="your-api-key-here"
Puis dans la requête :
Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json
Conservez l'URL de base et la clé dans des variables d'environnement ou un gestionnaire de secrets, plutôt qu'en dur dans le code. Pour le développement local, un fichier .env et une consultation via os.environ en Python suffisent. Pour un service déployé, injectez le secret à l'exécution.
Une habitude de configuration utile à prendre tôt : commencez par construire un petit appel de type « who am I » — toute requête d'authentification légère — pour confirmer que la clé et l'URL de base sont correctes avant de déboguer des tâches vidéo. Isoler l'authentification de la logique métier du modèle vous fera gagner du temps plus tard.
Une requête curl fonctionnelle
L'appel minimal crée une tâche et renvoie l'identifiant de la tâche. Voici la structure :
curl -X POST "$HIAPI_BASE_URL/video/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kling-4.0/text-to-video",
"prompt": "A slow aerial push over a rain-soaked Tokyo alley at night, neon signs reflecting in puddles, steam rising from vents, shallow depth of field, cinematic color grading",
"generate_audio": true
}'
Décryptage champ par champ du corps de la requête :
model— l'identifiant du modèle. Obligatoire.prompt— votre description de scène. C'est là que se concentre l'essentiel de votre budget qualité ; voir la section sur les prompts.generate_audio— demande la génération d'un audio synchronisé avec la vidéo. Si vous ne voulez que la piste visuelle, omettez-le ou mettez-le à false.
La réponse est un objet tâche, pas la vidéo terminée. Attendez-vous à un champ de statut et à un id que vous utiliserez pour l'interrogation — par exemple un statut queued ou processing, plus un id de tâche. Stockez cet id immédiatement ; si votre processus s'arrête, l'id est votre seul justificatif du travail en cours.
Deux conseils pratiques. Premièrement, lorsque le prompt s'allonge, enregistrez le JSON dans un fichier et utilisez -d @payload.json — la gestion des guillemets shell sur des prompts multilignes est une source fréquente d'erreurs. Deuxièmement, capturez séparément le corps de la réponse et le code de statut HTTP (curl -s -w "\n%{http_code}") pour distinguer une requête rejetée d'une panne réseau.
Convertir la requête en Python
La même requête en Python, structurée pour être intégrée directement dans un vrai script :
import os
import requests
BASE_URL = os.environ["HIAPI_BASE_URL"].rstrip("/")
API_KEY = os.environ["HIAPI_API_KEY"]
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
def create_video_job(prompt: str, generate_audio: bool = True) -> dict:
payload = {
"model": "kling-4.0/text-to-video",
"prompt": prompt,
"generate_audio": generate_audio,
}
resp = requests.post(
f"{BASE_URL}/video/generations",
headers=HEADERS,
json=payload,
timeout=30,
)
resp.raise_for_status()
return resp.json()
if __name__ == "__main__":
job = create_video_job(
"A slow aerial push over a rain-soaked Tokyo alley at night, "
"neon signs reflecting in puddles, steam rising from vents, "
"shallow depth of field, cinematic color grading"
)
print(job)
Pourquoi cette écriture :
requests.post(..., json=payload)gère à la fois la sérialisation et le type de contenu, évitant unjson.dumpsmanuel.raise_for_status()convertit les 4xx/5xx en exceptions capturables, au lieu de parser silencieusement un corps d'erreur comme une tâche.timeoutest indispensable. Sans lui, une connexion bloquée immobilise indéfiniment le worker.- La configuration réside dans des constantes de niveau module lues depuis l'environnement, ce qui rend la fonction testable et réutilisable.
Cette fonction ne fait que créer la tâche. Elle renvoie immédiatement le handle de tâche — exactement ce qu'il vous faut dans un handler web ou un worker de file d'attente. Les sections suivantes expliquent comment attendre le résultat.
Écrire des prompts cinématographiques qui tiennent la route
Les modèles text-to-video récompensent la structure. Un prompt qui précise le sujet, la caméra, le mouvement et l'ambiance l'emporte toujours sur une idée en une phrase, car chaque élément élimine une ambiguïté que le modèle aurait tranchée au hasard.
Un modèle utilisable :
[sujet et décor], [emplacement et mouvement de caméra],
[mouvement dans le cadre], [éclairage], [atmosphère ou étalonnage], [référence de style]
Exemple d'application :
À l'aube, un cycliste solitaire en imperméable jaune traverse un pont de pierre, caméra basse en travelling parallèle à hauteur de roue, brume flottant sur l'eau, lumière douce de l'heure bleue rehaussée de touches de lanternes chaudes, calme et légèrement mélancolique, rendu d'objectif anamorphique cinémascope.
Le rôle de chaque partie :
- Sujet et décor — des noms concrets valent mieux que des concepts abstraits. « Un cycliste solitaire en imperméable jaune » donne au modèle quelque chose à rendre ; « la liberté », non.
- Caméra — l'emplacement (
caméra basse,vue aérienne,à hauteur d'œil) et le mouvement (travelling,léger push-in,statique) sont les leviers les plus puissants sur la valeur perçue de la production. - Mouvement dans le cadre — brume qui flotte, tissu qui ondule, ondulations à la surface de l'eau. La vidéo a besoin de mouvement ; dites-le explicitement.
- Éclairage et atmosphère — heure, température de couleur, tonalité émotionnelle. Gardez-les cohérents entre eux.
- Style — le langage de l'objectif ou du format (
objectif anamorphique,faible profondeur de champ,étalonnage cinématographique) façonne la texture de manière plus fiable que de nommer un réalisateur.
Gardez les prompts comme des descriptions denses de quelques phrases, plutôt qu'un paragraphe d'idées concurrentes. Si un plan exige deux actions radicalement différentes, générez deux clips. Et itérez : ne changez qu'une variable à la fois — d'abord la caméra, puis l'éclairage — pour comprendre à quoi le modèle réagit au lieu de deviner.
Gérer les tâches asynchrones et l'interrogation
La génération vidéo n'est pas instantanée, donc le schéma est créer d'abord, interroger ensuite. Vous avez déjà la partie création ; voici la boucle :
import time
def wait_for_job(job_id: str, timeout: int = 600) -> dict:
deadline = time.monotonic() + timeout
delay = 2.0
while time.monotonic() < deadline:
resp = requests.get(
f"{BASE_URL}/video/generations/{job_id}",
headers=HEADERS,
timeout=30,
)
resp.raise_for_status()
job = resp.json()
status = job.get("status")
if status == "succeeded":
return job
if status in ("failed", "cancelled"):
raise RuntimeError(f"Job {job_id} ended with status {status}: {job}")
time.sleep(delay)
delay = min(delay * 1.5, 15.0) # back off, cap at 15s
raise TimeoutError(f"Job {job_id} did not finish in {timeout}s")
Des décisions de conception importantes en production :
Interroger avec backoff plutôt qu'en boucle serrée
Commencez par un intervalle court et augmentez progressivement — le backoff exponentiel ci-dessus plafonne à une limite fixe. Une interrogation rapide et continue épuise votre limite de débit sans bénéfice, car le temps de génération ne diminue pas parce que vous demandez plus tôt.
Toujours fixer une échéance
Chaque boucle d'interrogation a besoin d'un temps maximum en horloge murale et d'une erreur explicite en cas de dépassement. Sinon, une tâche bloquée immobilise silencieusement un worker pour toujours.
Traiter les états terminaux comme définitifs
Distinguez les états en cours (queued, processing) des états terminaux (succeeded, failed, cancelled). Ne renvoyez la sortie qu'en cas de succès ; les autres états doivent lever une exception ou basculer vers un chemin de reprise, plutôt que de continuer la boucle.
Découpler l'interrogation du handler de requête
Dans un serveur web, ne bloquez pas la réponse HTTP en attendant la vidéo. Créez la tâche, renvoyez l'id au client, et interrogez depuis un worker en arrière-plan ou un consommateur de file. Persistez l'id de tâche et son dernier statut connu pour ne pas perdre le suivi du travail en cours après un redémarrage.
Télécharger et vérifier la sortie
Quand une tâche atteint succeeded, la réponse contient une référence au média généré — généralement une URL vers le fichier terminé. Téléchargez rapidement et considérez cette URL comme temporaire : récupérez, stockez et enregistrez votre propre emplacement persistant, plutôt que de transmettre directement l'URL du fournisseur à l'utilisateur final.
import pathlib
def download_output(job: dict, dest: pathlib.Path) -> pathlib.Path:
url = job["output"]["video_url"]
with requests.get(url, stream=True, timeout=120) as r:
r.raise_for_status()
dest.parent.mkdir(parents=True, exist_ok=True)
with open(dest, "wb") as f:
for chunk in r.iter_content(chunk_size=1 << 20):
f.write(chunk)
return dest
Étapes de vérification qui valent la peine avant de remettre le fichier à quiconque :
- Vérifier que le transfert est complet. Streamer par blocs, comparer la taille écrite au
Content-Length(s'il existe), échouer bruyamment en cas de lecture insuffisante. - Confirmer la piste audio. Si vous avez demandé
generate_audio, le fichier doit avoir un flux audio. Une sonde rapide avecffprobeest la vérification la moins coûteuse :
ffprobe -v error -show_entries stream=codec_type -of csv=p=0 output.mp4
Vous devriez voir à la fois les lignes video et audio. Si l'audio manque, vérifiez que le flag était bien défini dans l'appel de création — impossible de l'ajouter après coup.
- Valider la durée et la résolution par rapport à vos attentes, afin de détecter avant publication un rendu tronqué ou aux spécifications erronées.
- Stocker avec une clé déterministe (id de tâche plus hash), écrire d'abord dans un chemin temporaire, renommer en cas de succès, et conserver l'id de tâche avec l'asset pour la traçabilité.
Si le téléchargement échoue en cours de transfert, réessayez avec backoff ; si l'URL a expiré, vous devrez récupérer l'enregistrement de la tâche pour obtenir une nouvelle référence.
Encapsuler le tout dans un client réutilisable
Les parties ci-dessus forment naturellement une classe. En les assemblant, vous obtenez quelque chose d'importable entre projets, sans duplication :
class KlingTextToVideo:
def __init__(self, base_url: str, api_key: str):
self.base_url = base_url.rstrip("/")
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
def generate(self, prompt: str, generate_audio: bool = True,
timeout: int = 600) -> dict:
job = create_video_job(prompt, generate_audio) # create half
return wait_for_job(job["id"], timeout=timeout) # poll half
Au fur et à mesure que le client mûrit, plusieurs choses à ajouter :
- Des logs structurés clés par id de tâche — transitions de statut, nombre d'interrogations, temps écoulé et échecs. Quand un rendu pose problème, l'id de tâche est votre clé de corrélation entre les logs.
- Des nouvelles tentatives bornées pour les erreurs transitoires uniquement (réseau, 5xx). Ne réessayez jamais aveuglément une requête rejetée ; un corps de requête malformé échouera toujours de la même façon et ne fera que gaspiller du quota.
- Implémentez l'idempotence à votre niveau. Si votre service peut soumettre deux fois le même prompt, dédupliquez avant l'appel de création, plutôt que de payer deux tâches.
- Gardez les modèles de prompts comme données, pas comme code. Placez les modèles cinématographiques dans des fichiers de configuration, pour itérer sur les prompts sans déploiement.
- Calculez les coûts en fonction des secondes de sortie. La facturation repose sur l'usage de sortie généré ; suivez donc la durée générée par tâche pour attribuer les dépenses à une fonctionnalité ou un utilisateur.
Une fois le client prêt, le pipeline est court : construire le prompt à partir du modèle, appeler generate, télécharger et sonder la sortie, puis remettre le fichier stocké à votre application. Si vous ajoutez plus tard d'autres modèles sur HiAPI, les mêmes en-têtes d'authentification, cycle de vie des tâches et schéma de téléchargement s'appliquent — c'est la principale raison de construire une couche d'abstraction une seule fois.
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