Lección 9 — Projet final

L'assistant de fiches produit, de bout en bout

5 min de lectura

Este contenido aún no está traducido. Se muestra la versión original.

L'assistant de fiches produit, de bout en bout

L'architecture complète

flowchart TB
  F["produits.txt : une description par ligne"] --> M["main() : lit le fichier"]
  M --> R["rediger_fiche(client, description)"]
  R --> C["build_contents : exemples + demande"]
  R --> G["build_config : prompt système, schéma, réglages"]
  C --> API["client.models.generate_content"]
  G --> API
  API -->|"429 / 5xx"| W["attente puis nouvel essai"] --> API
  API --> V["FicheProduit.model_validate_json"]
  V --> O["JSON sur la sortie standard"]
FichierRôle
fiche_produit.pyle script : prompt, exemples, schéma, appel, réessais, ligne de commande
test_fiche_produit.py8 tests avec un faux client, sans clé ni réseau
produits.txt3 descriptions fictives pour l'essai
requirements.txtles dépendances
files/.env.examplemodèle de fichier .env (valeurs factices)

Étape 1 : les tests, sans clé

Un test automatisé est une petite fonction qui vérifie un comportement et échoue bruyamment s'il change. Ici, un faux client (mock) imite client.models.generate_content : il renvoie une réponse préparée à l'avance, ou lève une erreur 429 pour simuler un quota dépassé.

files/test_fiche_produit.py
def test_reessaie_sur_429(monkeypatch):
    monkeypatch.setattr(fp.time, "sleep", lambda s: None)   # pas de vraie attente
    quota = errors.ClientError(429, {"error": {"message": "quota", "status": "RESOURCE_EXHAUSTED"}})
    client = fake_client(quota, json.dumps(FICHE))
    assert fp.rediger_fiche(client, "Gourde").titre
    assert len(client.models.appels) == 2                   # un échec, puis un succès
terminal
pytest -q

Étape 2 : le vrai modèle

terminal
cp .env.example .env        # puis collez votre clé dans .env
python fiche_produit.py --fichier produits.txt > fiches.json

Pourquoi les tests utilisent-ils un faux client plutôt que la vraie API ?

Une fiche affiche « garantie 5 ans » alors que la description n'en parle pas. Par quoi commencer ?

Résultat obtenu

Exécution réelle le 2026-10-15. D'abord les tests :

pytest -v (extrait)
test_fiche_produit.py::test_config_reprend_le_prototype PASSED           [ 12%]
test_fiche_produit.py::test_temperature_et_top_p_optionnels PASSED       [ 25%]
test_fiche_produit.py::test_exemples_puis_demande PASSED                 [ 37%]
test_fiche_produit.py::test_rediger_fiche_valide_le_json PASSED          [ 50%]
test_fiche_produit.py::test_json_incomplet_refuse PASSED                 [ 62%]
test_fiche_produit.py::test_description_vide_refusee PASSED              [ 75%]
test_fiche_produit.py::test_reessaie_sur_429 PASSED                      [ 87%]
test_fiche_produit.py::test_ne_reessaie_pas_sur_400 PASSED               [100%]
============================== 8 passed in 0.30s ===============================

Puis le catalogue de 3 produits avec gemini-3.5-flash (troisième fiche, environ 18 secondes pour les trois) :

fiches.json (extrait)
{
  "titre": "Lampe de bureau LED à bras articulé et port USB-C",
  "accroche": "Illuminez efficacement votre espace de travail au quotidien.",
  "description": "Cette lampe de bureau LED est dotée d'un bras articulé pour orienter la lumière à votre convenance. Elle propose 3 températures de couleur afin de personnaliser votre éclairage selon vos besoins. Son port USB-C intégré apporte une praticité appréciable au quotidien.",
  "points_forts": ["Bras articulé pratique", "3 températures de couleur", "Port USB-C intégré"],
  "mots_cles": ["lampe de bureau", "led", "bras articule", "usb-c"]
}

Les trois fiches respectent le schéma et n'ajoutent aucune caractéristique absente des descriptions. Un défaut à corriger : le mot-clé « bras articule » a perdu son accent. C'est typiquement le genre de détail qu'on règle par une règle (« garde les accents dans les mots-clés ») puis un nouvel essai.

Exercice final

Faites évoluer l'assistant : (1) ajoutez la règle sur les accents, (2) vérifiez dans le code que chaque titre fait au plus 70 caractères et, sinon, levez une erreur, (3) ajoutez le test correspondant.

Voir la solution
files/fiche_produit.py (modifications)
SYSTEM_INSTRUCTION += "\nGarde les accents dans les mots-clés."

def rediger_fiche(client, description: str, essais: int = 4) -> FicheProduit:
    ...
            fiche = FicheProduit.model_validate_json(response.text)
            if len(fiche.titre) > 70:
                raise ValueError(f"Titre trop long ({len(fiche.titre)} caractères)")
            return fiche
files/test_fiche_produit.py (ajout)
def test_titre_trop_long_refuse():
    longue = dict(FICHE, titre="x" * 71)
    with pytest.raises(ValueError):
        fp.rediger_fiche(fake_client(json.dumps(longue)), "Gourde")

La règle du prompt réduit le problème ; la vérification dans le code le garantit. Le test empêche qu'un futur changement retire cette garantie sans que personne ne s'en aperçoive.

Pour aller plus loin

Prochaine étape : Premiers pas avec l'API Gemini en Python, pour maîtriser le streaming, les conversations, le comptage des tokens et le passage à Vertex AI sur Google Cloud.

Je sais faire

  • Lancer les tests du lab sans clé
  • Générer les fiches d'un fichier de descriptions avec le vrai modèle
  • Repérer un défaut dans une sortie et le corriger par le prompt ou par le code
  • Ajouter une vérification et son test