HiAPI
Blog

Tutoriel

Comment utiliser imagen4-ultra via l'API HiAPI : exemples curl et Python

Un exercice pratique complet de requête pour la génération d'images de haute qualité à partir de texte sur HiAPI

Oct 31, 2026
博客封面图:淡蓝底上多层半透明玻璃平面叠错排列,折射出克制的冷蓝色带。

Ce que imagen4-ultra sur HiAPI peut vous offrir

imagen4-ultra est le modèle de génération d'images de haute qualité à partir de texte de HiAPI : vous envoyez un prompt et recevez une image générée. Ce qui le rend vraiment pratique pour les développeurs, c'est qu'il fonctionne, comme tous les autres modèles de la plateforme, derrière l'interface unifiée de HiAPI. Ainsi, la méthode d'authentification, la structure des requêtes et le mode de traitement des tâches que vous apprenez ici sont directement réutilisables sur les autres endpoints.

Ce tutoriel est un exercice pratique exécutable, et non une simple énumération de paramètres. À la fin de votre lecture, vous disposerez de :

  • une requête curl directement copiable-collable pour soumettre une tâche de génération d'image à partir de texte,
  • un petit client Python réécrit à partir de la même requête,
  • une compréhension claire de l'impact du rapport hauteur/largeur et des autres options sur le résultat,
  • et d'une boucle de polling pour attendre la fin de la tâche et enregistrer l'image sur le disque.

Une mise au point préalable : la génération d'images n'est pas instantanée. imagen4-ultra fonctionne de manière asynchrone : vous soumettez une tâche, obtenez un identifiant de tâche, puis effectuez un polling jusqu'à ce que le rendu soit terminé. Si vous avez déjà utilisé d'autres endpoints asynchrones de HiAPI, ce flux vous sera familier ; sinon, la section sur le polling couvre l'intégralité du cycle de vie.

Nous resterons toujours dans le périmètre de l'API propre à HiAPI : pas de SDK spécifique à un fournisseur, pas de console tierce. Une URL de base, une clé, un format de requête.

Avant d'envoyer la première requête

Trois éléments sont nécessaires pour que le premier appel aboutisse.

1. Une clé API

Générez une clé depuis la console de votre compte HiAPI. Traitez-la comme un mot de passe : stockez-la dans une variable d'environnement plutôt que de la coller directement dans un fichier source.

export HIAPI_API_KEY="your-key-here"

2. L'URL de base

Toutes les requêtes HiAPI sont envoyées vers le même hôte API documenté dans la documentation de la plateforme. Centralisez-la à un seul endroit dans votre code, pour éviter de la coder en dur à plusieurs endroits :

export HIAPI_BASE_URL="https://api.hiapi.ai"

Si votre compte ou votre région utilise un autre hôte, utilisez la valeur indiquée dans la console : les chemins de requête ci-dessous restent inchangés.

3. Comment transmettre les informations d'authentification

HiAPI utilise un jeton bearer dans l'en-tête Authorization. Chaque requête — qu'il s'agisse de soumission ou de polling — porte les deux mêmes en-têtes :

Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json

C'est tout pour l'authentification. Pas d'étape de signature de requête, pas d'échange de jeton à chaque appel. Si vous savez définir des en-têtes, vous savez appeler cette API.

Avant de continuer, une vérification de base : assurez-vous que votre clé est exportée dans la même session shell que celle où vous exécuterez curl. Une proportion considérable des signalements de « 401 Unauthorized » se résume finalement à une clé exportée dans un onglet de terminal et utilisée dans un autre.

Dans ce qui suit, nous supposerons systématiquement que l'identifiant du modèle est imagen4-ultra. Si vous souhaitez vérifier la chaîne exacte exposée par votre compte, consultez la liste des modèles dans la documentation.

La requête curl exécutable

Voici une requête de soumission complète. Elle envoie le prompt, définit le rapport hauteur/largeur de sortie et demande la génération d'une seule image.

curl -sS -X POST "$HIAPI_BASE_URL/v1/images/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "imagen4-ultra",
    "prompt": "A lone lighthouse on a rocky coast at dusk, long exposure, dramatic clouds, cinematic lighting",
    "aspect_ratio": "16:9",
    "n": 1
  }'

Détail champ par champ du corps de la requête :

  • model — l'identifiant du modèle que vous appelez. Il détermine le routage de la requête ; sans lui, l'API ne peut pas savoir quel modèle exécuter.
  • prompt — la description en langage naturel de l'image. C'est le principal levier influençant la qualité du résultat. Soyez précis sur le sujet, l'éclairage, le style et la composition ; un prompt vague ne produira que des images vagues.
  • aspect_ratio — la forme du canevas de sortie, exprimée en largeur:hauteur. Nous détaillerons cela plus loin.
  • n — le nombre d'images à générer pour cette soumission. Gardez-le à 1 pendant les tests, afin que le coût de chaque exécution soit facile à calculer.

Selon la configuration de l'endpoint, la réponse contient soit l'image déjà terminée, soit — plus couramment pour ce type de modèle — un objet de tâche avec un identifiant et un champ de statut. Capturez cet identifiant ; la section sur le polling en dépend.

# 提交响应的典型结构
{
  "id": "job_abc123",
  "status": "queued"
}

Passez la réponse dans un formateur JSON (avec | jq . si disponible) pour pouvoir lire les noms de champs en fonction de la réponse de votre compte, plutôt que de plisser les yeux sur une seule ligne.

Écrire la même requête en Python

La version Python est une traduction ligne par ligne : même URL, mêmes en-têtes, même corps de requête. L'utilisation de requests rend la correspondance évidente :

import os
import requests

API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = os.environ.get("HIAPI_BASE_URL", "https://api.hiapi.ai")

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

payload = {
    "model": "imagen4-ultra",
    "prompt": "A lone lighthouse on a rocky coast at dusk, long exposure, dramatic clouds, cinematic lighting",
    "aspect_ratio": "16:9",
    "n": 1,
}

response = requests.post(
    f"{BASE_URL}/v1/images/generations",
    headers=headers,
    json=payload,
    timeout=30,
)
response.raise_for_status()
job = response.json()
print(job["id"], job["status"])

Lorsque vous intégrerez ce code dans un vrai service, plusieurs points méritent d'être conservés :

  • Lisez la clé depuis une variable d'environnement, jamais depuis une valeur littérale dans un fichier. L'écriture os.environ[...] échoue explicitement si la variable est absente, ce qui est précisément le comportement souhaité.
  • Définissez un timeout explicite pour l'appel de soumission. La tâche elle-même s'exécute de manière asynchrone, donc la requête HTTP doit revenir rapidement ; une limite de 30 secondes permet de détecter les problèmes réseau au lieu de laisser le programme se bloquer.
  • Appelez raise_for_status() avant de manipuler le JSON. Le corps d'une réponse 4xx n'a pas la structure attendue ; échouer tôt donne une trace plus claire qu'un KeyError levé trois lignes plus loin.
  • Réutilisez requests.Session si vous soumettez un grand nombre de tâches — le pool de connexions compte plus qu'il n'y paraît.

Si vous préférez httpx ou aiohttp, la conversion est mécanique : même dictionnaire d'en-têtes, même corps JSON, même chemin. La requête elle-même est indépendante de la bibliothèque HTTP.

Rapport hauteur/largeur et options de requête

Le rapport hauteur/largeur est l'option que vous ajusterez le plus souvent, car il modifie à la fois la composition et les dimensions de sortie utilisables pour la mise en page en aval.

Le rapport hauteur/largeur est transmis dans le corps de la requête sous forme de chaîne "largeur:hauteur" — "1:1", "16:9", "9:16", "4:3", "3:2", etc. Choisissez un ratio correspondant à l'usage final de l'image :

  • 1:1 — avatars, vignettes produit, posts sociaux recadrés en carré.
  • 16:9 / 9:16 — bannières principales, miniatures vidéo, emplacements au format story vertical.
  • 4:3 / 3:2 — compositions photographiques classiques, mises en page de galerie.

Définissez le ratio de manière réfléchie, plutôt que de générer un carré puis de recadrer. Le recadrage élimine des pixels que vous avez déjà payés pour générer, et peut couper le sujet hors du cadre. Si vous connaissez l'emplacement final, encodez-le dans la requête.

Outre le rapport hauteur/largeur, les options importantes au quotidien sont :

  • prompt — toujours l'entrée la plus influente. Itérez ici avant d'itérer ailleurs.
  • n — le nombre d'images générées par soumission. Utile lorsque vous voulez plusieurs variantes pour choisir ; gardez une valeur basse pendant la phase d'exploration du prompt.
  • model — l'identifiant exact de la variante du modèle. Si votre compte expose plusieurs modèles d'image, c'est le commutateur entre eux.

Tenez-vous-en aux paramètres documentés pour cet endpoint, sans deviner les noms. Les champs inconnus sont une cause fréquente de réponses 400, et une option mal orthographiée passe facilement inaperçue dans un corps de requête volumineux. En cas de doute, envoyez d'abord un corps minimal — model, prompt, aspect_ratio —, vérifiez qu'il fonctionne, puis ajoutez les options une par une.

Polling d'une tâche asynchrone et téléchargement du résultat

La génération d'images prend du temps, donc l'appel de soumission renvoie une tâche, pas une image. Le cycle de vie est : soumettre → poller le statut → télécharger la sortie.

Étape 1 : soumettre et capturer l'ID de tâche

Réutilisez la requête précédente et extrayez l'id de la réponse :

job = response.json()
job_id = job["id"]

Étape 2 : poller jusqu'à ce que la tâche atteigne un état terminal

Interrogez l'endpoint de statut avec les mêmes en-têtes d'authentification, en dormant entre chaque tentative. Augmentez progressivement l'intervalle pour ne pas surcharger l'API :

import time

def wait_for_job(job_id, headers, base_url, timeout=300):
    deadline = time.time() + timeout
    delay = 2
    while time.time() < deadline:
        r = requests.get(
            f"{base_url}/v1/images/generations/{job_id}",
            headers=headers,
            timeout=30,
        )
        r.raise_for_status()
        data = r.json()
        status = data["status"]
        if status == "succeeded":
            return data
        if status == "failed":
            raise RuntimeError(f"job failed: {data}")
        time.sleep(delay)
        delay = min(delay * 2, 15)
    raise TimeoutError(f"job {job_id} not finished within {timeout}s")

Détails essentiels : une échéance stricte, un plafond sur l'intervalle de backoff, et une branche explicite pour l'état d'échec, afin que les tâches problématiques se manifestent sous forme d'exception plutôt que de rester bloquées indéfiniment.

Étape 3 : télécharger l'image

La réponse d'une tâche terminée contient l'emplacement de la sortie — une URL ou une référence d'artefact équivalente. Récupérez-la et écrivez les octets sur le disque :

result = wait_for_job(job_id, headers, BASE_URL)
image_url = result["output"][0]["url"]

img = requests.get(image_url, timeout=60)
img.raise_for_status()
with open("lighthouse.png", "wb") as f:
    f.write(img.content)

Deux habitudes qui évitent la plupart des incidents en production : écrivez toujours en mode binaire ("wb"), jamais en mode texte ; et considérez l'URL de téléchargement comme temporaire — enregistrez immédiatement le fichier dans votre propre stockage, plutôt que de compter sur la validité indéfinie du lien.

Erreurs courantes et solutions

La plupart des échecs se classent en quelques catégories. Voici, pour chacune, la manifestation et la solution.

401 Unauthorized

Clé absente, mal formatée, ou invisible pour le processus qui effectue la requête.

  • Vérifiez que l'en-tête est exactement Authorization: Bearer <key> — le mot Bearer, un espace, puis la clé.
  • Confirmez que la variable d'environnement est définie dans le même shell ou processus. Dans les conteneurs et la CI, les variables exportées dans votre shell local ne suivent pas le code.
  • Si vous avez récemment fait tourner la clé, assurez-vous que l'ancienne n'est pas encore mise en cache quelque part.

400 Bad Request

Généralement un problème de corps de requête.

  • Nom de champ inconnu ou mal orthographié — tenez-vous aux paramètres documentés.
  • Valeur de aspect_ratio non acceptée par l'endpoint — utilisez le format largeur:hauteur de la documentation.
  • n hors de la plage autorisée.
  • JSON mal formé — par exemple une virgule superflue, ou des guillemets non échappés dans la chaîne du prompt. Si vous soupçonnez ce problème, formatez et inspectez le corps de la requête avant l'envoi.

404 renvoyé par l'étape de consultation du statut ou de téléchargement

L'ID de tâche est erroné, ou le chemin que vous interrogez ne correspond pas à l'endpoint utilisé pour la soumission. Lors de la première intégration, enregistrez intégralement la réponse de soumission et comparez l'ID caractère par caractère.

Timeout de polling

Si wait_for_job atteint l'échéance :

  • Vérifiez que vous contrôlez la bonne valeur de statut ; un état terminal que vous ne reconnaissez pas ressemblera à un blocage.
  • Pour les rendus volumineux et complexes, augmentez le timeout global plutôt que de raccourcir l'intervalle de polling.
  • Pendant l'intégration, journalisez chaque réponse de statut, afin de voir combien de temps les tâches prennent réellement avec votre combinaison de prompts.

Statut de tâche failed

Lisez le corps de réponse d'erreur renvoyé par l'API — il existe pour une raison. Les tâches échouées proviennent généralement du côté du prompt ou des paramètres ; la correction se fait dans la requête, pas dans le code de polling.

En cas de doute, la documentation HiAPI de ce modèle est la source de référence pour les noms de champs et les valeurs acceptables. Validez un changement à la fois et conservez une requête connue pour fonctionner comme référence pour la prochaine intégration.

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