API OpenAI Image Generation en Python : exemple pas à pas
Envoyez un prompt depuis Python, récupérez une image en base64 et enregistrez-la sur le disque. Ce guide utilise les modèles GPT Image actuels et montre comment la taille, la qualité et le format modifient le résultat. Il ajoute ensuite les modifications par masque, les aperçus en streaming, les lots asynchrones et un suivi des coûts.
La plupart des tutoriels sur le point de terminaison d’image d’OpenAI s’arrêtent à « voici une URL ». Cela fonctionnait avec DALL-E. Ce n’est plus le cas avec les modèles GPT Image, qui renvoient des données base64 et rien d’autre, si bien que le script copié en premier plante souvent sur result.data[0].url. Ce guide part d’un script qui fonctionne, puis l’enrichit avec les tailles, les niveaux de qualité, les modifications par masque, les aperçus en streaming, les lots asynchrones et un petit suivi des coûts.
Les paramètres, noms de modèles et tarifs ci-dessous proviennent de la documentation actuelle d’OpenAI sur la génération d’images et de sa page de tarification, consultées le 2026-10-06. Lorsqu’un chiffre est susceptible de changer, le texte le signale.
Avant d’écrire le moindre code
Trois éléments doivent être en place avant que la première requête aboutisse : un nom de modèle, le SDK installé et une organisation OpenAI vérifiée. Ce dernier point piège la plupart des comptes neufs, car les modèles GPT Image renvoient une erreur d’accès tant que la vérification n’est pas terminée dans les paramètres de la console développeur.
Choisir un modèle
Voici les modèles GPT Image qu’OpenAI tarifie aujourd’hui. Les cinq sont aussi disponibles sur PicassoIA, ce qui est pratique pour tester un prompt avant d’écrire la moindre ligne de code.
Créez un secret de projet dans le tableau de bord OpenAI, puis exposez-le sous forme de variable d’environnement. Le SDK le lit automatiquement, si bien que le secret n’apparaît jamais dans votre fichier source.
# macOS / Linux
export OPENAI_API_KEY="sk-..."
# Windows PowerShell
$env:OPENAI_API_KEY = "sk-..."
💡 Astuce : gardez le secret hors des notebooks que vous comptez partager et hors de l’historique git. S’il fuite, révoquez-le dans le tableau de bord et créez-en un nouveau.
Votre première image en Python
Le script minimal
Voici le script complet. Exécutez-le et un PNG apparaît à côté du script.
import base64
from pathlib import Path
from openai import OpenAI
client = OpenAI()
result = client.images.generate(
model="gpt-image-2.5-flare",
prompt="A ceramic bowl of ripe peaches on a linen cloth, soft window light, 50mm photograph",
size="1536x1024",
quality="medium",
)
image_bytes = base64.b64decode(result.data[0].b64_json)
Path("peaches.png").write_bytes(image_bytes)
Quatre arguments font le travail. model choisit le moteur, prompt décrit l’image, size fixe les dimensions en pixels, et quality arbitre entre vitesse, coût et détail. Tout le reste a une valeur par défaut raisonnable, et le format de sortie est PNG, sauf si vous en demandez un autre.
Rédiger des prompts solides
Un prompt qui fonctionne dans une démo peut s’effondrer au bout de cinquante images générées en boucle. Quatre habitudes gardent les résultats stables :
Commencez par le sujet, puis le décor, la lumière et l’objectif. « Un bol en céramique de pêches mûres posé sur un linge en lin, lumière douce venant de la fenêtre à gauche, photographie 50 mm » fait mieux qu’une liste d’adjectifs.
Mettez entre guillemets tout texte qui doit apparaître sur l’image, et limitez-le à un ou deux mots.
Dites ce qu’il faut éviter en termes positifs. « Mur blanc et nu » fonctionne mieux que « pas d’encombrement ».
Changez une seule chose à la fois. Si vous modifiez en même temps le sujet, la lumière et la taille, vous ne saurez pas quel changement a aidé.
Pourquoi la réponse est en base64
Les modèles GPT Image renvoient toujours du base64. L’option response_format="url" acceptée par DALL-E n’est pas prise en charge, donc result.data[0].url n’existe pas, et l’image arrive directement dans b64_json. Trois habitudes en découlent :
Décodez une fois, écrivez sur le disque.base64.b64decode vous donne des octets bruts que vous pouvez enregistrer, importer ou confier à Pillow.
Hébergez le fichier vous-même. Si un blog ou une application a besoin d’un lien public, transférez les octets vers votre propre stockage (S3, R2, un CDN) et conservez cette URL.
Évitez le disque pour les aperçus rapides. Construisez une data URI avec f"data:image/png;base64,{b64}" et insérez-la dans une balise <img>.
💡 Vous migrez un ancien code ? Rechercher .url et response_format dans votre projet permet de trouver presque toutes les lignes à modifier.
Taille, qualité et format de sortie
Ces paramètres déterminent ce que vous obtenez et ce que cela coûte. Voici la liste complète publiée par la documentation :
Paramètre
Valeurs acceptées
Remarques
size
1024x1024, 1536x1024, 1024x1536, ou WIDTHxHEIGHT personnalisé
Les côtés personnalisés doivent être des multiples de 16, le format compris entre 1:3 et 3:1, le plus long côté jusqu’à 3 840 px, et le nombre total de pixels entre 655 360 et 8 294 400
quality
low, medium, high, auto
Les modèles 2.5 listent aussi xhigh et max
output_format
png (par défaut), jpeg, webp
Choisissez webp ou jpeg pour des fichiers plus légers
output_compression
0 à 100
JPEG et WebP uniquement
background
transparent, opaque, auto
La transparence nécessite un format avec canal alpha, donc utilisez PNG ou WebP
n
Entier
Plusieurs images pour une même requête
moderation
auto (par défaut), low
low applique un filtrage plus léger
stream, partial_images
Booléen, 0 à 3
Images d’aperçu pendant le rendu de l’image finale
Quelques règles empiriques :
Paysage et portrait.1536x1024 et 1024x1536 conviennent à la plupart des formats de blog et de réseaux sociaux. Pour un vrai 16:9, demandez 2048x1152 : les deux côtés sont des multiples de 16 et le nombre de pixels reste bien dans la plage autorisée.
Itérez à petit prix, finalisez en qualité. Testez vos prompts à quality="low", puis relancez le meilleur résultat à high. Vous payez les tokens de sortie, et une qualité supérieure en produit davantage.
Choisissez le format selon la destination. Gardez PNG pour la retouche et la transparence, passez à webp avec output_compression=85 pour les pages qui doivent se charger vite.
Modifier des images existantes avec des masques
Modifier une image
images.edit prend un fichier source et un prompt décrivant la modification. Passez une liste de fichiers lorsque vous voulez combiner plusieurs références.
with open("living-room.png", "rb") as photo:
edited = client.images.edit(
model="gpt-image-2.5-sunburst",
image=photo,
prompt="Swap the grey sofa for a green velvet armchair, keep the window light unchanged",
)
Path("living-room-edit.png").write_bytes(base64.b64decode(edited.data[0].b64_json))
Décrivez aussi clairement ce qui doit rester identique que ce qui doit changer. Les modèles dérivent lorsque le prompt ne nomme que l’élément nouveau.
Ajouter un masque
Un masque limite la modification à une seule zone. C’est un PNG avec canal alpha, aux mêmes dimensions que la source. Les pixels entièrement transparents marquent la zone à repeindre ; tout ce qui est opaque est protégé. Pillow en crée un en quelques lignes :
from PIL import Image, ImageDraw
base = Image.open("living-room.png").convert("RGBA")
mask = Image.new("RGBA", base.size, (0, 0, 0, 255)) # opaque: keep
ImageDraw.Draw(mask).rectangle((620, 380, 1180, 900), fill=(0, 0, 0, 0)) # transparent: repaint
mask.save("mask.png")
with open("living-room.png", "rb") as photo, open("mask.png", "rb") as hole:
edited = client.images.edit(
model="gpt-image-2.5-sunburst",
image=photo,
mask=hole,
prompt="A green velvet armchair with a wooden side table, matching the room's light",
)
Le masque est une indication, pas une découpe nette. Les bords peuvent déborder légèrement, prévoyez donc une petite marge autour de l’objet à remplacer.
Aperçus en streaming et lots
Images partielles pendant l’attente
Les rendus en haute qualité peuvent prendre du temps. Avec stream=True et partial_images, l’API envoie des images d’aperçu avant l’image finale, si bien qu’une interface peut afficher une progression au lieu d’un simple spinner.
stream = client.images.generate(
model="gpt-image-2.5-flare",
prompt="A vintage red bicycle leaning on a brick wall, golden hour, 35mm photograph",
size="1536x1024",
quality="high",
stream=True,
partial_images=2,
)
for event in stream:
if event.type == "image_generation.partial_image":
Path(f"preview-{event.partial_image_index}.png").write_bytes(base64.b64decode(event.b64_json))
else:
Path("final.png").write_bytes(base64.b64decode(event.b64_json))
Les aperçus peuvent augmenter le nombre de tokens, donc comparez usage avec et sans streaming avant de l’activer pour chaque requête.
Lots asynchrones sans erreurs de limite
Pour une liste de prompts, AsyncOpenAI associé à un sémaphore maintient sous contrôle le nombre de requêtes en cours :
import asyncio
from openai import AsyncOpenAI
client = AsyncOpenAI(max_retries=4, timeout=180)
gate = asyncio.Semaphore(3)
async def render(index: int, prompt: str) -> Path:
async with gate:
result = await client.images.generate(
model="gpt-image-2.5-flare", prompt=prompt, size="1536x1024", quality="low",
)
path = Path(f"batch-{index:02d}.png")
path.write_bytes(base64.b64decode(result.data[0].b64_json))
return path
async def main(prompts: list[str]) -> list[Path]:
return await asyncio.gather(*(render(i, p) for i, p in enumerate(prompts)))
Un sémaphore limite la concurrence, pas le nombre d’images par minute. Avec les niveaux d’utilisation bas, la limite par minute est atteinte en premier, donc augmentez max_retries et laissez le SDK temporiser. Lorsque personne n’attend le résultat, le point de terminaison Batch est pris en charge par ces modèles et facture les tokens de sortie à moitié prix.
Coûts, limites et erreurs
Tarifs en tokens par modèle
OpenAI tarifie ces modèles au token, et non à l’image, et ne publie pas de tableau par image pour les modèles actuels. Tarifs par 1M de tokens :
Modèle
Entrée texte
Entrée image
Sortie image
Sortie image (Batch)
gpt-image-2.5-flare
$5.00
$8.00
$30.00
$15.00
gpt-image-2.5-sunburst
$5.00
$8.00
$30.00
$15.00
gpt-image-2
$5.00
$8.00
$30.00
$15.00
gpt-image-1
$5.00
$10.00
$40.00
$20.00
gpt-image-1-mini
$2.00
$2.50
$8.00
$4.00
La qualité et la taille modifient le nombre de tokens de sortie qu’une image utilise, ce qui explique qu’un même prompt puisse coûter des montants très différents à low et à high.
Suivre les dépenses dans le code
La réponse contient un objet usage avec les décomptes de tokens. Convertissez-le en dollars après chaque appel et vous ne serez jamais surpris par une facture :
Les limites de débit dépendent de votre niveau d’utilisation. Pour gpt-image-2.5-flare, la page du modèle indique ces limites au moment de la rédaction :
Niveau
Tokens par minute
Images par minute
Niveau 1
100K
5
Niveau 2
250K
20
Niveau 3
800K
50
Niveau 4
3M
150
Niveau 5
8M
250
Erreurs que vous rencontrerez
Symptôme
Cause probable
Correction
Erreur d’accès au premier appel
Organisation non vérifiée
Terminez la vérification dans la console développeur
AttributeError sur .url
Les modèles GPT Image renvoient uniquement du base64
Lisez plutôt b64_json
« Bad request » mentionnant la modération
Le prompt ou l’image d’entrée a déclenché un filtre de sécurité
Reformulez le prompt et évitez les sujets sensibles
« Bad request » sur size
Côté non multiple de 16, ratio supérieur à 3:1, ou nombre de pixels hors plage
Ajustez les dimensions
429 (limite de débit)
Limite du niveau atteinte
Réduisez la concurrence, augmentez max_retries ou utilisez Batch
Timeout
La haute qualité peut prendre du temps
Augmentez timeout côté client
Interceptez les trois erreurs qui comptent en production :
Avant de dépenser votre budget API pour tester des prompts, lancez-les dans un navigateur. GPT Image 2 sur PicassoIA rend du texte lisible dans les images, prend en charge les fonds transparents, accepte des images de référence et produit jusqu’à 10 variantes par exécution.
Prototyper des prompts sans code
Ouvrez la page du modèle et rédigez votre prompt. Mettez entre guillemets tout texte qui doit apparaître dans l’image.
Réglez la qualité sur low pour les brouillons. Passez à high pour le rendu final.
Choisissez un format : 3:2 ou 2:3 correspondent à 1536x1024 et 1024x1536, et 16:9 donne un cadre panoramique.
Choisissez le format de sortie. WebP est le format par défaut, PNG conserve proprement la transparence.
Réglez le nombre d’images entre 1 et 10, puis lancez la génération.
Importez des images de référence si vous voulez modifier plutôt que créer à partir de zéro.
Les champs du formulaire correspondent à l’appel Python, si bien qu’une recette qui fonctionne dans le navigateur passe directement dans le code :
Champ PicassoIA
Argument Python
aspect_ratio
size
quality
quality
output_format
output_format
output_compression
output_compression
background
background
moderation
moderation
number_of_images
n
input_images
image (dans images.edit)
Un champ facultatif accepte votre propre clé OpenAI ; laissez-le vide et le proxy de PicassoIA gère la requête.
Deux autres habitudes en valent la peine. D’abord, rédigez le prompt avec un grand modèle de langage : collez une idée brute dans GPT 5 ou Claude Sonnet 4.6 et demandez trois variantes photographiques avec objectif, lumière et cadrage. Ensuite, passez le même prompt dans PicassoIA Image et Seedream 4.5 pour voir quel style convient à votre projet. Pour les modifications qui ne demandent aucun code, PicassoIA Image Editor Pro traite directement les retouches photo dans le navigateur.
L’API développeur de PicassoIA
Si votre pipeline nécessite un autre fournisseur, PicassoIA dispose de sa propre API développeur, au format similaire à Replicate :
URL de base :https://api.picassoia.com/v1
Authentification : un jeton Bearer qui commence par pia_sk_
Déroulement : créez une prédiction avec POST /v1/models/{owner}/{name}/predictions, interrogez GET /v1/predictions/{id}, puis lisez le résultat
Limite : 5 prédictions simultanées par compte
Les tâches sont asynchrones, donc la boucle création puis interrogation remplace l’appel bloquant unique que vous avez écrit plus haut. Vérifiez les exigences du forfait sur la page de l’API PicassoIA avant de construire dessus.
Créez vos propres images dès aujourd’hui
Vous disposez maintenant d’un pipeline fonctionnel : installer le SDK, vérifier l’organisation, demander une image, décoder le base64, régler size et quality, modifier avec un masque, diffuser des aperçus, regrouper en lots avec des limites et suivre les dépenses. Le moyen le plus rapide d’améliorer les résultats reste le volume. Rédigez dix prompts, lancez-les à low, gardez les deux meilleurs et refaites le rendu de ceux-ci à high.
Si vous voulez tester des prompts avant de toucher à l’API, ouvrez GPT Image 2 sur PicassoIA, générez quelques variantes et comparez-les avec d’autres modèles dans la bibliothèque de modèles PicassoIA. Une fois que vous avez des images fixes qui vous plaisent, la collection d’effets de PicassoIA peut y ajouter du mouvement et du style. Choisissez un sujet qui vous tient à cœur, rédigez un prompt détaillé et voyez ce qui en sort.