HiAPI
Blog

Tutoriel

Comment appeler gpt-image-2/image-to-image sur HiAPI : curl, Python et une requête qui fonctionne

Requêtes image-to-image pour développeurs : soumettre une image de référence, interroger la tâche et télécharger le résultat

Oct 31, 2026
扁平流体形态交叠的封面图,墨黑底色上浮现青瓷绿与石板灰的克制波纹,呼应教程文章。

Ce qu'attend le point de terminaison image-to-image

Le modèle gpt-image-2/image-to-image sur HiAPI est un point de terminaison de génération d'images asynchrone. Contrairement à un appel synchrone qui bloque en attendant l'image, ce point de terminaison reçoit votre requête, la met en file d'attente et renvoie un handle de tâche. Vous devez ensuite suivre cette tâche jusqu'à son achèvement.

Au niveau de la requête, vous devez fournir trois choses :

  • L'id du modèle : gpt-image-2/image-to-image.
  • Une image de référence : l'image source à partir de laquelle le modèle doit transformer ou construire le résultat. C'est l'entrée décisive du mode image-to-image — sans elle, vous faites du texte-vers-image.
  • Le prompt et les options : une instruction textuelle décrivant la sortie attendue, ainsi que les champs optionnels listés dans la documentation du modèle (par exemple la taille ou le format de sortie). N'envoyez que les paramètres listés dans la documentation du modèle.

La réponse n'est pas l'image elle-même, mais un objet de tâche contenant un identifiant et un statut. Considérez ce statut comme la seule source de vérité : pending ou processing signifie qu'il faut continuer d'attendre, succeeded que le résultat est prêt, failed qu'un problème est survenu et qu'il faut arrêter l'interrogation.

Concevez votre client autour de ce cycle de vie dès le départ. Tout le reste de ce tutoriel — curl, Python, interrogation, téléchargement — repose sur le fait que « soumettre » et « terminer » sont deux moments distincts.

Préparez votre clé HiAPI et votre image de référence

Avant d'écrire la moindre ligne de code, préparez deux choses.

Une clé API. Créez-en une dans la console HiAPI et stockez-la dans une variable d'environnement, plutôt que de la coller directement dans le script :

export HIAPI_API_KEY="your-key-here"

Traitez la clé comme un secret. Ne la committez pas dans le dépôt et ne la consignez pas dans les logs de requêtes.

Une image de référence. Choisissez un fichier image local que vous souhaitez transformer. Gardez une taille raisonnable — une image source trop grande et à haute résolution est la cause la plus fréquente de requêtes lentes ou rejetées. Placez un PNG ou JPEG dans le répertoire du script, c'est le plus simple pour le premier essai :

ls -lh ./reference.png

Notez le chemin du fichier ; vous le référencerez dans les exemples curl et Python. Si vous prévoyez d'appeler le modèle depuis un serveur, vérifiez que le processus a le droit de lire ce chemin et que le fichier est bien une image valide (pas un fichier renommé avec une mauvaise extension).

La clé exportée et l'image sur le disque : tout ce qu'il faut pour la première requête est en place.

Une requête curl qui fonctionne

Le moyen le plus rapide de vérifier vos identifiants et la structure du corps de requête est un appel curl. Il soumet la tâche et affiche l'objet de tâche :

curl -sS https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2/image-to-image",
    "input": {
      "image": "https://example.com/reference.png",
      "prompt": "Turn this photo into a watercolor illustration"
    }
  }'

Deux remarques sur cet exemple. Premièrement, l'image de référence est transmise sous forme d'URL via le champ input.image ; si la documentation du point de terminaison prend en charge le base64 intégré ou l'upload multipart pour votre cas, utilisez cette forme, mais gardez le même nom de champ. Deuxièmement, le prompt est l'endroit où vous décrivez la transformation — soyez précis sur le style, la composition et ce qui doit rester inchangé.

Exécutez-la et lisez la réponse. Une soumission réussie renvoie un id de tâche et un statut non terminal. Si vous recevez 401, votre clé est absente ou erronée. Si vous recevez 422 ou une erreur de validation similaire, vérifiez le corps de requête — souvent, l'id du modèle ou le format du champ image est incorrect.

Conservez l'id de la tâche. Les étapes suivantes en dépendent.

La même chose en Python

La version Python doit correspondre exactement à l'appel curl, en conservant explicitement l'authentification et la construction du corps de requête, pour que rien ne soit masqué par une couche d'abstraction. Utilisez requests :

import os
import requests

API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = "https://api.hiapi.ai/v1"

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

payload = {
    "model": "gpt-image-2/image-to-image",
    "input": {
        "image": "https://example.com/reference.png",
        "prompt": "Turn this photo into a watercolor illustration",
    },
}

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

Si votre intégration envoie un fichier local plutôt qu'une URL, encodez et joignez l'image conformément à la documentation du point de terminaison, plutôt que d'inventer un champ. La discipline est la même qu'avec curl : construisez le corps de requête sous forme de dictionnaire simple, envoyez, vérifiez le statut HTTP avant d'analyser la réponse.

Encapsulez la logique de soumission dans une fonction qui renvoie l'id de tâche. Ainsi, le code d'interrogation de la section suivante sera indépendant de la façon dont la tâche a été créée.

Interrogez la tâche asynchrone jusqu'à son achèvement

L'appel de soumission renvoie déjà une réponse alors que l'image est encore en cours de génération. Pour obtenir le résultat, interrogez le point de terminaison de statut de la tâche jusqu'à ce qu'elle atteigne un état terminal. Une boucle robuste a trois caractéristiques : un délai entre les interrogations, un temps d'attente maximal et une gestion explicite des états d'échec.

import time

def wait_for_task(task_id, headers, base_url, timeout=300, interval=3):
    deadline = time.time() + timeout
    while time.time() < deadline:
        r = requests.get(f"{base_url}/tasks/{task_id}", headers=headers, timeout=30)
        r.raise_for_status()
        task = r.json()
        status = task["status"]
        if status == "succeeded":
            return task
        if status == "failed":
            raise RuntimeError(f"Task failed: {task}")
        time.sleep(interval)
    raise TimeoutError(f"Task {task_id} did not finish within {timeout}s")

Quelques améliorations pratiques :

  • Backoff : commencez par un intervalle court et augmentez-le progressivement, ou gardez un intervalle fixe suffisamment large pour ne pas marteler l'API. La génération d'images n'est pas instantanée.
  • Timeout : fixez toujours une limite au temps d'attente total. Sinon, une tâche bloquée suspendra indéfiniment votre worker.
  • États terminaux : ne considérez comme terminaux que succeeded et failed. Tout autre état signifie qu'il faut continuer d'interroger. Si l'API ajoute un jour des états intermédiaires, votre boucle continuera de fonctionner correctement.

Si vous exécutez un grand nombre de tâches, interrogez dans un worker en arrière-plan ou une file d'attente, plutôt que de bloquer une requête web. Le cycle de vie est identique, seul le modèle de concurrence change.

Téléchargez et vérifiez le résultat

Une fois la tâche signalée comme réussie, l'objet de tâche contient l'emplacement de l'image générée — généralement une URL dans un champ de sortie. Téléchargez-la et écrivez-la sur le disque :

task = wait_for_task(task_id, headers, BASE_URL)
image_url = task["output"]["image"]

img = requests.get(image_url, timeout=60)
img.raise_for_status()

with open("result.png", "wb") as f:
    f.write(img.content)

Si l'URL signée a une durée de validité, téléchargez immédiatement après la fin ou persistez directement le fichier, plutôt que de stocker l'URL pour un usage ultérieur. Si votre point de terminaison renvoie du base64 plutôt qu'une URL, décodez-le avant de l'écrire.

Une vérification rapide d'intégrité évite des défaillances en aval déroutantes :

from PIL import Image

with Image.open("result.png") as im:
    im.verify()
print("valid image, bytes:", os.path.getsize("result.png"))

Si le fichier n'est pas une image décodable, verify() lèvera une exception, ce qui permet de détecter les téléchargements tronqués et les pages d'erreur enregistrées comme image. Vérifier la taille en octets vous indique aussi si la réponse est plausible. Ici, la boucle est bouclée : soumettre, interroger, télécharger, vérifier.

Diagnostiquez les pannes courantes

La plupart des premières intégrations échouent de quelques manières prévisibles. Diagnostiquez dans l'ordre suivant.

Erreurs d'authentification (401/403). Clé absente, mal formée ou manquant de permissions. Vérifiez que la variable d'environnement est bien exportée dans le shell ou le processus qui exécute la requête, et que l'en-tête Authorization utilise exactement le préfixe attendu par l'API.

Image de référence invalide ou trop volumineuse (400/422). L'URL de l'image est peut-être inaccessible depuis le côté API, le fichier peut être corrompu, ou les dimensions et le poids dépassent les limites. Testez d'abord avec un petit PNG confirmé. Si vous passez une URL, assurez-vous qu'elle est accessible publiquement ; si vous passez des données inline, vérifiez que l'encodage est correct.

Timeout d'interrogation. Si la tâche atteint systématiquement votre timeout, augmentez la limite, allongez l'intervalle, ou vérifiez si la tâche n'a pas en réalité échoué sans que vous affichiez la raison. Consignez le dernier objet de tâche avant de lever l'exception, pour pouvoir inspecter le statut.

Limitation de débit (429). Faites un backoff avec jitter avant de réessayer, plutôt que de réessayer immédiatement. Si vous soumettez massivement en parallèle, limitez la concurrence pour éviter que des pics de trafic déclenchent la limitation, et rendez les tentatives idempotentes en consignant l'id de tâche.

Pour toute catégorie d'erreur, consignez le statut HTTP, un corps de réponse tronqué et l'id de tâche — ces trois éléments suffisent généralement pour déterminer si le problème vient de l'authentification, du corps de requête ou du timing. Isolez d'abord le problème avec l'exemple curl pour savoir s'il vient de votre code ou de l'entrée, puis reportez le correctif en Python.

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