Architecture DALL-E en production
Intégrer DALL-E dans une application SaaS nécessite une architecture robuste qui gère les coûts, la latence, le stockage des images et la modération du contenu.
Architecture recommandée
Client → API Backend → Queue de jobs → Worker DALL-E → CDN/Storage
↓
Modération → Rejet si inappropriéEndpoint de génération
// app/api/generate-image/route.ts
import OpenAI from "openai";
const openai = new OpenAI();
export async function POST(req: Request) {
const { prompt, size = "1024x1024", quality = "standard" } = await req.json();
// Validation et modération du prompt
const moderation = await openai.moderations.create({ input: prompt });
if (moderation.results[0].flagged) {
return Response.json({ error: "Contenu inapproprié" }, { status: 400 });
}
// Génération
const response = await openai.images.generate({
model: "dall-e-3",
prompt,
n: 1,
size,
quality,
response_format: "url" // ou "b64_json"
});
const imageUrl = response.data[0].url;
const revisedPrompt = response.data[0].revised_prompt;
// Télécharger et stocker dans votre CDN
const storedUrl = await uploadToStorage(imageUrl);
return Response.json({ url: storedUrl, revisedPrompt });
}Stockage des images
Les URLs retournées par DALL-E expirent après 1 heure. Vous devez systématiquement les télécharger et les stocker :
async function uploadToStorage(temporaryUrl: string): Promise<string> {
// Télécharger l'image depuis l'URL temporaire OpenAI
const response = await fetch(temporaryUrl);
const buffer = await response.arrayBuffer();
// Uploader vers votre storage (S3, Cloudflare R2, Supabase Storage...)
const key = `generated/${Date.now()}-${crypto.randomUUID()}.png`;
await s3.putObject({
Bucket: "my-bucket",
Key: key,
Body: Buffer.from(buffer),
ContentType: "image/png"
});
return `https://cdn.monapp.com/${key}`;
}Gestion des coûts
Pricing (par image) - Standard 1024x1024 : $0.040 - Standard 1792x1024 : $0.080 - HD 1024x1024 : $0.080 - HD 1792x1024 : $0.120
Stratégies d'optimisation
// Rate limiting par utilisateur
const DAILY_LIMIT = 10; // images par jour par user
// Cache de prompts similaires
const cacheKey = hashPrompt(normalizedPrompt);
const cached = await cache.get(cacheKey);
if (cached) return cached;
// Qualité adaptative selon le plan
const quality = user.plan === "premium" ? "hd" : "standard";File d'attente pour les pics de charge
// Producteur : ajouter à la queue
await queue.add("generate-image", {
userId: user.id,
prompt,
size,
quality,
webhookUrl: "/api/webhooks/image-ready"
});
// Worker : traiter la queue
worker.process("generate-image", async (job) => {
const image = await openai.images.generate({ ... });
const storedUrl = await uploadToStorage(image.data[0].url);
await notifyUser(job.data.userId, storedUrl);
});Modération et sécurité
Pré-modération (avant génération) - Utilisez l'API Moderation d'OpenAI sur le prompt - Bloquez les termes interdits spécifiques à votre contexte - Limitez le nombre de tentatives rejetées
Post-modération (après génération)
- Vérifiez le revised_prompt retourné par DALL-E
- Loggez toutes les générations pour audit
- Implémentez un système de signalement utilisateur
Bonnes pratiques production
- Toujours stocker : Ne servez jamais les URLs temporaires OpenAI au client
- Retry avec backoff : L'API peut retourner des erreurs 500 temporaires
- Timeout : Prévoyez 30-60 secondes pour la génération
- Métadonnées : Stockez le prompt, la date, l'utilisateur avec chaque image
- Fallback : Prévoyez une image par défaut en cas d'échec