Intégration d'une API de génération d'images : modèles compatibles OpenAI
Intégrez la génération d'images via des endpoint compatibles OpenAI, gérez les éditions, bornez n et la taille, et persistez correctement les médias temporaires avec gpt-image-2.
L'intégration d'une API de génération d'images consiste à appeler depuis le code produit un endpoint stable — généralement POST /v1/images/generations et souvent POST /v1/images/edits — tout en sortant de chaque client le choix du modèle, les identifiants, les quotas et le stockage des médias. Avec une passerelle compatible OpenAI, les applications envoient un prompt et, éventuellement, model, n, size, quality ainsi que des champs GPT Image comme output_format, puis décodent les charges utiles en base64. Les réponses URL historiques ne doivent être gérées que lorsqu'un modèle les prend encore en charge. Ce guide présente un chemin d'intégration adapté à la production à partir des routes déjà exposées par cette passerelle, sans inventer de prix fournisseur ni de notes de qualité.
Forme minimale correcte pour GPT Image
Utilisez une seule URL de base authentifiée, un Bearer token émis par votre passerelle et le contrat GPT Image actuel d'OpenAI. La documentation officielle présente gpt-image-2 comme le modèle d'image principal actuel ; les générations GPT Image renvoient data[].b64_json. Le paramètre response_format concerne les anciens modèles DALL·E, pas GPT Image.
curl -sS https://YOUR_GATEWAY/v1/images/generations \
-H "Authorization: Bearer $GATEWAY_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "A product photo of a ceramic mug on a wooden table, soft window light",
"n": 1,
"size": "1024x1024",
"output_format": "png"
}' | jq -r '.data[0].b64_json' | base64 --decode > mug.png
Traitez la réponse comme un média éphémère accompagné de métadonnées de facturation, et non comme une ressource produit durable. Si le produit doit conserver les images après l'expiration d'une URL temporaire du fournisseur, dans le cas de modèles historiques ou d'adaptateurs non OpenAI, téléchargez-les immédiatement dans un object storage que vous contrôlez, ou utilisez le chemin de persistance de l'atelier image personnel, autorisé selon la propriété utilisateur.
Revérifiez toujours les champs propres au modèle dans le guide OpenAI de génération d'images et la référence de l'API Images. Google documente séparément la génération d'images native de Gemini sur ai.google.dev. Une passerelle ne remplace pas ces documentations : elle normalise l'accès.
Pourquoi intégrer via une passerelle plutôt que plusieurs SDK
Les équipes produit échouent généralement pour des raisons opérationnelles, pas à cause de la qualité du modèle :
- chaque service détient une clé fournisseur différente
- les expériences de prompt contournent les budgets
- des URL CDN temporaires sont stockées en base puis cessent de fonctionner
- le nombre d'images
nou la résolution multiplie le coût sans validation - les environnements personnels et les projets d'équipe partagent une même clé, ce qui détruit l'attribution des coûts
Le modèle de passerelle multi-fournisseurs, présenté plus largement dans passerelle LLM multi-fournisseurs et passerelle API compatible OpenAI, stabilise les clients tandis que les opérateurs associent des alias stables aux canaux, imposent les quotas et écrivent les journaux d'usage. Pour les médias, le même plan de contrôle doit aussi répondre à la question : « qui pourra télécharger cette ressource plus tard ? »
Endpoint et champs de requête importants
Générations
POST /v1/images/generations est le point d'entrée text-to-image. Les champs courants du DTO de requête image de ce dépôt sont les suivants :
| Champ | Rôle avec GPT Image / la passerelle |
|---|---|
model | Préférez l'alias stable gpt-image-2, ou votre alias associé ; les anciens ID gpt-image-1* suivent le calendrier de dépréciation d'OpenAI vers gpt-image-2 |
prompt | instruction textuelle obligatoire |
n | nombre facultatif ; le type pointeur préserve la présence JSON, mais cette passerelle normalise n=0, ou l'absence de n, à 1 avant la facturation |
size | résolution comme 1024x1024, 1536x1024, 1024x1536 ; GPT Image 2 documente aussi des règles WIDTHxHEIGHT plus larges |
quality | jeton de qualité propre au fournisseur lorsqu'il est pris en charge |
output_format | png / jpeg / webp pour les familles GPT Image |
output_compression | compression pour les formats qui la prennent en charge |
response_format | DALL·E historique uniquement (url ou b64_json) ; non pris en charge par GPT Image, qui renvoie toujours du base64 |
background, moderation, stream | extensions propres à la famille de modèles lorsque l'adaptateur les prend en charge |
user | étiquette d'utilisateur final pour le suivi des abus |
Ne supposez pas que tous les champs fonctionnent avec tous les modèles. Validez les modèles réellement activés dans votre environnement et la documentation actuelle du fournisseur.
Éditions
POST /v1/images/edits est la surface d'édition et d'inpainting. Les intégrations envoient généralement des champs multipart pour l'image source, un masque facultatif et le prompt. Le code produit doit :
- accepter les uploads utilisateur dans un stockage temporaire avec limite de taille
- normaliser les types MIME avant l'appel à la passerelle
- conserver la même authentification et le même propriétaire de facturation que pour les générations
- ne jamais journaliser les octets bruts des images dans les logs applicatifs
Si le produit a seulement besoin de « régénérer avec un prompt plus précis », les générations peuvent suffire. Ajoutez les éditions lorsque les utilisateurs doivent préserver la composition ou les ressources de marque.
La sécurité de facturation fait partie de l'intégration
La génération d'images comporte de nombreux multiplicateurs. Un client hostile ou défectueux qui fixe n à une valeur absurde peut transformer une requête HTTP en catastrophe comptable. Dans ce code :
- la validation refuse un
nsupérieur àMaxImageN(128) avant le calcul du quota - un
nabsent ou égal à0est normalisé à1: préserver la présence du pointeur ne signifie pas accepter zéro image - les chemins de pré-consommation et de règlement doivent toujours refuser les charges négatives ou saturées
- les ratios de qualité et de taille ne deviennent des multiplicateurs qu'après validation
Règles produit :
- fixez la valeur UI par défaut de
nà1 - n'acceptez jamais un
nfourni par l'utilisateur sans limite supérieure inférieure au maximum de la plateforme - affichez le coût estimé avant une génération de plusieurs variantes
- si la pré-consommation échoue, faites échouer l'UX ; ne placez pas la tâche en file de manière optimiste sur un autre portefeuille
TypeScript : générer, décoder, persister
type ImageGenResponse = {
data: Array<{ b64_json?: string; url?: string; revised_prompt?: string }>;
};
async function generatePng(prompt: string, model = "gpt-image-2") {
const res = await fetch(`${process.env.GATEWAY_BASE}/v1/images/generations`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.GATEWAY_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model,
prompt,
n: 1,
size: "1024x1024",
output_format: "png",
}),
});
if (!res.ok) throw new Error(await res.text());
const body = (await res.json()) as ImageGenResponse;
const b64 = body.data?.[0]?.b64_json;
if (!b64) {
// Legacy/provider-adapter path only: some non-GPT models may still return url.
if (body.data?.[0]?.url) {
return { kind: "url" as const, url: body.data[0].url, revised: body.data[0].revised_prompt };
}
throw new Error("no image payload");
}
const bytes = Buffer.from(b64, "base64");
// upload bytes to object storage under the billing owner's key prefix
return { kind: "bytes" as const, bytes, revised: body.data[0].revised_prompt };
}
Python : même contrat avec décodage explicite
import base64
import os
from pathlib import Path
import requests
def generate_and_store(prompt: str, model: str = "gpt-image-2") -> Path:
r = requests.post(
f"{os.environ['GATEWAY_BASE']}/v1/images/generations",
headers={"Authorization": f"Bearer {os.environ['GATEWAY_KEY']}"},
json={
"model": model,
"prompt": prompt,
"n": 1,
"size": "1024x1024",
"output_format": "webp",
"output_compression": 80,
},
timeout=120,
)
r.raise_for_status()
b64 = r.json()["data"][0]["b64_json"]
out = Path("/tmp/out.webp")
out.write_bytes(base64.b64decode(b64))
return out
Préférez b64_json, valeur par défaut de GPT Image, lorsque vous contrôlez le stockage et souhaitez un seul aller-retour. Ne mentionnez url que comme comportement d'un modèle historique ou d'un adaptateur fournisseur. Ne supposez jamais qu'une URL reste valide indéfiniment.
Atelier image personnel et atelier vidéo d'équipe
Ce dépôt expose un atelier image limité à la portée personnelle / session / token :
- UI : atelier image
- API utilisateur sous
/api/user/image-workbench/*pour presets, modèles, exécutions, ressources, génération et édition - variantes par clé API sous
/api/image-workbench/*pour générer, éditer et télécharger - outils d'administration des modèles sous
/api/image-workbench/admin/* - les clés d'objet et l'historique utilisent la propriété utilisateur
L'arborescence actuelle ne contient aucune route /api/teams/:team_id/image-workbench limitée à une équipe. N'affirmez pas qu'il existe un historique image d'équipe ou des ressources image limitées à un projet, sauf si votre fork les ajoute.
En revanche, l'atelier vidéo inclut des routes équipe/projet sous /api/teams/:team_id/video-workbench. Si les responsables produit demandent « un historique image partagé comme pour la vidéo », il s'agit d'une fonctionnalité manquante, et non d'une capacité déjà fournie par l'atelier image. La facturation multi-locataires des appels bruts /v1/images/* suit toujours le propriétaire associé au token ; consultez l'architecture de passerelle LLM multi-locataires.
Utilisez l'atelier lorsque les opérateurs ou designers ont besoin d'un historique interactif et de presets. Utilisez les appels bruts /v1/images/* lorsque des services backend génèrent des ressources par programme. Les deux chemins doivent partager les mêmes alias de modèles et champs de journaux d'usage pour l'attribution ultérieure.
Liste de contrôle du cycle de vie des médias
- Soumettre avec une clé de passerelle limitée, pas une clé fournisseur.
- Valider
n, en se rappelant qu'ici0devient1, la taille et la longueur du prompt avant l'envoi. - Enregistrer l'ID de requête ou de journal d'usage pour le support.
- Décoder
b64_json, ou récupérer une fois une URL historique, puis persister les clés d'object storage selon votre politique de rétention. - Autoriser les téléchargements ultérieurs par propriétaire : utilisateur pour les ressources de l'atelier image, propriétaire de facturation pour les tâches API que vous stockez vous-même.
- Faire expirer ou modérer à nouveau les ressources lorsque la politique produit l'exige.
- Observer les taux d'échec et les coûts par modèle dans votre stack de monitoring.
Si l'étape 4 est ignorée, les défauts produit apparaissent plusieurs semaines plus tard comme des miniatures cassées, pas comme des erreurs API.
Notes d'ingénierie des prompts et du produit
- Séparez l'intention système, comme les règles de marque, du prompt utilisateur dans la couche applicative ; l'API Images utilise généralement une chaîne
promptunique, composez-la avec soin. - Stockez le prompt final envoyé, pas uniquement le brouillon de l'UI, car les fournisseurs peuvent renvoyer
revised_prompt. - Limitez les tâches image simultanées par utilisateur ; les retries peuvent facilement déclencher un fan-out accidentel.
- Gérez les HTTP 429/5xx avec des retries bornés et des clés clientes idempotentes lorsque la stack les prend en charge (retries et idempotence des API LLM).
- Pour les expériences multi-modèles, changez seulement l'alias
modelaprès avoir vérifié la prise en charge de la taille et de la qualité ; ne dupliquez pas tout le client. - Préférez
gpt-image-2dans les exemples par défaut ; associez explicitement les anciens alias si un canal les expose encore.
Échecs d'intégration fréquents
| Symptôme | Cause probable | Correction |
|---|---|---|
| Images vides après un « succès » | Le client cherche url avec GPT Image | Lire b64_json et le décoder |
| Consommation soudaine du quota | n non borné ou tempête de retries | Borner n, dédupliquer les retries |
n=0 devait signifier « simulation » | La passerelle normalise 0 → 1 | Ne pas effectuer l'appel au lieu d'envoyer zéro |
| Fonctionne en compte personnel, échoue avec une clé d'équipe | La clé n'a pas l'autorisation projet ou utilise le mauvais groupe de modèles | Corriger les droits du token d'équipe ; ne pas supposer que l'atelier image est limité à l'équipe |
| Endpoint d'édition en 400 | Noms de champs multipart ou taille de masque incorrects | S'aligner sur le contrat de formulaire fournisseur/passerelle |
| Modèle introuvable | Alias non associé sur le canal | Associer l'alias stable à l'ID upstream dans la configuration du canal |
Lecture associée
Sources
- Guide OpenAI de génération d'images
- Référence OpenAI Images API
- Dépréciations OpenAI, anciens GPT Image vers
gpt-image-2 - Génération d'images Google Gemini
- OWASP Top 10 for LLM Applications
Questions sur les échecs
Faut-il appeler OpenAI, Gemini et les autres avec trois SDK ?
Non si le produit n'a besoin que d'un seul contrat client. Préférez le chemin compatible OpenAI de la passerelle pour les générations et éditions, et réservez les SDK natifs aux fonctionnalités que la passerelle ne mappe pas encore.
response_format=url est-il sûr pour une base de production ?
C'est un mauvais choix par défaut pour GPT Image, où il n'est pas pris en charge et où la réponse est toujours en base64. Pour les anciens modèles qui renvoient encore des URL, considérez-les uniquement comme des pointeurs temporaires et réhébergez les images avant de les afficher sur des pages durables.
Quelle est une valeur sûre par défaut pour n ?
Commencez à 1 dans l'UX de production. Augmentez uniquement lorsque le produit exige explicitement plusieurs variantes, et gardez un maximum produit strict inférieur au maximum de la plateforme, 128 dans ce code. N'envoyez pas n=0 en espérant une opération vide.
Les requêtes image ont-elles besoin du streaming ?
Généralement non. Activez-le uniquement si l'adaptateur et l'UI profitent des aperçus partiels ; sinon, conservez le chemin simple requête/réponse.
Comment partager un historique d'images entre équipes sans fuite de ressources ?
Avec la passerelle actuelle, l'historique de l'atelier image est personnel. Pour une bibliothèque partagée, construisez un partage applicatif au-dessus des octets que vous stockez, ou utilisez les clés projet d'équipe uniquement pour facturer /v1/images/* tout en appliquant votre propre ACL aux objets persistés.
Premier raccordement en production
Raccordez un job backend à POST /v1/images/generations avec model=gpt-image-2, n=1, output_format=png, décodage base64 et upload immédiat dans l'object storage. Confirmez que le journal d'usage indique le propriétaire de facturation attendu, puis ajoutez un deuxième alias de modèle seulement après avoir vérifié la compatibilité taille/qualité dans la configuration du canal.