Aller au contenu principal

Variations et itérations

Mis à jour le 29 juillet 2026

Variations et itérations

Obtenir l’image parfaite du premier coup est rare. Le travail réel consiste à produire des variations, à les comparer, puis à resserrer progressivement le prompt jusqu’au rendu souhaité. Cette leçon vous donne les trois outils de cette méthode : la variation par relance, la variation contrôlée par modification du prompt, et l’itération par raffinement successif.

Générer des variations d’un même concept

La méthode la plus simple consiste à relancer la génération avec le même prompt : GPT Image produit un résultat différent à chaque appel. C’est utile en début d’exploration, quand vous ne savez pas encore ce que vous cherchez et que vous voulez voir l’éventail des interprétations possibles d’une idée.

from openai import OpenAI
import base64

client = OpenAI()

def generer_variations(prompt: str, n_variations: int, prefix: str):
    """Génère plusieurs variations indépendantes d'un même prompt."""
    paths = []
    for i in range(n_variations):
        response = client.images.generate(
            model="gpt-image-1",
            prompt=prompt,
            size="1024x1024",
            quality="medium",
            response_format="b64_json"
        )

        path = f"{prefix}_v{i+1}.png"
        data = base64.b64decode(response.data[0].b64_json)
        with open(path, "wb") as f:
            f.write(data)
        paths.append(path)
        print(f"Variation {i+1} sauvegardée : {path}")

    return paths


variations = generer_variations(
    prompt="Illustration d'un robot jardinier arrosant des fleurs, style enfantin et coloré",
    n_variations=5,
    prefix="robot_jardinier"
)

Variations par modification du prompt

L’approche précédente vous livre du hasard ; celle-ci vous rend le contrôle. Vous fixez un sujet invariant — ici une tasse de café fumante sur une table en bois — et vous ne faites bouger qu’une seule dimension, l’ambiance. Les cinq résultats deviennent alors comparables entre eux, puisque vous savez exactement ce qui les distingue. C’est la différence entre cinq essais et une expérience.

from openai import OpenAI
import base64

client = OpenAI()

base_prompt = "Tasse de café fumante sur une table en bois"

ambiances = [
    "lumière matinale douce, tons chauds",
    "ambiance café parisien, noir et blanc",
    "style pop art, couleurs saturées",
    "minimaliste scandinave, fond blanc",
    "atmosphère cosy d'hiver, bokeh de guirlandes",
]

for i, ambiance in enumerate(ambiances):
    prompt = f"{base_prompt}, {ambiance}"
    response = client.images.generate(
        model="gpt-image-1",
        prompt=prompt,
        size="1024x1024",
        quality="medium",
        response_format="b64_json"
    )

    path = f"cafe_ambiance_{i+1}.png"
    data = base64.b64decode(response.data[0].b64_json)
    with open(path, "wb") as f:
        f.write(data)
    print(f"Ambiance : {ambiance[:30]}... → {path}")

Itération par raffinement du prompt

Quand le résultat n’est pas satisfaisant, la bonne réaction n’est pas de relancer en espérant mieux, mais d’ajouter la contrainte qui manquait. La série ci-dessous montre cette progression sur un cas concret : « Un logo pour une startup fintech » ne dit rien au modèle, la deuxième itération borne le nombre de couleurs et le fond, la troisième nomme la métaphore visuelle et la palette, la quatrième descend jusqu’aux codes hexadécimaux et à l’épaisseur du trait. À chaque passe, l’espace des résultats possibles se rétrécit et la reproductibilité augmente.

from openai import OpenAI
import base64

client = OpenAI()

iterations = [
    # Itération 1 : prompt de base
    "Un logo pour une startup fintech",

    # Itération 2 : ajout de contraintes visuelles
    "Un logo pour une startup fintech, design minimaliste, deux couleurs maximum, fond transparent",

    # Itération 3 : précision du style
    (
        "Logo minimaliste pour une startup fintech, icône géométrique abstraite "
        "évoquant la croissance, palette bleu marine et vert émeraude, sans texte, vectoriel"
    ),

    # Itération 4 : ajustements fins
    (
        "Logo minimaliste pour une startup fintech, icône géométrique abstraite : "
        "deux flèches entrelacées formant un losange, bleu marine (#1B2A4A) et "
        "vert émeraude (#2ECC71), trait fin 2px, fond blanc, rendu vectoriel net, centré"
    ),
]

for i, prompt in enumerate(iterations):
    response = client.images.generate(
        model="gpt-image-1",
        prompt=prompt,
        size="1024x1024",
        quality="high",
        response_format="b64_json"
    )

    path = f"logo_iteration_{i+1}.png"
    data = base64.b64decode(response.data[0].b64_json)
    with open(path, "wb") as f:
        f.write(data)
    print(f"Itération {i+1} : {prompt[:60]}...")
    print(f"  → {path}\n")

Pipeline d’itération automatisé

Sur un projet un peu long, la mémoire humaine ne suffit plus : au bout de quinze images vous ne savez plus quel prompt a produit laquelle. Le pipeline suivant structure le travail en rounds, génère plusieurs variantes par round, nomme les fichiers de façon traçable et conserve l’historique complet des prompts dans un JSON. C’est ce fichier d’historique qui fait la valeur du dispositif : il vous permet de revenir en arrière et de capitaliser d’un projet à l’autre.

from openai import OpenAI
import base64
import json

client = OpenAI()

def pipeline_iteration(brief: str, n_rounds: int = 3, n_par_round: int = 3):
    """
    Pipeline d'itération : génère plusieurs variantes par round,
    garde un historique des prompts et résultats.
    """
    historique = []
    prompt_courant = brief

    for round_num in range(1, n_rounds + 1):
        print(f"\n{'='*50}")
        print(f"ROUND {round_num} — Prompt : {prompt_courant[:80]}...")
        print(f"{'='*50}")

        images_round = []
        for i in range(n_par_round):
            response = client.images.generate(
                model="gpt-image-1",
                prompt=prompt_courant,
                size="1024x1024",
                quality="medium",
                response_format="b64_json"
            )

            path = f"pipeline_r{round_num}_v{i+1}.png"
            data = base64.b64decode(response.data[0].b64_json)
            with open(path, "wb") as f:
                f.write(data)
            images_round.append(path)
            print(f"  Variante {i+1} : {path}")

        historique.append({
            "round": round_num,
            "prompt": prompt_courant,
            "images": images_round
        })

        # Affiner le prompt pour le round suivant
        if round_num < n_rounds:
            prompt_courant += ", plus de détails, meilleure composition"

    # Sauvegarder l'historique
    with open("pipeline_historique.json", "w") as f:
        json.dump(historique, f, indent=2, ensure_ascii=False)

    print(f"\nHistorique sauvegardé : pipeline_historique.json")
    return historique


pipeline_iteration(
    brief="Illustration d'une librairie indépendante vue de l'extérieur, soir d'automne, style Ghibli",
    n_rounds=3,
    n_par_round=3
)

Comparer les variations dans un catalogue

Ouvrir neuf PNG un par un dans un visualiseur ne permet aucune comparaison sérieuse. Générez plutôt une page HTML qui les affiche côte à côte, images encodées en base64 pour que le fichier soit autonome et partageable tel quel avec un client ou un directeur artistique.

import base64
from pathlib import Path
from glob import glob

def generer_catalogue(images: list[str], titre: str, output: str = "catalogue.html"):
    """Crée une page HTML avec toutes les images côte à côte."""
    html_parts = [
        '<!DOCTYPE html><html><head><meta charset="utf-8">',
        f'<title>{titre}</title>',
        '<style>',
        'body { background: #111; color: #fff; font-family: sans-serif; padding: 2rem; }',
        '.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1rem; }',
        '.card { background: #222; border-radius: 8px; overflow: hidden; }',
        '.card img { width: 100%; display: block; }',
        '.card p { padding: 0.5rem 1rem; font-size: 0.85rem; color: #aaa; }',
        '</style></head><body>',
        f'<h1>{titre}</h1><div class="grid">',
    ]

    for img_path in images:
        with open(img_path, "rb") as f:
            b64 = base64.b64encode(f.read()).decode()
        html_parts.append(f'<div class="card">')
        html_parts.append(f'<img src="data:image/png;base64,{b64}" />')
        html_parts.append(f'<p>{Path(img_path).name}</p></div>')

    html_parts.append('</div></body></html>')

    with open(output, "w") as f:
        f.write("\n".join(html_parts))
    print(f"Catalogue généré : {output}")


images = sorted(glob("pipeline_r*_v*.png"))
generer_catalogue(images, "Variations — Librairie Ghibli")

La discipline de l’itération

Quelques principes séparent une itération productive d’un tâtonnement coûteux. Ne changez qu’un seul paramètre à la fois, sans quoi vous ne saurez jamais lequel a amélioré le résultat. Gardez un historique de vos prompts et de vos rendus, comme le fait le pipeline ci-dessus, pour capitaliser au lieu de repartir de zéro à chaque projet. Travaillez en quality: low pendant toute la phase d’exploration et ne passez en high que pour le rendu final, sous peine de payer au prix fort des images que vous jetterez. Lorsque vous cherchez simplement de la diversité rapide, préférez un appel unique avec le paramètre n à une boucle de requêtes. Enfin, nommez vos fichiers de manière descriptive : c’est un détail trivial le premier jour, décisif au bout de deux cents images.

Appliquez maintenant cet enchaînement complet sur un sujet de votre choix — logo, illustration ou photo de produit. Générez trois variantes avec un prompt initial, affinez ce prompt à la lumière des résultats, générez trois nouvelles variantes, puis produisez le catalogue HTML comparatif des six images.