freedge/backend/.env.example
ordinarthur 9dbd7e0ba9 feat(ai): quality-first recipe pipeline with structured outputs
Overhaul of the backend AI module to produce better recipes, better
images, more reliably, and cheaper.

New src/ai/ module:
- prompts.ts: long 'Chef Antoine' system prompt (~1500 tokens) with
  explicit originality rules, technical precision requirements, vocal
  transcription handling, and 3 few-shot style examples. Long enough
  to benefit from OpenAI's automatic prompt caching (-50% on cached
  portion from the 2nd call onward).
- recipe-generator.ts: uses Structured Outputs (json_schema strict).
  Rich schema: titre, description, origine_inspiration, ingredients
  with quantity/notes/complement flag, numbered etapes with per-step
  duration, conseils array, accord_boisson. No more JSON.parse crashes.
- image-generator.ts: switched from dall-e-3 to gpt-image-1 (medium
  quality by default). Much better photographic realism. Dedicated
  magazine-style prompt (editorial food photography, 45-deg overhead,
  natural light, stoneware). Slugify preserves extended Latin chars
  (cote-de-boeuf not c-te-de-b-uf).
- transcriber.ts: migrated from whisper-1 to gpt-4o-mini-transcribe
  (50% cheaper, better on French). Includes a context prompt to bias
  toward culinary vocabulary.
- cost.ts: centralized pricing table + helpers. Every OpenAI call now
  emits a structured log with model, durationMs, costUsd, usage, and
  cacheHit flag.

Plugin refactor:
- plugins/ai.ts now delegates to src/ai/* and only keeps the Fastify
  decoration glue + storage fallback for audio.
- OpenAI client configured with maxRetries=3, timeout=60s.
- Image generation runs in parallel with the recipe flatten/serialize
  step (minor speedup, ~0.5s).
- flattenRecipe() converts the rich structured recipe into the legacy
  flat RecipeData shape (for Prisma columns) while preserving the
  structured form in recipeData.structured.

Routes:
- recipes.ts stores the structured JSON in generatedRecipe (instead
  of the aplatissement lossy), enabling future frontends to render
  rich recipes with per-ingredient notes and step timers.

Env vars:
- OPENAI_TRANSCRIBE_MODEL, OPENAI_IMAGE_MODEL, OPENAI_IMAGE_QUALITY,
  OPENAI_IMAGE_SIZE, OPENAI_MAX_RETRIES, OPENAI_TIMEOUT_MS

Cost per recipe (estimated):
- Before: ~$0.044 (whisper $0.003 + 4o-mini $0.0004 + dall-e-3 $0.04)
- After : ~$0.018 (4o-mini-transcribe $0.0015 + 4o-mini $0.0004
  + gpt-image-1 medium $0.0165), ~-59%.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 08:46:18 +02:00

50 lines
1.3 KiB
Plaintext

# ---- Requis ----
DATABASE_URL="file:./prisma/dev.db"
JWT_SECRET="change-me-please-use-at-least-32-characters"
OPENAI_API_KEY="sk-..."
# ---- Serveur ----
PORT=3000
LOG_LEVEL=info
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
FRONTEND_URL=http://localhost:5173
# ---- IA ----
# Modèle texte (recette). Recommandé : gpt-4o-mini (rapide & cheap),
# ou gpt-4o pour un cran de qualité supplémentaire.
OPENAI_TEXT_MODEL=gpt-4o-mini
# Modèle de transcription audio.
# - gpt-4o-mini-transcribe : -50% par rapport à whisper-1, meilleur en français
# - whisper-1 : ancien, à éviter sauf compat
OPENAI_TRANSCRIBE_MODEL=gpt-4o-mini-transcribe
# Génération d'image
ENABLE_IMAGE_GENERATION=true
# - gpt-image-1 (recommandé) : qualité photo nettement supérieure à dall-e-3
# - dall-e-3 : ancien, à éviter
OPENAI_IMAGE_MODEL=gpt-image-1
# Pour gpt-image-1: low | medium | high
# Pour dall-e-3: standard | hd
OPENAI_IMAGE_QUALITY=medium
OPENAI_IMAGE_SIZE=1024x1024
# Robustesse OpenAI
OPENAI_MAX_RETRIES=3
OPENAI_TIMEOUT_MS=60000
# ---- Stripe (optionnel) ----
STRIPE_SECRET_KEY=
# ---- MinIO (optionnel — fallback local sinon) ----
MINIO_ENDPOINT=
MINIO_PORT=9000
MINIO_USE_SSL=false
MINIO_ACCESS_KEY=
MINIO_SECRET_KEY=
MINIO_BUCKET=freedge
MINIO_ALLOW_SELF_SIGNED=false
# ---- Email (optionnel) ----
RESEND_API_KEY=