HiAPI
Blog

Tutoriel

Comment appeler gpt-image-2/text-to-image@ext via l'API HiAPI : curl et Python

Un exercice pratique de requêtes pour les développeurs qui intègrent la génération d'images à partir de texte

Oct 31, 2026
黑绿底上,黄铜色与深绿色扁平缎带以经纬交织方式构成开放式网格,这是教程文章的封面图。

Ce que gpt-image-2/text-to-image@ext vous apporte

gpt-image-2/text-to-image@ext est un modèle de génération d'images à partir de texte exposé via l'interface unifiée de HiAPI. Il vous suffit d'envoyer un prompt et des paramètres de génération facultatifs au même point de terminaison pour obtenir les données de l'image générée. Aucun composant spécifique au modèle à installer, aucun SDK propre à chaque fournisseur à intégrer, aucun compte distinct à gérer : la même clé API et la même structure de requête couvrent le reste des capacités de la plateforme.

Choisissez ce modèle lorsque votre produit doit transformer une description textuelle en une image inédite : transformer un texte marketing en visuel principal, convertir un prompt utilisateur en vignette, ou alimenter un outil de design qui rend des concept arts à la demande. Comme l'appel n'est qu'une simple requête HTTP, il s'intègre facilement dans un service backend, un worker de file d'attente ou un script, sans aucune bibliothèque cliente.

Il est le bon choix lorsque l'entrée est du texte et que la sortie est une image bitmap que vous comptez stocker et distribuer vous-même. Si vous devez plus tard basculer vers un autre modèle d'image sur la plateforme, la logique d'intégration — authentification, enveloppe de requête, traitement de la sortie — reste inchangée ; il suffit de modifier l'identifiant du modèle et le bloc de paramètres.

Comment lire ce guide

Cet exercice se déroule par couches. D'abord une requête minimale qui renvoie une image, puis la version Python, ensuite la décision structurelle entre appel unique et interrogation asynchrone, et enfin le traitement de la sortie. Chaque couche est testable indépendamment, ce qui vous permet, en cas de problème, de savoir précisément quelle modification l'a introduit.

Prérequis et authentification

Avant d'envoyer votre première requête, il vous faut deux choses : un compte HiAPI et une clé API qui y est associée. Créez la clé dans le tableau de bord de votre compte et stockez-la comme n'importe quel secret — variable d'environnement en local, gestionnaire de secrets en production. Ne la commitez pas dans un dépôt de code et ne la collez pas dans du code client susceptible d'être envoyé au navigateur.

L'authentification se fait via un jeton bearer dans l'en-tête de la requête. Le format est toujours le même :

Authorization: Bearer $HIAPI_API_KEY

Définissez cette variable une fois dans votre shell ; les exemples ci-dessous pourront y faire référence sans réafficher la clé :

export HIAPI_API_KEY="your-key-here"

Points à vérifier avant de commencer

  • La clé est active et dispose des droits d'accès à la génération d'images.
  • Votre environnement peut émettre des requêtes HTTPS sortantes vers le point de terminaison HiAPI.
  • Vous savez où les fichiers générés seront écrits — un répertoire local pour les tests, un stockage objet en production.

Si la clé est absente ou mal formée, le problème se manifeste dès le premier appel sous forme d'erreur d'authentification : c'est le moment le plus précoce et le plus clair pour le détecter.

Une requête curl minimale fonctionnelle

Commencez par la plus petite requête capable de produire une image. Tout sauf le prompt est facultatif, et garder le premier appel minimal signifie que toute erreur est presque certainement liée à l'authentification ou à la structure de la requête, et non à un conflit de paramètres.

curl -sS -X POST "$HIAPI_BASE_URL/v1/images/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2/text-to-image@ext",
    "prompt": "一枚斑驳的黄铜指南针放在折叠的纸质地图上,柔和的窗光,浅景深",
    "size": "1024x1024",
    "n": 1
  }'

Explication champ par champ

  • model — l'identifiant du modèle. C'est la seule valeur qui rattache la requête à gpt-image-2/text-to-image@ext ; elle doit être exacte.
  • prompt — la description du contenu. Soyez précis sur le sujet, le style et l'éclairage ; un prompt vague produit une image vague, plus difficile à déboguer qu'une erreur de paramètre.
  • size — les dimensions de sortie. Peut être omis lors de la phase de validation du pipeline, la valeur par défaut étant acceptée.
  • n — le nombre d'images générées par appel. Gardez-le à 1 pendant l'intégration pour qu'un échec corresponde exactement à une sortie.

Écrivez la réponse dans un fichier, afin de pouvoir l'inspecter sans que le terminal ne saccage les données binaires :

curl -sS -X POST "$HIAPI_BASE_URL/v1/images/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @payload.json -o response.json

Dès qu'elle renvoie une image, vous disposez d'une base de référence connue comme fonctionnelle. Chaque modification ultérieure doit être une édition unique et réversible par rapport à elle.

Porter la requête en Python

La version Python est la même requête, seul le moyen de transport diffère. Utilisez requests — c'est le choix le moins susceptible de surprendre, et il correspond un à un aux champs curl que vous avez déjà validés.

import os
import requests

API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = os.environ["HIAPI_BASE_URL"]

payload = {
    "model": "gpt-image-2/text-to-image@ext",
    "prompt": "一枚斑驳的黄铜指南针放在折叠的纸质地图上,柔和的窗光",
    "size": "1024x1024",
    "n": 1,
}

response = requests.post(
    f"{BASE_URL}/v1/images/generations",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    },
    json=payload,
    timeout=120,
)

response.raise_for_status()
data = response.json()

Lecture des points clés

  • json=payload définit le type de contenu et sérialise le corps de la requête en une seule étape — pas de concaténation de chaînes à la main, pas de bug d'échappement.
  • En pratique, timeout n'est pas facultatif. La génération d'images est plus lente qu'un appel d'API JSON typique ; sans timeout, un worker se bloque dès que l'amont ralentit.
  • raise_for_status() convertit un échec HTTP en exception que vous pouvez intercepter et catégoriser, au lieu de laisser un corps de réponse malformé se propager en aval.

Conservez le payload sous forme de dict plutôt que de chaîne en ligne. Lorsque vous ajouterez des paramètres plus tard, il suffira d'ajouter des clés — la structure de la requête ne change pas, et vous n'aurez jamais à redéboguer la couche de transport.

Si vous préférez un client de style SDK, le même point de terminaison et les mêmes en-têtes s'appliquent toujours ; seule la syntaxe d'appel diffère. Validez d'abord avec curl, puis adoptez le client que votre application a standardisé.

Choisir entre appel unique et interrogation asynchrone

Il s'agit d'une décision de conception, non de syntaxe, et elle influence la logique de nouvelle tentative et de stockage plus que tout autre choix dans l'intégration.

Appel unique

Utilisez un cycle requête-réponse unique dans les cas suivants :

  • Vous générez à la demande et un utilisateur attend.
  • Votre couche HTTP tolère les connexions longues.
  • Vous générez une image à la fois plutôt qu'en lot.

Réglez le timeout avec une marge confortable par rapport au temps de génération le plus lent que vous avez observé, et traitez le timeout comme un échec réessayable, non comme une erreur fatale.

Interrogation asynchrone

Choisissez l'asynchrone pour le traitement par lots, lorsque la requête provient d'un worker de file d'attente, ou lorsque l'appelant ne doit pas se bloquer. Le schéma est : soumettre, obtenir un handle, puis interroger l'état d'achèvement.

import time

def poll_until_done(fetch_status, handle, interval=2, max_wait=300):
    deadline = time.monotonic() + max_wait
    while time.monotonic() < deadline:
        status = fetch_status(handle)
        if status["state"] == "succeeded":
            return status
        if status["state"] == "failed":
            raise RuntimeError(status.get("error", "generation failed"))
        time.sleep(interval)
    raise TimeoutError("generation did not finish in time")

Règles pour une boucle d'interrogation fiable

  • Backoff. Commencez par un intervalle court et augmentez progressivement ; une interrogation constante et rapprochée gaspille le quota et le budget de débit.
  • Limitez l'attente. Une échéance max_wait empêche les tâches orphelines d'occuper indéfiniment un worker.
  • Persistez le handle. Si le worker redémarre, vous devez pouvoir reprendre l'interrogation, plutôt que de resoumettre et payer une génération en double.
  • Traitez l'échec comme un état terminal par tâche. L'état failed doit être journalisé, non réessayé silencieusement en boucle serrée.

Décidez-le tôt. Adapter après coup la sémantique asynchrone à un chemin de code synchrone signifie réécrire à la fois l'appelant, le stockage et la gestion des erreurs.

Traiter la sortie image

La réponse contient l'image générée, mais sous forme de données à l'intérieur d'une enveloppe JSON — pas d'URL directement chaînable. Traitez-la comme une sortie binaire que vous possédez.

Décoder et persister

import base64

item = data["data"][0]
image_bytes = base64.b64decode(item["b64_json"])

with open("out.png", "wb") as f:
    f.write(image_bytes)

Si la réponse contient une URL plutôt que des données en ligne, récupérez-la immédiatement et écrivez les octets dans votre propre stockage. Les URL générées sont temporaires ; tout ce que vous exposez à vos utilisateurs doit se trouver derrière votre propre infrastructure.

Vérifiez avant de distribuer

  • Vérifiez la signature magique. Un PNG commence par \x89PNG ; une page d'erreur HTML non. Quelques octets de vérification suffisent à capturer les problèmes de proxy qui renvoient un HTTP 200 avec un corps de réponse erroné.
  • Enregistrez la taille. Consignez la longueur en octets pour que les téléchargements tronqués apparaissent dans la supervision.
  • Stockage déterministe. Nommez les fichiers d'après l'identifiant de génération plutôt que le texte du prompt, et conservez le prompt, les paramètres et les métadonnées de réponse avec l'image. Cette combinaison vous permet de reproduire ou d'auditer n'importe quelle sortie plus tard.
  • Définissez correctement le type de contenu — déduit du fichier réel, et non d'une supposition.

Conserver les métadonnées avec l'artefact

Rédigez un petit enregistrement d'accompagnement : identifiant du modèle, prompt complet, dimensions et nombre, horodatage, ainsi que tout identifiant de requête présent dans la réponse. Six mois plus tard, quand quelqu'un demandera pourquoi cette image ressemble à cela, cet enregistrement sera votre seule réponse.

Déboguer les pannes courantes

La plupart des échecs d'une première intégration se rangent en trois catégories. Vérifiez-les dans cet ordre — le coût du diagnostic va globalement du plus faible au plus élevé.

Erreurs d'authentification

401 ou 403 signifie que la clé est erronée, révoquée ou non envoyée. Réaffichez la construction de l'en-tête sans la clé, confirmez que le préfixe Bearer et l'espace sont intacts, et assurez-vous que la variable d'environnement est bien renseignée dans le processus qui émet la requête — le piège classique étant de la définir dans le shell mais pas dans le worker ou le conteneur.

Corps de requête malformé

400 pointe généralement vers le corps de la requête. Revenez à la requête minimale de la partie curl, puis rajoutez les champs un par un. Coupables habituels :

  • La chaîne model ne correspond pas exactement à gpt-image-2/text-to-image@ext.
  • Le corps n'est pas du JSON valide — virgule superflue ou guillemet non échappé.
  • Type de paramètre incorrect ; n est un nombre, pas une chaîne.
  • En-tête Content-Type: application/json absent, le serveur ne peut pas analyser le corps.

Timeouts et réponses lentes

Si la connexion se coupe avant le retour de l'image, vous avez probablement dépassé le timeout client plutôt que rencontré une panne du modèle. Pour une conception à appel unique, augmentez le timeout ; pour toute forme de traitement par lots, passez à l'interrogation asynchrone. Lors d'une nouvelle tentative, assurez-vous de ne pas dupliquer la génération : si une requête a pu réussir, vérifiez qu'un résultat n'existe pas déjà avant de la resoumettre.

Quand rien de tout cela ne s'applique

Capturez la réponse complète de la requête échouée — code d'état, en-têtes et corps — et reproduisez avec une commande curl minimale. Une panne qui persiste avec la requête minimale est un problème d'intégration lié à votre environnement ; une panne qui disparaît pointe vers les paramètres que vous avez ajoutés.

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