HiAPI
Blog

Tutoriel

Comment utiliser nano-banana-pro via l'API HiAPI : exemples curl et Python

Oct 31, 2026
平面流体形态层叠交错的封面图,墨色底上流动着青瓷绿与石板灰的波纹,呼应教程主题。

Ce que nano-banana-pro sur HiAPI vous offre

nano-banana-pro est un modèle de génération d'images accessible via l'API unifiée de HiAPI. Au lieu de vous intégrer directement au fournisseur du modèle, il vous suffit d'envoyer une requête au format unifié à HiAPI pour obtenir l'image générée — comme pour les modèles des autres plateformes, avec la même authentification, les mêmes conventions de point de terminaison et la même enveloppe de réponse.

nano-banana-pro est conçu pour la génération d'images pilotée par prompt, et peut joindre des images de référence en plus du prompt textuel. Les images de référence vous permettent de guider la sortie par un contexte visuel (sujet, style, composition), sans avoir à tout décrire en mots. La sortie est livrée en résolution 2K, ce qui rend le modèle plus adapté aux assets de production qu'aux ébauches rapides.

À la fin de ce tutoriel, vous disposerez d'une intégration complète et fonctionnelle capable de :

  • envoyer un prompt à nano-banana-pro via HiAPI avec une requête curl validée ;
  • reproduire le même appel en Python, sans modifier la charge utile de la requête ;
  • joindre une image de référence à la requête ;
  • soumettre une tâche asynchrone, interroger son état jusqu'à completion et gérer les tentatives de manière raisonnable ;
  • télécharger l'image 2K terminée et la stocker dans votre propre infrastructure.

Chaque section s'appuie sur la précédente, donc le chemin le plus sûr est de procéder dans l'ordre : valider d'abord la requête manuellement, puis la déplacer dans le code.

Avant d'envoyer la première requête

Trois éléments sont nécessaires avant le premier appel.

Une clé d'API

Créez une clé d'API dans votre compte HiAPI et assurez-vous qu'elle n'est pas placée sous gestion de code source. Traitez-la comme n'importe quel autre secret : chargez-la depuis une variable d'environnement (HIAPI_API_KEY) ou un gestionnaire de secrets, et ne la codez jamais en dur dans un fichier susceptible d'être commité. Si la clé fuite, faites-la tourner dans le tableau de bord plutôt que d'essayer de la purger de l'historique.

Un client HTTP

Tout outil capable d'envoyer des requêtes HTTPS convient. Pour la première requête, curl en ligne de commande est idéal car il n'y a aucun framework entre vous et le réseau — chaque en-tête de requête et chaque octet du corps de réponse sont visibles. Pour la partie Python, la bibliothèque standard urllib.request suffit ; si vous utilisez déjà requests ou httpx, le mapping est identique. Ce tutoriel limite Python à la bibliothèque standard, vous n'avez donc rien à installer en plus.

Un emplacement pour stocker la sortie

Comme les tâches nano-banana-pro sont asynchrones, prévoyez dès le départ un répertoire ou un bucket pour sauvegarder les images terminées. En développement, un dossier local output/ suffit ; en production, visez un stockage objet.

Vous n'avez pas besoin d'installer de SDK fournisseur. HiAPI s'appelle via du HTTPS classique, donc la requête que vous construisez dans curl est exactement celle que votre client Python enverra ensuite.

Une requête curl fonctionnelle, expliquée étape par étape

Le moyen le plus rapide de vérifier que la clé, le point de terminaison et la charge utile sont corrects est d'envoyer une requête manuellement. Décomposez-la en parties avant de la saisir.

Point de terminaison et méthode

Tous les appels de modèle sont envoyés à la même URL de base HiAPI, le modèle étant identifié dans le corps de la requête, et non dans le chemin. Les requêtes de génération utilisent POST.

En-têtes

Trois en-têtes importent à chaque appel :

  • Authorization: Bearer $HIAPI_API_KEY — votre clé, transmise comme jeton bearer.
  • Content-Type: application/json — pour les requêtes contenant uniquement un prompt.
  • Accept: application/json — pour obtenir une réponse structurée plutôt qu'une page d'erreur HTML.

Corps de la requête

Le corps JSON contient le nom du modèle et les paramètres de génération. Au minimum, envoyez l'identifiant du modèle et votre prompt :

curl -sS -X POST "$HIAPI_BASE_URL" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "model": "nano-banana-pro",
    "input": {
      "prompt": "a glass terrarium on a sunlit windowsill, soft morning light, shallow depth of field"
    }
  }'

Avant d'exécuter cette commande, définissez HIAPI_BASE_URL et HIAPI_API_KEY dans votre shell. Conserver l'URL dans une variable signifie que vous pourrez plus tard pointer le même script vers une URL de staging ou de sandbox sans modifier la commande.

Lire la réponse

Une soumission réussie renvoie un objet JSON identifiant la tâche. Le champ important est l'identifiant de tâche — vous l'utiliserez à l'étape d'interrogation. Comme la génération prend du temps, ne vous attendez pas à obtenir l'image elle-même dans la première réponse ; nano-banana-pro fonctionne de manière asynchrone, et cet appel ne constitue que la partie soumission de l'interaction.

Si la commande renvoie une erreur, arrêtez-vous ici et corrigez-la avant d'écrire du code. La requête curl validée est votre implémentation de référence : chaque étape suivante doit produire la même requête HTTP.

Porter la requête en Python

Le portage est mécanique : l'URL, la méthode, les en-têtes et le corps JSON restent inchangés. Seul le client change.

La même requête avec urllib

import json
import os
import urllib.request

api_key = os.environ["HIAPI_API_KEY"]
base_url = os.environ["HIAPI_BASE_URL"]

payload = {
    "model": "nano-banana-pro",
    "input": {
        "prompt": "a glass terrarium on a sunlit windowsill, soft morning light, shallow depth of field"
    },
}

request = urllib.request.Request(
    base_url,
    data=json.dumps(payload).encode("utf-8"),
    method="POST",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
        "Accept": "application/json",
    },
)

with urllib.request.urlopen(request, timeout=60) as response:
    body = json.loads(response.read().decode("utf-8"))

print(body)

Règles de mapping

Trois détails sont faciles à rater lors de la conversion depuis curl :

  1. Le corps doit être en octets. json.dumps produit une chaîne ; il faut l'encoder avant de la confier à l'objet de requête.
  2. Les en-têtes sont un dictionnaire, pas des options. Chaque ligne -H devient une paire clé/valeur. Conservez le préfixe Bearer suivi de son espace.
  3. La méthode doit être spécifiée explicitement. Lorsque des données sont présentes, urllib.request utilise POST par défaut, mais définir method="POST" rend l'intention plus claire et évite les surprises si vous supprimez le corps plus tard.

Si vous utilisez requests, l'équivalent est requests.post(base_url, headers=headers, json=payload, timeout=60) — json= gère la sérialisation et le type de contenu pour vous. Si vous utilisez httpx, la forme de l'appel est identique.

Un petit utilitaire qui vaut la peine

Placez l'appel de soumission dans une fonction qui reçoit un prompt et renvoie l'identifiant de tâche. Chaque section suivante — images de référence, interrogation, téléchargement — s'appuie sur cette fonction ; la garder au même endroit signifie que les changements de forme de requête n'ont lieu qu'une seule fois.

Envoyer une image de référence avec le prompt

L'image de référence modifie la forme de la requête, donc décidez tôt quelle méthode d'entrée votre application utilisera.

Deux options pratiques

Entrée par URL. Si l'image de référence est déjà accessible via HTTPS, vous pouvez joindre son URL dans le corps de la requête avec le prompt. Cela maintient la requête en application/json, la forme la plus facile à réessayer et à journaliser.

Envoi de fichier. Si l'image se trouve côté client ou dans un stockage privé, vous pouvez l'envoyer comme partie fichier dans une requête multipart/form-data. Dans ce cas, l'en-tête Content-Type: application/json est remplacé par le type de contenu multipart — laissez votre client HTTP le générer pour garantir la bonne boundary — et les champs JSON deviennent des champs de formulaire dans la même requête.

Pour la plupart des intégrations côté serveur, l'entrée par URL est plus simple : votre image est déjà dans le stockage objet, la requête reste en JSON, et vous évitez d'envoyer deux fois de gros corps de requête lors des tentatives.

Garder le prompt et l'image de référence synchronisés

Le prompt doit décrire l'usage de l'image de référence, pas seulement son contenu. « Reprends l'éclairage et la tonalité de l'image de référence ; remplace le sujet par un vase en céramique » donne au modèle une tâche claire. Un prompt qui ignore l'image de référence gaspille l'entrée.

Valider avant l'envoi

L'image de référence est la source la plus fréquente d'erreurs de requête. Vérifiez que l'URL est publiquement accessible (ou que les deux côtés de votre système s'accordent sur la durée de validité de l'URL signée), que le type de fichier est accepté par le modèle et que l'image n'est pas trop lourde au point de provoquer un dépassement de délai d'envoi. Effectuez ces vérifications dans votre propre code d'abord — déboguer un échec de validation côté client coûte bien moins cher qu'une requête rejetée.

Gérer les tâches asynchrones et interroger les résultats

La génération nano-banana-pro est asynchrone. Structurez votre client autour de trois étapes distinctes : soumission, interrogation, téléchargement. Les mélanger dans une seule fonction rend les tentatives et les délais d'attente difficiles à raisonner.

Étape 1 : soumettre

Envoyez la requête ci-dessus et stockez l'identifiant de tâche qu'elle renvoie. Persistez cet identifiant dans un emplacement durable — une ligne de base de données ou un message de file d'attente — car votre processus peut redémarrer entre la soumission et la completion.

Étape 2 : interroger

Utilisez la même URL de base et le même en-tête Authorization, en incluant l'identifiant de tâche dans la requête, pour récupérer l'état de la tâche. Interrogez à intervalles plutôt qu'en boucle serrée ; quelques secondes entre chaque vérification est typique, et il convient de reculer si plusieurs vérifications consécutives renvoient l'état en attente.

import time

TERMINAL = {"succeeded", "failed"}

def wait_for_job(job_id, timeout=300, interval=3):
    deadline = time.monotonic() + timeout
    while time.monotonic() < deadline:
        status = get_job_status(job_id)  # same headers as submit
        if status in TERMINAL:
            return status
        time.sleep(interval)
    raise TimeoutError(f"job {job_id} did not finish in time")

Étape 3 : respecter l'état

Traitez le champ d'état comme une énumération. Une tâche est soit toujours en cours, soit terminée avec succès, soit échouée. Gérez explicitement les trois cas : en cas de succès, passez au téléchargement ; en cas d'échec, lisez le message d'erreur et déterminez si le problème vient de l'entrée ou du prompt ; en cas de dépassement de délai, arrêtez l'interrogation et exposez l'identifiant de tâche pour une enquête ultérieure.

Les tentatives relèvent de deux niveaux

Les tentatives au niveau réseau doivent s'appliquer à l'appel de soumission et à chaque requête d'interrogation, avec un nombre d'essais limité. Les tentatives au niveau de la tâche sont différentes : si une tâche échoue à cause d'un mauvais prompt ou d'une mauvaise image de référence, soumettre à nouveau la même charge utile échouera de la même manière. Ne réessayez la tâche elle-même qu'après avoir modifié les entrées.

Un modèle de production courant consiste à confier la boucle d'interrogation à un worker, afin que les requêtes web ne soient jamais bloquées par la génération. Soumettez depuis votre gestionnaire d'API, transmettez l'identifiant de tâche au worker, et notifiez le client lorsque le worker a terminé.

Télécharger et stocker la sortie 2K

La réponse finale de la tâche pointe vers l'image générée au lieu de l'intégrer, ce qui signifie que le téléchargement est une étape dont vous êtes responsable.

Récupérer l'image

Lorsque la tâche signale un succès, la réponse contient l'emplacement de la sortie. Récupérez-le avec une simple requête GET, puis écrivez les octets dans un fichier ou streamez-les vers le stockage. En développement, enregistrez dans un répertoire local avec un nom prévisible construit à partir de l'identifiant de tâche, afin de relier le fichier à l'enregistrement de la tâche.

import pathlib
import urllib.request

def save_image(url, job_id, out_dir="output"):
    pathlib.Path(out_dir).mkdir(exist_ok=True)
    target = pathlib.Path(out_dir) / f"nano-banana-pro-{job_id}.png"
    with urllib.request.urlopen(url, timeout=60) as response:
        target.write_bytes(response.read())
    return target

Stocker correctement

En production, streamez la réponse directement vers le stockage objet plutôt que de l'écrire sur le disque local, afin que le comportement soit identique quel que soit le worker qui traite la tâche. Enregistrez la clé d'objet et l'identifiant de tâche dans la base de données, et vérifiez que le type de contenu et l'extension de fichier correspondent à ce que le modèle a généré. Si l'image doit être servie sur une page web, générez des vignettes dans le même pipeline, afin que les pages publiques ne chargent jamais le fichier complet en résolution 2K.

Planifier la politique de rétention

La sortie générée est votre donnée. Décidez combien de temps la conserver, si un versioning est nécessaire, et si l'emplacement final est quelque chose que votre application peut régénérer en cas de perte. Si la réponse est non, stockez également la charge utile de la requête et l'image, afin qu'un futur bug ou changement de modèle ne vous empêche jamais de reproduire le résultat.

Points de défaillance courants et méthodes de débogage

La plupart des premières intégrations échouent pour quelques raisons seulement. Avant de supposer un problème du modèle, passez en revue cette liste.

  • Erreurs d'autorisation. Préfixe Bearer manquant, clé comportant un caractère de fin de ligne à cause d'une copie depuis un fichier d'environnement, ou clé issue d'un environnement différent de celui de l'URL de base configurée.
  • Incohérence de type de contenu. Envoyer des champs JSON avec un en-tête multipart, ou envoyer un fichier en application/json, est la cause la plus fréquente de rejet des requêtes avec image de référence. Pour un corps multipart, laissez le client définir l'en-tête.
  • Mauvaise méthode ou mauvaise forme de corps. Utiliser GET au lieu de POST, ou un prompt de niveau supérieur au lieu d'un objet input imbriqué, produit des erreurs de validation qui semblent totalement sans rapport. Comparez votre requête octet par octet avec l'appel curl validé — curl -v affiche les en-têtes réellement envoyés.
  • Interrogation trop rapide ou absente. Des requêtes fréquentes sur le point de terminaison d'état provoquent des limitations de débit ; sans interrogation, vous n'obtiendrez rien. Utilisez un intervalle fixe avec recul et un délai d'attente maximal strict.
  • URL de sortie expirée. Si vous attendez trop longtemps entre la completion de la tâche et le téléchargement, l'URL de sortie signée peut expirer. Téléchargez immédiatement après le succès, ou prévoyez un chemin de récupération d'un nouvel emplacement.
  • Échecs silencieux dans le code. Journalisez toujours le code de statut HTTP et le corps de la réponse en cas d'erreur. Les messages d'exception génériques levés par les clients HTTP masquent les parties utiles de la réponse.

En cas de doute, revenez à la requête curl validée de la première section. Si cette requête fonctionne et que votre appel Python ne fonctionne pas, la différence entre les deux est le bug.

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