API de génération d’images Gemini en Python : exemple de code
Un guide Python fonctionnel pour l’API de génération d’images Gemini, avec le modèle actuel gemini-3.1-flash-image et l’Interactions API. Générez votre première image, contrôlez le format et la résolution, retouchez des photos, relancez les appels échoués et estimez les coûts réels par image.
La plupart des tutoriels sur la génération d’images Gemini appellent encore gemini-2.5-flash-image, et la page tarifaire de Google indique que ce modèle est obsolète, avec une date d’arrêt fixée au 2 octobre 2026. Cette date est passée : les extraits construits dessus doivent donc être considérés comme cassés. Cette page utilise le modèle actuel, gemini-3.1-flash-image, ainsi que l’Interactions API que la documentation de Google présente désormais en premier.
Vous passerez d’un dossier vide à un script fonctionnel qui génère une image, contrôle sa taille, retouche une photo existante, enregistre une sortie mixte texte et image, et gère les limites de débit. Chaque extrait est assez court pour être collé dans un fichier et exécuté. Une image 1K sur le modèle Flash standard coûte environ 0,067 $, donc les tests restent peu coûteux.
Ce dont vous avez besoin avant de coder
Trois éléments vous séparent de votre première image : une installation récente de Python 3, un identifiant obtenu dans Google AI Studio, et un projet avec la facturation activée. La page tarifaire de Google n’indique aucun niveau gratuit pour les modèles d’image Gemini, donc un projet sans facturation sera probablement rejeté dès le premier appel.
Installer le SDK
Un seul paquet fait tout :
pip install -U google-genai
L’Interactions API nécessite google-genai2.3.0 ou plus récent, c’est pourquoi l’option -U est importante. Exécutez pip show google-genai si un extrait ci-dessous échoue avec une erreur d’attribut sur client.interactions.
Définir votre identifiant
Créez un identifiant dans Google AI Studio, puis exportez-le comme variable d’environnement sous le nom exact indiqué ci-dessous. Le SDK lit cette variable de lui-même, ainsi votre script n’a jamais à contenir le secret.
Sous Windows PowerShell, la même ligne devient $env:GEMINI_API_KEY = "paste-your-credential-here".
💡 Ne collez jamais l’identifiant dans un script envoyé sur Git. Conservez-le dans une variable d’environnement ou dans un fichier .env que votre .gitignore exclut déjà.
Choisir un modèle
Google propose désormais quatre modèles d’image. Trois sont actuels, un est retiré.
ID du modèle
Tailles
Prix par image
Idéal pour
gemini-3.1-flash-lite-image
1K uniquement
environ 0,034 $
Traitements en masse, vignettes
gemini-3.1-flash-image
0.5K, 1K, 2K, 4K
0,045 $, 0,067 $, 0,101 $, 0,151 $
Choix par défaut pour la plupart des scripts
gemini-3-pro-image
1K, 2K, 4K
0,134 $ (1K et 2K), 0,24 $ (4K)
Prompts complexes à plusieurs parties
gemini-2.5-flash-image
n.d.
0,039 $
Retiré, à ne pas utiliser
Les prix proviennent de la page tarifaire de Google au moment de la rédaction. Vérifiez-les à nouveau avant un traitement important.
Comment choisir ? Commencez par gemini-3.1-flash-image. C’est le seul modèle actuel qui propose les quatre tailles, donc un seul chemin de code couvre les vignettes comme les fichiers destinés à l’impression. Passez à Flash Lite lorsque vous générez des milliers de petites images et que chaque centime par image compte. Tournez-vous vers Pro lorsqu’un prompt comporte beaucoup d’éléments, comme une mise en page d’affiche avec plusieurs éléments étiquetés, et qu’un modèle moins cher continue d’oublier des détails. Comme les trois modèles actuels partagent la même forme d’appel, changer de modèle plus tard revient à modifier une seule chaîne de caractères.
Générer votre première image
Enregistrez ceci sous first_image.py :
import base64
from google import genai
client = genai.Client()
interaction = client.interactions.create(
model="gemini-3.1-flash-image",
input="A photograph of a bowl of oranges on a linen cloth, soft window light",
)
with open("oranges.png", "wb") as f:
f.write(base64.b64decode(interaction.output_image.data))
Exécutez python first_image.py et un fichier oranges.png apparaît à côté du script. C’est tout le cycle : prompt en entrée, chaîne base64 en sortie, octets sur le disque.
Dès que vous générez plus d’une image, un nom de fichier fixe écrase votre résultat précédent. Construisez plutôt le nom à partir d’un horodatage, par exemple f"image_{int(time.time())}.png", et chaque exécution conservera son propre fichier. Vous pouvez ensuite comparer une douzaine de variations d’un même prompt côte à côte.
Ce que fait chaque ligne
genai.Client() crée un client et récupère l’identifiant depuis la variable d’environnement que vous avez exportée plus tôt, de sorte qu’aucune donnée sensible ne figure dans le fichier.
client.interactions.create() envoie le prompt et renvoie un objet Interaction qui contient une id, les étapes de sortie et des raccourcis tels que output_image.
interaction.output_image.data contient l’image sous forme de chaîne base64. Vous devez la décoder avant l’écriture, sinon le fichier sera du texte et non une image.
Écrire des prompts efficaces
Le modèle répond mieux aux descriptions de scènes qu’à une accumulation de mots-clés désordonnés. Un prompt qui ressemble à la liste de plans d’un photographe vous donne plus de contrôle qu’une liste d’adjectifs.
Nommez le sujet et l’action. « Un boulanger saupoudrant de farine une miche » vaut mieux que « boulangerie ».
Précisez la lumière. Lumière de fenêtre, ciel couvert, heure dorée ou soleil de midi dur.
Ajoutez l’objectif et la distance. « Portrait 85 mm, faible profondeur de champ » ou « vue aérienne grand angle 24 mm ».
Indiquez ce qu’il faut exclure. Une phrase courte, comme « aucun texte dans l’image ».
💡 Conservez vos prompts dans une liste Python ou un fichier texte. Lorsqu’un résultat vous surprend, vous pouvez modifier une seule variable et comparer, ce qui vaut mieux que de tout réécrire de mémoire.
Contrôler la taille et le format
La taille et la forme se trouvent dans un dictionnaire response_format. Cela déroute beaucoup de monde, car l’ancien code plaçait les réglages d’image dans generation_config.
interaction = client.interactions.create(
model="gemini-3.1-flash-image",
input="A wide photograph of a coastal road at dawn, 35mm lens, film grain",
response_format={
"type": "image",
"mime_type": "image/jpeg",
"aspect_ratio": "16:9",
"image_size": "2K",
},
)
with open("coast.jpg", "wb") as f:
f.write(base64.b64decode(interaction.output_image.data))
Comme le mime_type demandé est du JPEG, le fichier reçoit l’extension .jpg. Faites correspondre l’extension au type demandé et votre visionneuse d’images ne protestera jamais.
Formats d’image que vous pouvez demander
La documentation de Google répertorie dix formats : 1:1, 3:2, 2:3, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9 et 21:9.
Format
Usage courant
1:1
Photos de profil, vignettes de produits
4:5
Publications pour les flux sociaux
9:16
Stories et vignettes de vidéos verticales
16:9
En-têtes de blog, vignettes de vidéos
21:9
Bannières ultra-larges
3:2
Tirages photo classiques
Choisir une résolution
La valeur image_size dépend du modèle. Flash Lite propose uniquement 1K. Flash propose 0.5K, 1K, 2K et 4K. Pro propose 1K, 2K et 4K. Utilisez K en majuscules dans la valeur.
Une règle simple garde les coûts raisonnables : 1K pour les brouillons, 2K pour les pages web, 4K uniquement pour l’impression. Une image 4K sur Flash coûte 0,151 $ contre 0,067 $ en 1K, soit environ 2,25 fois plus, donc l’habitude de « toujours choisir le maximum » s’accumule vite.
Retoucher une photo avec des prompts textuels
Le même point de terminaison permet de modifier des images. Au lieu d’une simple chaîne, input devient une liste qui mélange des blocs de texte et des blocs d’image. L’image est transmise sous forme de chaîne base64 avec son type MIME.
import base64
from google import genai
client = genai.Client()
with open("portrait.png", "rb") as f:
encoded = base64.b64encode(f.read()).decode("utf-8")
interaction = client.interactions.create(
model="gemini-3.1-flash-image",
input=[
{
"type": "text",
"text": "Replace the background with a sunlit brick wall. Keep the person unchanged.",
},
{"type": "image", "data": encoded, "mime_type": "image/png"},
],
)
with open("portrait_edit.png", "wb") as f:
f.write(base64.b64decode(interaction.output_image.data))
Remarquez la formulation du prompt de modification. Il indique ce qui change (l’arrière-plan) et ce qui reste (la personne). Sans la seconde partie, le modèle est libre de restyler toute l’image.
Enchaîner les modifications dans une conversation
Vous n’avez pas besoin de renvoyer l’image à chaque retouche. Transmettez le id de l’interaction précédente, et le modèle se souvient de l’image qu’il vient de créer :
second = client.interactions.create(
model="gemini-3.1-flash-image",
input="Make the light warmer, like late afternoon.",
previous_interaction_id=interaction.id,
response_format={
"type": "image",
"mime_type": "image/jpeg",
"aspect_ratio": "4:5",
"image_size": "2K",
},
)
Conservez le même format que la première image, sinon le modèle risque de recadrer ou d’étendre la scène. Enregistrez chaque interaction.id dans votre base de données, et vous pourrez revenir à n’importe quelle étape antérieure d’une session, ce qui est pratique pour le travail client, où « revenez à la version deux » revient souvent.
Lire les réponses mixtes et ajouter la recherche
Parfois, le modèle répond avec une phrase de texte et une image. Le raccourci output_image convient aux scripts simples, mais une fonction qui parcourt la liste steps gère tous les cas :
def save_outputs(interaction, prefix="gemini", ext="png"):
saved = []
for step in interaction.steps:
if step.type != "model_output":
continue
for block in step.content:
if block.type == "text":
print(block.text)
elif block.type == "image":
path = f"{prefix}_{len(saved) + 1}.{ext}"
with open(path, "wb") as f:
f.write(base64.b64decode(block.data))
saved.append(path)
return saved
La fonction renvoie une liste de chemins de fichiers. Une liste vide signifie que le modèle n’a envoyé que du texte, ce qui n’est pas une exception ; vérifiez-le avant de supposer qu’un fichier existe.
Ancrer les prompts avec la recherche
Certaines images dépendent de faits qui changent chaque jour : une infographie météo, un tableau de scores, un graphique de prix. Activez Google Search et le modèle peut récupérer des données en direct avant de dessiner :
interaction = client.interactions.create(
model="gemini-3.1-flash-image",
input="Create an infographic of this week's weather in Chicago",
tools=[{"type": "google_search"}],
generation_config={"thinking_level": "high"},
)
Le réglage thinking_level accepte "minimal" ou "high". Utilisez minimal lorsque la vitesse compte et que la mise en page est simple. Utilisez high lorsque le prompt demande une mise en page structurée en plusieurs parties.
💡 Chaque image renvoyée par l’API porte un filigrane SynthID, une marque invisible ajoutée par Google pour qu’on puisse identifier l’image comme générée par IA. Vous n’avez rien à ajouter vous-même.
Gérer les erreurs avant la production
Les appels d’image tendent à prendre plus de temps que les appels de texte, et les rafales de requêtes peuvent déclencher des limites de débit. Une petite fonction de relance vous évite la plupart des ennuis. Il relance en cas de HTTP 429, 500 et 503 et attend plus longtemps après chaque échec :
import time
def generate_with_retry(prompt, retries=4, **kwargs):
for attempt in range(retries):
try:
return client.interactions.create(
model="gemini-3.1-flash-image",
input=prompt,
**kwargs,
)
except Exception as exc:
status = getattr(exc, "status_code", None) or getattr(exc, "code", None)
if status not in (429, 500, 503) or attempt == retries - 1:
raise
time.sleep(2 ** attempt)
Selon la version du SDK, le code HTTP se trouve sur status_code ou sur code, donc la fonction vérifie les deux. Tout ce qui n’est pas réessayable, comme une mauvaise requête, est levé immédiatement pour que vous voyiez le vrai message.
Pour traiter une liste de prompts, lancez quelques tâches à la fois :
from multiprocessing.pool import ThreadPool
prompts = ["A bowl of oranges", "A lighthouse at dusk", "A forest road in fog"]
with ThreadPool(4) as pool:
results = pool.map(generate_with_retry, prompts)
Commencez avec quatre workers. Si la fonction de relance se déclenche sans cesse, descendez à deux avant d’augmenter votre quota.
Les prompts refusés demandent une autre habitude. La documentation de Google indique que les paramètres de sécurité personnalisés ne sont pas pris en charge dans l’Interactions API : vous ne pouvez donc pas assouplir les filtres depuis le code. Lorsqu’une réponse revient avec du texte et sans image, journalisez à la fois le prompt et le texte, puis réécrivez le prompt avec une description plus calme et plus concrète. Relancer le prompt identique change rarement la réponse et ne fait que perdre du temps.
3 erreurs courantes
Appeler un modèle retiré. Tout extrait contenant gemini-2.5-flash-image doit voir sa chaîne de modèle remplacée par une version actuelle.
Mettre aspect_ratio dans generation_config. Ce paramètre appartient à response_format, à côté de image_size.
Écrire la chaîne base64 sur le disque. Exécutez toujours base64.b64decode() d’abord, sinon le fichier ne s’ouvrira pas.
Si vous avez encore un ancien code qui appelle generate_content, Google indique que cette API reste prise en charge et qu’elle est désormais étiquetée comme héritée. Pour les nouveaux projets, l’Interactions API est celle que recommande la documentation de Google.
Surveiller les coûts
Les coûts évoluent avec le volume, donc faites le calcul avant une grande boucle. Cinq cents images 2K sur Flash coûtent 500 x 0,101 $, soit 50,50 $. Google propose aussi une tarification par lots, à environ la moitié du tarif standard, pour les traitements qui peuvent attendre :
Résolution
Standard
Lot
0.5K
0,045 $
0,022 $
1K
0,067 $
0,034 $
2K
0,101 $
0,050 $
4K
0,151 $
0,076 $
Les mêmes 500 images en 2K via le lot coûtent environ 25 $. Si personne n’attend le résultat, comme une mise à jour nocturne d’un catalogue, le lot est la voie la moins chère.
Utiliser Nano Banana Pro sur PicassoIA
Toutes les images n’ont pas besoin d’un script. Si vous voulez tester un prompt avant de dépenser des crédits API, ou confier le travail à un collègue qui n’écrit pas de Python, Nano Banana Pro sur PicassoIA est une façon sans code d’obtenir une sortie allant jusqu’à 4K avec la même famille de modèles Google.
Rédigez votre prompt. Utilisez le même style de liste de plans que précédemment : sujet, lumière, objectif.
Ajoutez des images de référence (facultatif). Le champ Image Input accepte jusqu’à 14 images qui orientent le style, la composition ou le sujet.
Choisissez un format. Sélectionnez parmi 11 préréglages, dont 16:9, 9:16, 4:5, 21:9 et match_input_image.
Choisissez une résolution.1K, 2K (la valeur par défaut) ou 4K.
Choisissez un format de fichier. JPG (par défaut) ou PNG.
Réglez le filtre de sécurité.block_only_high est la valeur par défaut et la plus permissive ; block_low_and_above est la plus stricte.
Générez et téléchargez. Relancez avec un prompt légèrement modifié pour comparer les versions.
Faire correspondre les réglages de l’API aux champs de la page
Si vous prototypez sur la page puis passez au code, les réglages correspondent presque un à un :
Champ PicassoIA
Équivalent dans l’API Python
Prompt
input (bloc texte)
Image Input
input (blocs image, base64)
aspect_ratio
response_format["aspect_ratio"]
resolution
response_format["image_size"]
output_format
response_format["mime_type"]
La famille Google sur PicassoIA ne se limite pas à un seul modèle. Nano Banana gère les retouches rapides, Nano Banana 2 Lite privilégie la vitesse, et Imagen 4 et Imagen 4 Ultra misent sur le détail photoréaliste. Faire passer le même prompt dans deux d’entre eux prend une minute et montre quel style convient à votre projet avant d’écrire la moindre ligne de code d’intégration.
Créez vos propres images dès aujourd’hui
Vous avez désormais tous les éléments : une installation fonctionnelle, une première image, le contrôle de la taille et du format, les retouches, une façon sûre de lire les sorties mixtes, une fonction de relance et une estimation de coûts fiable. Choisissez un petit travail, comme un en-tête de blog ou une vignette de produit, et menez-le de bout en bout cet après-midi.
Si vous préférez voir les résultats avant de toucher à un terminal, ouvrez Picasso IA, choisissez un modèle comme Nano Banana Pro, et saisissez le prompt que vous venez d’écrire pour votre script. Essayez trois variations, changez le format et comparez. Le meilleur prompt trouvé là-bas s’intègre directement dans le code Python ci-dessus.
Cette boucle, tester sur la page puis livrer en code, est la manière la plus rapide de trouver le style qui vous convient sans payer chaque essai. Ouvrez Picasso IA, lancez votre premier prompt, et voyez ce que vous pouvez créer avant la fin de l’après-midi.