Génération d’images par modèle avec Genviso et BetterToken

Une méthode concrète pour séparer l’exploration visuelle de l’exécution backend et versionner un prompt prêt pour la production.

Une image réussie ne constitue pas encore un processus de production. Pour un seul visuel, on peut réécrire le prompt, examiner plusieurs réponses et choisir manuellement. Avec des centaines de SKU, cette habitude devient une suite coûteuse d’essais. Chaque modification de lumière, d’angle ou de matière déclenche une nouvelle requête, tandis que la raison du bon résultat reste dans la tête de son auteur.

Il vaut mieux séparer le travail en deux boucles. L’équipe teste d’abord la direction visuelle et consigne les règles reproductibles. Le backend insère ensuite les données métier dans le modèle validé, envoie les requêtes, conserve les résultats et traite les erreurs. L’exploration créative reste hors de la file de production et une retouche de composition n’impose plus de modifier le serveur.

Pourquoi le réglage du prompt dans le code devient incontrôlable

Trop de variables sont liées

Le modèle réagit simultanément au sujet, à l’environnement, à la lumière, à la position de la caméra, à la matière, à la profondeur de champ et à la palette. Pour photographier un flacon de sérum, le résultat varie nettement entre :

  • une vue de face et une plongée à 45 degrés ;
  • une lumière dure directionnelle et une lumière diffuse ;
  • un verre aux reflets marqués et une surface mate ;
  • un fond en travertin, en métal ou en papier uni ;
  • un rendu macro de 85 mm et une composition grand-angle.

Si plusieurs paramètres changent ensemble, personne ne sait quelle formulation a aidé. S’ils changent un à un, le nombre de requêtes augmente vite. Un backend utilisant BetterToken peut exécuter le modèle par Image API, mais lancer la file trop tôt ne fait que reproduire une hypothèse visuelle non validée.

Chaque usage a sa grammaire visuelle

Une fiche produit réclame une silhouette lisible, des reflets maîtrisés et de la place pour la mise en page. Une illustration 3D obéit à d’autres contraintes de forme et de matière. Une affiche sociale dépend de la hiérarchie, du contraste et des zones sûres. Un prompt universel accumule généralement des adjectifs contradictoires.

Mieux vaut conserver plusieurs familles :

skincare_product luxury_watch food_photography 3d_illustration social_poster

Chaque famille définit ses champs obligatoires et ses critères d’acceptation. L’application choisit le bon modèle selon la catégorie, puis remplit les données du produit ou de la campagne.

Exploration et production suivent des règles différentes

L’exploration accepte de nombreuses variantes et une comparaison subjective. La production exige un contrat prévisible, une version, des nouvelles tentatives limitées, un identifiant de tâche et une décision d’acceptation claire.

modifier le prompt dans le code → envoyer une requête API → ouvrir l’image → modifier de nouveau le code → envoyer une autre requête

Cette boucle ne possède aucun point d’approbation visuelle. Toute discussion de design finit donc par toucher le backend et sa file de tâches.

Architecture : de l’hypothèse visuelle au fichier dans le CMS

Pendant l’exploration, l’équipe utilise Genviso pour comparer des options dans sa galerie visuelle de prompts, tester la composition, la lumière et le style, puis conserver la structure qui fonctionne. Pendant l’exécution serveur, l’application passe par BetterToken avec la Base URL compatible OpenAI et la propre API Key de l’utilisateur, injecte les données, appelle un modèle disponible et enregistre le résultat. Le passage entre les étapes est une version du Prompt Template, et non une image choisie ou des consignes orales.

Pour tester cette frontière avant de connecter une file, créez votre propre API Key, exécutez une requête de contrôle avec le modèle approuvé et rapprochez aussitôt son modèle, son statut et son débit réel dans le Dashboard. Le trajet serveur est ainsi validé sans transformer l’exploration visuelle en requêtes de production.

exploration visuelle ↓ validation du Prompt Template ↓ variables et contraintes figées ↓ données PIM / CMS / SKU ↓ requête Image API du backend ↓ fichier, statut et métadonnées ↓ acceptation visuelle

Chaque transition produit un artefact vérifiable :

ÉtapeRésultatCondition de sortie
ExplorationVariantes retenues et rejetéesLes paramètres influents sont compris
ValidationPrompt avec variables nomméesIl fonctionne sur plusieurs produits représentatifs
IntégrationFonction de rendu et schémaLes champs requis sont validés avant l’API
TestUn fichier stocké et une traceLe fichier s’ouvre et modèle/statut sont corrects
ProductionTâche avec template_id, version et job_idLes tentatives sont bornées et le résultat correspond au SKU

Étape 1 : transformer la décision visuelle en modèle

Une structure initiale pour une photographie cosmétique peut être :

Commercial studio product photography of {subject}. Environment: {environment} Visual style: {visual_style} Lighting: {lighting} Composition: {composition} Color palette: {color_palette} Crisp reflections, premium material texture, high-end commercial editorial photography.

L’ordre et les dimensions visuelles restent stables. Les valeurs de subject, environment, visual_style, lighting, composition et color_palette évoluent séparément.

Avant de transmettre le modèle aux développeurs, fixez quatre éléments :

  1. Champs obligatoires. Sans subject ou composition, aucune requête ne doit partir.
  2. Valeurs autorisées. Si trois angles sont validés, utilisez un enum plutôt qu’un texte libre du CMS.
  3. Combinaisons interdites. Un emballage transparent sur un miroir peut nécessiter un autre modèle.
  4. Critères d’acceptation. La silhouette reste lisible, le logo n’est pas déformé, le produit n’est pas coupé et le fond convient à la mise en page.

Conservez le prompt près d’un contrat lisible par la machine :

{ "template_id": "skincare_product_v3", "required_variables": [ "subject", "environment", "visual_style", "lighting", "composition", "color_palette" ], "output_size": "1024x1024" }

La version dans template_id garantit la reproductibilité. Si la lumière ou la composition change, les nouvelles tâches utilisent la version suivante ; les ressources existantes restent liées à l’ancienne.

Étape 2 : connecter le modèle au backend

Pour un premier test, il faut le SDK Python officiel openai, votre propre BetterToken API Key et un Model ID actuel consulté dans la documentation Image API. Placez la clé et le modèle dans l’environnement :

python -m pip install openai export BETTERTOKEN_API_KEY="your_api_key_here" export BETTERTOKEN_IMAGE_MODEL="current_image_model_id"

N’insérez jamais une vraie clé dans le dépôt, le prompt, une capture ou les journaux. En production, utilisez un gestionnaire de secrets et des clés distinctes selon l’application ou l’environnement.

Cet exemple rend le modèle, envoie une requête et enregistre un PNG depuis b64_json :

import base64 import os from pathlib import Path from typing import Mapping from openai import OpenAI client = OpenAI( base_url="https://www.bettertoken.ai/v1", api_key=os.environ["BETTERTOKEN_API_KEY"], ) def render_product_prompt(variables: Mapping[str, str]) -> str: return f""" Commercial studio product photography of {variables['subject']}. Environment: {variables['environment']} Visual style: {variables['visual_style']} Lighting: {variables['lighting']} Composition: {variables['composition']} Color palette: {variables['color_palette']} Crisp reflections, premium material texture, high-end commercial editorial photography. """.strip() product = { "subject": "frosted amber glass serum bottle with a minimalist gold dropper", "environment": "organic travertine pedestal surrounded by subtle water ripples", "visual_style": "high-end botanical skincare editorial", "lighting": "warm directional morning rim light with soft diffused fill", "composition": "centered 85mm macro product photography with shallow depth of field", "color_palette": "earthy amber, warm beige and subtle gold", } response = client.images.generate( model=os.environ["BETTERTOKEN_IMAGE_MODEL"], prompt=render_product_prompt(product), size="1024x1024", n=1, ) image_base64 = response.data[0].b64_json if not image_base64: raise RuntimeError("Image API response does not contain b64_json") output_path = Path("serum-product.png") output_path.write_bytes(base64.b64decode(image_base64)) print(f"Saved: {output_path}")

L’appel client.images.generate(...) et le décodage de b64_json suivent le contrat actuel du SDK. Le modèle vient de BETTERTOKEN_IMAGE_MODEL, ce qui permet de le changer sans réécrire le Prompt Template ni la logique métier.

Boucle minimale d’une tâche par lots

Le bloc suivant est un pseudocode d’intégration volontairement explicite. save_job, generate_image et ApiError représentent les adaptateurs du stockage et du client API ; ce ne sont pas des méthodes supplémentaires du SDK.

MAX_ATTEMPTS = 3 RETRYABLE_STATUS = {429, 500, 502, 503, 504} for sku in sku_rows: variables = validate_variables(sku) # avant tout appel API prompt = render_product_prompt(variables) job_id = uuid4().hex prompt_hash = sha256(prompt.encode()).hexdigest() save_job(job_id=job_id, sku_id=sku["id"], template_id="skincare_product_v3", prompt_hash=prompt_hash, status="pending") for attempt in range(1, MAX_ATTEMPTS + 1): save_job(job_id=job_id, status="running", attempt=attempt) try: result = generate_image(prompt) except ApiError as error: if error.status_code in {400, 401}: save_job(job_id=job_id, status="failed", error_code=error.status_code) break if error.status_code not in RETRYABLE_STATUS or attempt == MAX_ATTEMPTS: save_job(job_id=job_id, status="failed", error_code=error.status_code) break sleep(min(2 ** attempt, 8)) continue except TimeoutError: save_job(job_id=job_id, status="unknown", error_code="timeout") break # vérifier Dashboard et stockage avant un nouvel envoi if not result.b64_json: save_job(job_id=job_id, status="failed", error_code="empty_output") break output_path = persist_png(job_id, result.b64_json) save_job(job_id=job_id, status="succeeded", output_path=output_path, model=result.model, attempt=attempt) break

Le job_id local relie le SKU, le modèle et le fichier, mais il ne rend pas la requête distante idempotente. Après un timeout, gardez l’état unknown, recherchez la requête par heure dans le Dashboard et vérifiez le stockage avant de décider d’un seul nouvel envoi.

Ordre de diagnostic

SymptômePremière vérificationCorrectionNouvelle validation
400Variables requises, Model ID actuel et size acceptéCorriger les données ou le paramètre ; ne pas répéter automatiquementLancer un SKU de contrôle et ouvrir le PNG
401Variable de clé chargée, propriété de la clé et protocoleRemplacer ou recréer la clé sans la journaliserEnvoyer la requête minimale et retrouver son statut dans le Dashboard
429Concurrence et rythme des tâchesSuspendre les nouvelles tâches, réduire la concurrence, appliquer un backoff bornéLaisser passer une requête puis rétablir la charge progressivement
5xxHeure et nombre de tentativesRépéter seulement jusqu’à MAX_ATTEMPTS ; conserver heure et statutTester une requête après une pause sans changer le modèle approuvé
TimeoutDashboard et stockageConserver unknown ; ne pas supposer l’échecSans trace ni fichier, autoriser un seul renvoi avec le même job_id local
b64_json vide ou échec du décodageFormat de réponse, modèle et paramètres actuelsConserver l’erreur sans donnée de clé et corriger lecture ou configurationRéessayer un SKU et vérifier que le PNG s’ouvre

À ajouter avant une génération par lots

Valider les données avant la requête

Un material vide, un balisage inattendu dans product_name ou un texte libre à la place d’une palette validée modifie le prompt. Contrôlez les champs requis, leur longueur et les valeurs autorisées. Conservez le hash final, template_id et l’identifiant du SKU avec la tâche.

Borner les nouvelles tentatives

Une nouvelle tentative après un timeout peut créer une deuxième image même si l’application n’a pas reçu la première réponse. Définissez un maximum, appliquez un délai progressif et attribuez un job_id. Ne répétez pas indéfiniment les erreurs 400, 401 ou de configuration : corrigez d’abord les données, la clé ou le modèle.

Séparer acceptation technique et visuelle

HTTP 200 et un PNG valide prouvent le succès technique. La composition, la déformation du produit et la cohérence de marque sont vérifiées séparément. La tâche automatique conserve le fichier et les métadonnées ; l’étape suivante applique les critères visuels.

Rapprocher la requête de l’usage

Après la génération de contrôle, retrouvez la requête dans le Dashboard grâce à l’heure. Vérifiez modèle, statut et débit ; les champs disponibles couvrent les tokens d’entrée, de sortie et de cache. Le Dashboard conserve les métadonnées d’usage et de dépense, pas le prompt ou la réponse complets. Consultez la page actuelle des modèles et prix pour le budget, puis la trace de requête pour le coût réel du test.

Exemple de flux pour un catalogue

PIM / base SKU ↓ catégorie → template_id ↓ nom / matière / couleur / fond ↓ validation des champs ↓ rendu du Prompt Template ↓ tâche avec job_id ↓ Image API ↓ stockage objet ↓ acceptation visuelle ↓ CMS / médiathèque

Le prompt devient un objet de production versionné. Il est possible d’identifier le modèle ayant créé chaque fichier, de comparer les rejets par version et d’annuler une modification sans refaire toute l’intégration.

Liste de contrôle avant le lancement

  • Le modèle a été testé sur des produits représentatifs et des cas limites.
  • template_id, variables obligatoires et critères d’acceptation sont définis.
  • L’API Key reste hors du code et des journaux.
  • Le Model ID vient de l’environnement ou de la configuration.
  • Une requête de test produit un fichier valide de la taille attendue.
  • Les erreurs 400/401 imposent une correction avant une nouvelle requête.
  • Les erreurs 429/5xx disposent de tentatives limitées.
  • Chaque tâche correspond à un SKU, un job_id, une version et un emplacement.
  • Validation technique et acceptation visuelle sont séparées.
  • Modèle, statut et coût du test ont été vérifiés dans le Dashboard.

Comment la répartition des rôles facilite la collaboration

Genviso prend en charge la boucle interactive : trouver une direction visuelle, comparer les prompts et valider le modèle avant transmission aux développeurs. BetterToken prend en charge la boucle serveur : API Key, connexion compatible OpenAI, appel d’un modèle disponible et enregistrement de l’usage. Les équipes partagent un contrat unique : Prompt Template, variables, version et critères d’acceptation.

Pour intégrer le modèle approuvé dans un backend opérationnel et mesurer le coût sur un SKU représentatif, créez votre propre API Key, exécutez la requête minimale de la référence Image API, puis vérifiez modèle, statut et débit dans le Dashboard avant de connecter la file.

Prêt à optimiser votre workflow LLM ?

Connectez vos modèles via une API unique, gérez les clés et maîtrisez vos dépenses d’IA.