GPT-6 Sol et Claude Opus 5.5 disponiblesGPT-6 Sol à moitié prix par rapport à 5.6 Sol

Nano Banana Pro API : tutoriel Python, édition d'image et prix

Un POST, une interrogation, un téléchargement : un script Nano Banana Pro qui fonctionne.

Kiki, OmniaKey COO9 minutes de lecture
Sur cette page

Nano Banana Pro, c'est gemini-3-pro-image de Google, et sur OmniaKey vous l'appelez avec un seul POST /v1/media/tasks. Nos trois essais en 3:4 sont revenus en 896x1200, 1792x2400 et 3584x4800, et chaque mot de l'affiche était correctement orthographié.

Réponse courte

  • Modèle : gemini-3-pro-image est l'identifiant GA de Google. La fiche du modèle chez Vertex indique une date de sortie au 28 mai 2026.
  • Appel : envoyez POST https://api.omniakey.com/v1/media/tasks avec une Idempotency-Key, interrogez GET /v1/media/tasks/{id} jusqu'au statut succeeded, puis téléchargez assets[0].url.
  • Paramètres : parameters.aspect_ratio et parameters.image_size ; les valeurs de taille sont 1K, 2K et 4K, avec un K en majuscule.
  • Limite de requête : 1 MiB pour tout le corps, données d'image en Base64 comprises.
  • Prix Google : $0.134 par image 1K/2K et $0.24 par image 4K, d'après la page tarifaire de l'API Gemini.
  • Nos jetons : les trois tâches ont déclaré 1,133, 1,225 et 2,480 jetons de sortie. À $120 par million de jetons d'image, cela fait $0.136, $0.147 et $0.298.
  • Retouche : utilisez operation: "edit" et placez l'image source dans input.image sous la forme {data, mime_type}.

La page du modèle Nano Banana Pro sur OmniaKey accepte aussi gemini-3-pro-image-preview, l'ancien identifiant d'instantané, au même prix.

L'identifiant du modèle et ce qu'il vous faut

L'identifiant à écrire dans votre code est gemini-3-pro-image. La fiche du modèle chez Vertex le liste en GA avec une date de sortie au 28 mai 2026. Il produit des images en 1K, 2K et 4K.

L'identifiant -preview désigne le même modèle. Le tableau des modèles d'image d'OmniaKey décrit gemini-3-pro-image-preview comme « Same model, -preview snapshot id », au même tarif par appel.

Il vous faut deux choses :

  1. Une clé d'API OmniaKey, exportée pour que le script la lise : export OMNIAKEY_API_KEY="your-key".
  2. Python 3. Le script ci-dessous n'utilise que la bibliothèque standard : urllib, json, time, uuid, base64 et pathlib. Aucun SDK à installer.

Le script Python

Trois étapes : créer la tâche, l'interroger, télécharger l'image. Enregistrez-le sous nano_banana.py et lancez python3 nano_banana.py.

python
import base64
import json
import os
import time
import urllib.request
import uuid
from pathlib import Path

API = "https://api.omniakey.com/v1/media/tasks"
HEADERS = {
    "Authorization": f"Bearer {os.environ['OMNIAKEY_API_KEY']}",
    "Content-Type": "application/json",
}


def call(url, payload=None, headers=None, method=None):
    body = json.dumps(payload).encode() if payload is not None else None
    req = urllib.request.Request(url, data=body, headers=headers or HEADERS, method=method)
    with urllib.request.urlopen(req, timeout=60) as resp:
        return resp.status, json.loads(resp.read())


def create_task(prompt, aspect_ratio="3:4", image_size="2K", image_path=None):
    body = {
        "model": "gemini-3-pro-image",
        "type": "image",
        "operation": "generate" if image_path is None else "edit",
        "input": {"prompt": prompt},
        "parameters": {"aspect_ratio": aspect_ratio, "image_size": image_size},
    }
    if image_path:
        encoded = base64.b64encode(Path(image_path).read_bytes()).decode("utf-8")
        body["input"]["image"] = {"data": encoded, "mime_type": "image/png"}
    headers = {**HEADERS, "Idempotency-Key": str(uuid.uuid4())}
    status, task = call(API, body, headers, "POST")
    print("created", task["id"], "HTTP", status)
    return task


def wait(task_id, interval=3, timeout=300):
    deadline = time.time() + timeout
    while time.time() < deadline:
        _, task = call(f"{API}/{task_id}")
        print(task["status"], task["progress"]["percent"])
        if task["status"] in ("succeeded", "failed", "canceled"):
            return task
        time.sleep(interval)
    # A timeout is not a failure: keep the task id and poll it again.
    raise TimeoutError(f"task {task_id} is still running")


def download(task, out_path):
    asset = task["assets"][0]
    with urllib.request.urlopen(asset["url"], timeout=120) as resp:
        Path(out_path).write_bytes(resp.read())
    print("saved", out_path, asset["mime_type"], asset["byte_size"], "bytes")


if __name__ == "__main__":
    task = create_task(
        "A vintage travel poster for the Night Train from Zürich to Milano, "
        "departing 21:40 from platform 7. A steam train crosses a stone arch "
        "bridge below snowy mountains under a deep blue night sky, with a cream "
        "border. Spell every word exactly as written.",
        aspect_ratio="3:4",
        image_size="2K",
    )
    task = wait(task["id"])
    if task["status"] != "succeeded":
        raise SystemExit(f"{task['status']}: {task.get('error')}")
    download(task, "night-train.jpg")

image_size accepte 1K, 2K ou 4K. Le guide image de Google est explicite : « You must use an uppercase 'K' … Lowercase parameters (e.g., 1k) will be rejected. » Envoyez 2K, pas 2k.

Idempotency-Key est obligatoire. Un UUID neuf par requête est la règle simple ; ne réutilisez une clé que pour renvoyer exactement le même corps. OmniaKey renvoie alors la tâche d'origine en HTTP 200 au lieu de facturer deux fois, et répond 409 si la même clé arrive avec un corps différent.

L'appel de création renvoie 202 avec un id. La documentation des tâches média d'OmniaKey décrit tout le cycle ; la tâche terminée porte les champs que vous lisez :

json
{
  "id": "task_AbMRVqzSnVh0VwBj0S7NuMUxy5sZtfHP",
  "status": "succeeded",
  "progress": {"percent": 100, "stage": "completed"},
  "usage": {"total_tokens": 1133},
  "assets": [
    {
      "kind": "image",
      "mime_type": "…",
      "url": "https://…signed-url…"
    }
  ]
}

Lisez assets[0].url et téléchargez tout de suite : le lien signé dure environ une heure, et l'enregistrement de la tâche reste 24 heures. Le champ mime_type donne le format ; les modèles Gemini renvoient le plus souvent du JPEG.

Le même script en 1:1 et 2K, avec une consigne d'enseigne en chinois, a donné ceci :

Une enseigne en métal sombre sur un mur de briques, avec trois lignes de texte chinois et un numéro de téléphone
2K, 1:1 : 2048x2048 en 47.2 s. Les trois lignes chinoises et le 010-6789 4321 sont revenus justes ; la rouille couvre une partie du premier 0.

Retoucher une image existante

Mettez operation: "edit" et passez l'image source dans input.image sous la forme {data, mime_type}. Le script ci-dessus le fait déjà quand vous lui donnez un image_path :

python
task = create_task(
    "Hang this poster in a thin black frame on a warm white wall, with a brass "
    "picture light above it, a low wooden cabinet below and a trailing plant on "
    "the right. Keep the poster exactly as it is.",
    aspect_ratio="1:1",
    image_size="2K",
    image_path="night-train-2k.png",
)

Voici le corps réellement envoyé :

json
{
  "model": "gemini-3-pro-image",
  "type": "image",
  "operation": "edit",
  "input": {
    "prompt": "Hang this poster in a thin black frame on a warm white wall…",
    "image": {"data": "…base64…", "mime_type": "image/png"}
  },
  "parameters": {"aspect_ratio": "1:1", "image_size": "2K"}
}

L'image source de l'exemple est un PNG, donc le script l'étiquette image/png ; changez cette étiquette pour un JPEG. Pour plusieurs références, utilisez input.images avec la même forme {data, mime_type} pour chaque entrée. Le guide de Google fixe la limite à 14 images de référence ; pour gemini-3-pro-image, la répartition est de 6 images d'objet, 5 de personnage et 3 de style.

Gardez le corps sous 1 MiB. Le Base64 grossit le fichier d'environ un tiers : réduisez ou compressez la source avant de l'encoder. Notre retouche a utilisé l'affiche en 2K et a conservé chaque mot et la mise en page :

L'affiche du train de nuit dans un cadre noir sur un mur, avec une lampe de tableau au-dessus et une plante à droite
2K, retouche 1:1 : 2048x2048 en 49.9 s. Le texte et le graphisme de l'affiche ont survécu ; le cadre est un rectangle net.

1K, 2K et 4K : ce que chacun apporte

Nous avons lancé la même consigne d'affiche en 3:4 dans les trois tailles. Les pixels correspondaient exactement au tableau de Google pour le 3:4 : 896x1200 en 1K, 1792x2400 en 2K et 3584x4800 en 4K. Le texte de l'affiche était juste à chaque taille.

L'affiche du train de nuit en 1K : train à vapeur sur un pont de pierre, montagnes enneigées et ciel bleu profond
1K, 3:4 : 896x1200 en 28.4 s. Les quatre lignes de l'affiche sont bonnes ; les fanaux et les bielles de la locomotive se serrent.
La même affiche du train de nuit en 2K, avec un village et deux clochers ajoutés sur le versant de droite
2K, 3:4 : 1792x2400 en 48.2 s. Même texte, plus un village et deux clochers sur le versant de droite.
La même affiche du train de nuit en 4K, avec trois voitures et le tender dessinés derrière la locomotive
4K, 3:4 : 3584x4800 en 66.9 s. Trois voitures et le tender sont dessinés ; les joints de briques varient en épaisseur.

Ce qui change avec la taille, c'est le détail, pas l'orthographe :

  • 1K : l'avant du train est encombré : fanaux, roues et bielles se touchent presque.
  • 2K : le village et ses deux clochers apparaissent sur le versant de droite, la cheminée fume d'un filet pâle et le pont montre sept arches.
  • 4K : les trois voitures et le tender sont séparés, et la pierre montre des joints d'épaisseur inégale. La mécanique sous la locomotive reste simplifiée.

La durée montait avec la taille : 28.4 s, 48.2 s et 66.9 s. Chaque taille n'a tourné qu'une fois, lisez donc ces secondes comme une seule passe.

Google facture la sortie d'image à $120 par million de jetons, et son tableau donne 1,120 jetons pour le 1K comme pour le 2K et 2,000 jetons pour le 4K. D'où son estimation :

text
1,120 × $120 ÷ 1,000,000 = $0.134 per 1K image
1,120 × $120 ÷ 1,000,000 = $0.134 per 2K image
2,000 × $120 ÷ 1,000,000 = $0.24  per 4K image

Nos tâches ont déclaré plus de jetons que les exemples de Google. Voici le même calcul avec nos chiffres :

text
1,133 × $120 ÷ 1,000,000 = $0.136 per 1K image
1,225 × $120 ÷ 1,000,000 = $0.147 per 2K image
2,480 × $120 ÷ 1,000,000 = $0.298 per 4K image
TaillePixels, 3:4Notre duréeNos jetonsEstimation Google
1K896x120028.4 s1,133$0.134
2K1792x240048.2 s1,225$0.134
4K3584x480066.9 s2,480$0.24

OmniaKey facture un appel d'image à forfait, pas au jeton : son montant ne bouge donc pas avec ces compteurs. Le tarif actuel par appel est sur la page du modèle, et une tâche échouée est remboursée. L'estimation de Google au tarif des jetons pour les mêmes trois images est de $0.134, $0.134 et $0.24.

Les erreurs que vous allez rencontrer

Les échecs listés ici se résument presque toujours à un nom de champ ou à une taille de fichier, pas au modèle. Voici ceux que la documentation média d'OmniaKey indique pour ce point d'entrée :

HTTPCode ou statutCe que ça veut direQue faire
400invalid_requestCorps mal formé, opération non prise en charge ou paramètre invalideVérifiez le JSON et les noms de champs ci-dessous
503no_available_channelAucun canal ne sert ce modèle en ce momentChangez de modèle ; réessayer n'y changera rien
—failedLa tâche s'est terminée sans résultatLisez error.code et error.message

Une tâche échouée n'est pas une erreur HTTP : l'appel de création a réussi, donc interrogez la tâche et lisez son objet error. Les tâches échouées ou annulées sont remboursées automatiquement.

Une source en pleine résolution envoyée en Base64 peut pousser le corps au-delà de 1 MiB. Réduisez d'abord, puis vérifiez la longueur encodée, pas seulement la taille du fichier.

Le guide de Google refuse un 1k en minuscules. Utilisez 1K, 2K ou 4K.

La documentation image d'OmniaKey refuse aussi size et un mime_type de premier niveau sur les modèles Gemini, car ce ne sont pas des paramètres Gemini. Utilisez parameters.aspect_ratio et parameters.image_size, et lisez le format de sortie dans le champ mime_type de la réponse.

Questions fréquentes

Quel est l'identifiant du modèle de l'API Nano Banana Pro ?

gemini-3-pro-image. La fiche Vertex de Google le donne en GA avec une date de sortie au 28 mai 2026, et OmniaKey accepte le même identifiant. L'ancien identifiant gemini-3-pro-image-preview fonctionne toujours sur OmniaKey et désigne le même modèle.

Combien coûte une image Nano Banana Pro ?

Google estime $0.134 pour une image 1K ou 2K et $0.24 pour une image 4K, à $120 par million de jetons d'image. Nos tâches ont déclaré 1,133, 1,225 et 2,480 jetons, soit $0.136, $0.147 et $0.298 à ce tarif. La page du modèle sur OmniaKey affiche son propre tarif par appel.

Nano Banana Pro sait-il dessiner du texte chinois ?

Oui. Notre enseigne en 2K est revenue avec trois lignes chinoises justes — 同福客栈, 住宿 餐饮 茶水 et 010-6789 4321 — avec les 11 chiffres et le trait d'union.

Faut-il demander du 1K, du 2K ou du 4K ?

Pour une affiche comme la nôtre, 2K est le bon milieu. Les trois tailles ont écrit notre affiche correctement : le 4K achète donc du détail plus fin — voitures séparées, joints de briques — et non un meilleur texte. Prenez 1K pour les brouillons où 896x1200 suffit.

Pourquoi ma retouche a-t-elle renvoyé 400 invalid_request ?

Les causes habituelles : un corps de plus de 1 MiB, la source dans le mauvais champ, ou un modèle Gemini qui reçoit size ou un mime_type de premier niveau. Placez l'image dans input.image sous la forme {data, mime_type}, gardez le corps encodé sous 1 MiB et utilisez aspect_ratio et image_size.

Sources vérifiées

Journal des mises à jour

  • 2026-11-03 : première version ; cinq appels de test passés ce jour-là via OmniaKey.

Modèles cités dans cet article

Nano Banana ProGemini imageAPI imagePythonTutoriel API

Articles similaires

Articles récents

Guides populaires