11 Commits

Author SHA1 Message Date
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
ordinarthur
fc3dfe83c9 refactor(backend): migrate from JavaScript to TypeScript
- tsconfig.json strict mode (noImplicitAny, strictNullChecks, noUnused*)
- Replace nodemon with tsx (watch + run TS directly)
- Build script (tsc -> dist/) and typecheck script
- Fastify decorator types in types/fastify.d.ts (prisma, openai,
  stripe, googleClient, auth helpers, ai helpers, request.user)
- Typed route handlers with generic Body/Params
- Strict null checks on Prisma results and env vars
- Stripe plugin now optional (no-op if STRIPE_SECRET_KEY missing)
- Delete dead utils/errors.js (empty) and utils/resend.js
  (contained a hardcoded Resend API key, unused)
- Add @types/bcrypt, @types/nodemailer, typescript-eslint
- ESLint upgraded to typescript-eslint flat config
- deploy.sh: run prisma generate, migrate deploy, backend build

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 22:36:21 +02:00
ordinarthur
0134390f5e refactor: cleanup, security hardening & frontend dedup
Backend:
- Remove malicious crypto dep; use node:crypto
- Add helmet + rate-limit (100 req/min)
- CORS whitelist via CORS_ORIGINS env
- Validate required env vars on boot (fail fast)
- Health endpoint + clean shutdown (SIGINT/SIGTERM)
- Multipart limits (15MB / 1 file)
- Fix findUnique composite where bug (use findFirst)
- Wrap JSON.parse(generatedRecipe) in try/catch
- Isolate DALL-E best-effort; ENABLE_IMAGE_GENERATION toggle
- Lazy MinIO client, safe TLS handling
- Uniform fastify.hashPassword/comparePassword
- Proper audio cleanup on delete
- ESLint flat config, Prettier, .env.example, .editorconfig

Frontend:
- Delete 10 orphan/duplicate components
- Remove orphan pages/recipe/, data/recipes.ts, root src/
- Fix /reset-password route order (was unreachable)
- Remove unused ky dep

Docs:
- README rewritten to match real routes and env vars

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 21:00:54 +02:00
Arthur Barre
9b98b3c0c6 fix minio2 2025-03-16 19:44:18 +01:00
Arthur Barre
fe493fe053 fix minio 2025-03-16 19:43:11 +01:00
Arthur Barre
8b6d76fdea add minio storage 2025-03-15 13:11:24 +01:00
Arthur Barre
b311e76bf3 add reset password from mail 2025-03-13 23:03:29 +01:00
Arthur Barre
7c2374f0b3 change mail + change password ok ! 2025-03-13 22:31:10 +01:00
Arthur Barre
223b593495 add more data + image on recipe 2025-03-13 22:17:39 +01:00
Arthur Barre
191b8a4da2 add google sso 2025-03-11 13:05:13 +01:00
Arthur Barre
958a778f85 init a fonctional prototype 2025-03-10 00:24:26 +01:00