HiAPI
Blog

Tutoriel

Rédiger des prompts image-vers-vidéo multi-angles avec minimax-h3-max via l'API hiapi

Aucun paramètre d'angle de caméra — la méthode de rédaction de prompts ci-dessous transforme une photo en séquence multi-plans.

Sep 12, 2026
Rédiger des prompts image-vers-vidéo multi-angles avec minimax-h3-max via l'API hiapi

minimax-h3-max peut transformer une photo en vidéo de 5 à 15 secondes, mais son point de terminaison n'expose aucun paramètre « angle de caméra », « multi-vues » ou « nombre de plans » — la référence des paramètres liste comme champs d'entrée pris en charge prompt, first_frame_image, last_frame_image, duration, resolution et aspect_ratio. Écrivez les instructions de caméra dans prompt, champ qui accepte jusqu'à 7 000 caractères.

Ainsi, un clip « multi-angles » — passant d'un plan d'ensemble d'ouverture à un gros plan, puis à un plan en suivi — n'est pas un paramètre que vous définissez, mais un prompt que vous écrivez. Ce tutoriel couvre la structure de la requête, les schémas de prompt demandant plusieurs angles de caméra au sein d'un même clip généré, ainsi que le flux de production qui l'entoure.

Générer avec ce prompt → Choisissez 10 secondes et 768P. Pour l'image-vers-vidéo, ajoutez votre image de trame et omettez aspect_ratio.

Prérequis

Obtenez une clé API depuis votre console hiapi. Chaque appel ci-dessous s'authentifie sur le point de terminaison partagé de tâches asynchrones POST https://api.hiapi.ai/v1/tasks avec Authorization: Bearer YOUR_API_KEY.

Exemple minimal : une photo, trois angles de caméra

first_frame_image ancre le sujet et la scène, donnant au modèle un contenu concret vers lequel couper et revenir. Le prompt décrit chaque plan comme une coupe numérotée explicite. Ce prompt de moto est un exemple de code, sans rendu d'exemple joint.

Une moto vintage rouge garée sur une rue urbaine mouillée au crépuscule, des enseignes au néon se reflétant sur le trottoir. Plan 1 - grand angle en contre-plongée : la caméra maintient un plan large statique de la moto entière, une pluie fine tombe. Coupe vers le plan 2 - gros plan : la caméra avance serré sur le phare chromé et la roue avant, en suivant lentement vers la droite. Coupe vers le plan 3 - plongée verticale : la caméra regarde droit vers le bas la moto depuis au-dessus, en tournant lentement. Aucun texte ni sous-titre.

Générer avec ce prompt → Ajoutez votre propre image de moto accessible publiquement, choisissez 10 secondes et 768P, et omettez aspect_ratio.

import os
import requests
import time

API_KEY = os.environ["HIAPI_API_KEY"]
BASE = "https://api.hiapi.ai/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

payload = {
    "model": "minimax-h3-max",
    "input": {
        "prompt": (
            "A red vintage motorcycle parked on a wet city street at dusk, neon signs reflecting on the pavement. "
            "Shot 1 - low wide angle: the camera holds a static wide shot of the full motorcycle, rain lightly falling. "
            "Cut to Shot 2 - close-up: the camera pushes in tight on the chrome headlight and front wheel, tracking slowly right. "
            "Cut to Shot 3 - overhead top-down: the camera looks straight down at the motorcycle from above, slowly rotating. "
            "No text or subtitles."
        ),
        "first_frame_image": "https://your-cdn.example.com/motorcycle-source.jpg",
        "duration": 10,
        "resolution": "768P",
    },
}

# Frame images and aspect_ratio are mutually exclusive.
def response_data(response):
    response.raise_for_status()
    body = response.json()
    if not isinstance(body, dict) or body.get("code") != 200:
        raise ValueError("Expected a JSON object with code=200")
    data = body.get("data")
    if not isinstance(data, dict):
        raise ValueError("Expected data to be an object")
    return data

# Submit once. An uncertain POST response is not a reason to submit again.
try:
    resp = requests.post(
        f"{BASE}/tasks", headers=HEADERS, json=payload, timeout=(10, 60)
    )
    created = response_data(resp)
    task_id = created.get("taskId")
    if not isinstance(task_id, str) or not task_id.strip():
        raise ValueError("Missing data.taskId")
except (requests.RequestException, ValueError) as exc:
    raise RuntimeError(
        "Could not confirm task creation. Check task records before resubmitting."
    ) from exc

print("taskId:", task_id, flush=True)
deadline = time.monotonic() + 600
while time.monotonic() < deadline:
    try:
        resp = requests.get(
            f"{BASE}/tasks/{task_id}", headers=HEADERS, timeout=(10, 60)
        )
        task = response_data(resp)
    except (requests.RequestException, ValueError) as exc:
        raise RuntimeError(
            f"Query failed; retain taskId={task_id} and resume GET for this ID."
        ) from exc

    state = task.get("status")
    if state == "fail":
        raise RuntimeError(f"Task {task_id} failed: {task.get('error')}")
    if state == "success":
        outputs = task.get("output")
        if not isinstance(outputs, list):
            raise RuntimeError(f"Task {task_id}: missing output array")
        video = next(
            (item for item in outputs
             if isinstance(item, dict) and item.get("type") == "video"
             and isinstance(item.get("url"), str) and item["url"]),
            None,
        )
        if video is None:
            raise RuntimeError(f"Task {task_id}: no video URL in output")
        print(video["url"])
        print("expireAt (Unix seconds):", video.get("expireAt"))
        break
    if state not in {"queued", "handling", "archiving"}:
        raise RuntimeError(f"Task {task_id}: unexpected status {state!r}")
    time.sleep(min(3, max(0, deadline - time.monotonic())))
else:
    raise TimeoutError(f"Polling timed out; continue GET with taskId={task_id}")

Remplacez first_frame_image par une URL d'image HTTPS réelle et accessible publiquement, ou supprimez-la entièrement pour générer la même séquence multi-angles à partir du seul texte — minimax-h3-max gère à la fois le texte-vers-vidéo et l'image-vers-vidéo via le même champ prompt.

Rédiger le prompt : le schéma des plans numérotés

Trois choix rendent votre séquence de plans cible claire et explicite :

  1. Une phrase d'établissement de scène, puis des plans numérotés. Décrivez le sujet et la scène une seule fois, puis listez chaque angle de caméra comme un temps annoté distinct : Plan 1 - [cadrage] : [action]. Coupe vers le plan 2 - [cadrage] : [action]. « Coupe vers le plan N » demande explicitement un changement d'angle de caméra.
  2. Employez le vocabulaire cinématographique standard. grand angle en contre-plongée, plan en plongée verticale, gros plan, travelling avant lent, plan en suivi latéral, caméra à l'épaule — ces termes indiquent le cadrage et le mouvement voulus. Des formulations vagues comme « un autre angle sympa » produisent des résultats incohérents.
  3. Planifiez le nombre de plans selon la durée. duration est un entier de 5 à 15 secondes. Deux à trois plans sont réalistes ; caser cinq angles différents dans un clip de 5 secondes donne moins d'une seconde par plan, ce qui ressemble souvent à un bug plutôt qu'à une coupe.

first_frame_image et last_frame_image sont tous deux facultatifs et indépendants l'un de l'autre — vous pouvez en définir un, les deux, ou aucun. Si vous en fournissez un, omettez aspect_ratio : ces champs sont mutuellement exclusifs et l'image de trame détermine le rapport d'aspect de la sortie. Notez aussi que l'exactitude tridimensionnelle ou géométrique n'est pas garantie d'un angle à l'autre — c'est un modèle de vidéo génératif, pas une chaîne de photogrammétrie ; attendez-vous donc, même avec une première trame ancrée, à une légère dérive des détails du sujet entre les coupes.

Le rendre prêt pour la production

  • Au-delà de l'échelle du script, privilégiez le callback au polling. Ajoutez "callback": {"url": "https://your-domain.com/hiapi/callback", "when": "final"} dans le corps de la requête ; hiapi enverra un POST de notification lorsque la tâche atteint un état final, au lieu que vous interrogiez GET /v1/tasks/{taskId} en boucle.
  • Dédupliquez par taskId. Les réponses de polling et les callbacks sont tous deux indexés par le même taskId — traitez les notifications d'état final répétées pour un même ID comme idempotentes, et non comme plusieurs tâches distinctes.
  • Téléchargez immédiatement les sorties. Une tâche réussie renvoie data.output[].url pour un stockage temporaire. Choisissez l'élément de sortie dont le type vaut video et vérifiez son horodatage Unix expireAt (en secondes). Dans le même gestionnaire qui traite l'état final, réhébergez-le sur votre propre stockage.
  • Gérez les deux formes d'échec. Un corps de requête incorrect (champ non pris en charge, duration hors plage, URL d'image malformée) échoue rapidement à la soumission avec 400 INVALID_REQUEST. Un problème d'authentification renvoie 401 avec error.code: "permission_denied". Une tâche qui échoue pendant la génération signale "status": "fail" dans la réponse de polling/callback — vérifiez status avant de faire confiance à output.

Pour aller plus loin

FAQ

minimax-h3-max dispose-t-il d'un paramètre dédié multi-angles ou multi-caméras ? Non. Les champs d'entrée documentés sont prompt, first_frame_image, last_frame_image, duration, resolution et aspect_ratio. Décrivez plusieurs plans dans prompt plutôt que d'ajouter un champ d'angle de caméra.

Peut-on définir aspect_ratio avec first_frame_image ou last_frame_image ? Non. aspect_ratio est mutuellement exclusif avec tout champ d'image de trame. L'image fournie détermine le rapport de sortie. Dès que vous passez une image de trame, omettez aspect_ratio.

Quelle peut être la durée d'un clip multi-angles ? duration accepte un entier de 5 à 15 secondes. Deux à trois angles de caméra différents tiennent confortablement dans cette fenêtre ; au-delà, chaque plan se retrouve souvent compressé à une fraction de seconde.

Le sujet reste-t-il parfaitement cohérent d'un angle à l'autre ? Ce n'est pas garanti. minimax-h3-max est un modèle de vidéo génératif, donc même si first_frame_image ancre la trame d'ouverture, les détails (textures précises, proportions subtiles) peuvent dériver entre les coupes. Considérez cela comme une forte cohérence créative, et non comme une reconstruction multi-vues exacte au pixel près.

Peut-on générer un clip multi-angles à partir du seul texte, sans image source ? Oui — omettez first_frame_image et last_frame_image et décrivez la scène et les plans dans le prompt. La génération purement textuelle utilise le canevas horizontal par défaut. Pour un cadrage vertical, fournissez une image de trame verticale sans définir aspect_ratio, ou recadrez/complétez la vidéo enregistrée dans l'éditeur.

À quoi ressemble un échec d'authentification ? HTTP 401, avec un corps de réponse semblable à {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"..."}}. Vérifiez soigneusement l'en-tête Authorization: Bearer et si la clé a été révoquée depuis la console.

Copiez la séquence de plans de la moto et générez avec ce prompt → Choisissez 10 secondes et 768P ; ajoutez votre image de trame pour guider la composition d'ouverture.

Articles similaires

Voir tous les articles →

Commencez avec des artefacts IA persistants

Obtenez votre clé API et appelez des modèles d'image, de vidéo et d'audio via une API unique basée sur les tasks.

Lire la documentation de l'API