Carte visuelle de la stack : site statique en edge, inference Koyeb, secrets Infisical, et boucle sft-wagmi pour les tiers CPU et GPU de Wagmi.
Cette page est la carte courte de la stack, avec schémas. Pour le récit complet (frugalité, souveraineté, RGPD, loi IA, coûts), voir Le site web est la démo.
Pourquoi cette forme ? Un seul codebase TypeScript reste portable. Les pages publiques coûtent peu au bord. L'inférence est bi-niveau : petit modèle CPU pour tous, grand modèle GPU lorsque l'authentification justifie le coût. Les modèles sont entraînés dans sft-wagmi, bakés dans des images Docker, et configurés via Infisical pour que dev, staging et prod ne divergent pas sur les secrets.
flowchart TB
visitor["Visiteur ou utilisateur connecte"]
subgraph edge ["Edge et runtime"]
cf["Cloudflare Pages statique et proxy API"]
web["Koyeb web : Next.js et llama-server CPU"]
gpu_svc["Koyeb GPU : wagmi-sft-14b scale-to-zero"]
end
subgraph app ["Application"]
ui["React 19, Assistant UI, next-intl"]
api["Routes API : chat, auth, health"]
end
subgraph data ["Donnees et configuration"]
inf["Secrets Infisical"]
pg[("PostgreSQL via Drizzle")]
sb["Supabase OTP email"]
end
subgraph factory ["Usine a modeles sft-wagmi"]
dexm_ds["Export JSONL dexm-one-page"]
hf_space["HF Space pipeline.py"]
hub["GGUF prives sur Hugging Face"]
hub_dh["Images Docker Hub"]
end
visitor --> cf
cf -->|proxy /api| web
visitor --> web
ui --> api
api --> pg
api --> sb
inf -.-> web
inf -.-> gpu_svc
api -->|anonyme| web
api -->|authentifie| gpu_svc
dexm_ds --> hf_space
hf_space --> hub
hub --> hub_dh
hub_dh --> web
hub_dh --> gpu_svc
| Mérite | Ce que cela nous apporte |
|---|---|
| Frugal | Marketing statique sur Cloudflare ; GPU facturé seulement quand le trafic auth le réveille |
| Souverain | Notre code, nos poids, endpoints compatibles OpenAI interchangeables |
| Auditable | Blog, datasets et workflows de déploiement dans des dépôts publics |
| Prudence | Validation Zod, rate limits, RAG BM25 sur le petit tier, portes release et AI Act |
Le chat choisit un tier d'inférence via la session Supabase, pas via un flag client opaque.
flowchart TD
start["POST /api/chat"]
session{"Session Supabase valide ?"}
anon["Tier anonyme"]
auth["Tier authentifie"]
rag["RAG BM25 sur wagmi-skills et ai.txt"]
cpu["CPU wagmi-sft 1.5B en loopback 127.0.0.1"]
cpu_first["Reponse CPU-first pendant le wake GPU"]
wake["GET LLM_GPU_WAKE_URL ou sonde mesh"]
gpu_ready{"Modele GPU disponible ?"}
gpu["GPU wagmi-sft-14b tier premium"]
start --> session
session -->|non| anon --> rag --> cpu
session -->|oui| auth
auth --> cpu_first --> cpu
auth --> wake --> gpu_ready
gpu_ready -->|oui| gpu
gpu_ready -->|non| cpu
Anonyme : toujours CPU (wagmi-sft dans le conteneur web). Authentifié : CPU-first par défaut (CHAT_AUTH_CPU_FIRST), puis bascule GPU lorsque /v1/models signale le modèle auth prêt. L'interface affiche le tier actif.
Les poids ne sont pas retouchés à la main. Le contenu et les garde-fous deviennent du JSONL dans dexm-one-page, puis sft-wagmi entraîne, évalue et exporte des GGUF pour les bakes Docker.
flowchart LR
content["Blog, wagmi-skills, ai.txt, notes Obsidian"]
gen["generate-wagmi-sft-dataset.ts"]
jsonl["datasets/wagmi-sft train et eval JSONL"]
sync["pnpm dataset:wagmi sync ou refresh"]
space["sft-wagmi HF Space Gradio"]
pipeline["pipeline.py preflight train eval redteam export"]
recurring["Cursor SDK recurring quotidien et hebdo"]
gguf["GGUF sur le Hub"]
docker["Docker build bake web et GPU"]
koyeb["Deploiement Koyeb"]
content --> gen --> jsonl --> sync --> space
recurring -.->|orchestre| space
space --> pipeline --> gguf --> docker --> koyeb
sft-wagmi (README) exécute Unsloth et TRL sur deux profils : small (1,5B, tier anonyme) et auth (14B, tier outils). Les étapes incluent eval_sft, eval_sft_rag, redteam et export-merged avant conversion GGUF. L'automation récurrente (automation/cursor-sdk, scripts/hf/recurring_runner.py) planifie des runs légers quotidiens qwen/small et des runs hebdomadaires plus lourds qwen/auth sur l'infrastructure Hugging Face, avec des portes pass ou fail avant qu'un build soit candidat release.
Sur le dépôt site :
pnpm run dataset:wagmi:refresh # regenere et synchronise le JSONL vers sft-wagmi/data/
| Couche | Choix |
|---|---|
| App | Next.js 16, React 19, TypeScript strict, Tailwind, Radix |
| Chat | Vercel AI SDK, Assistant UI, ancrage BM25 local-rag.ts |
| Secrets | Infisical UE (dev / staging / prod) |
| Données | PostgreSQL, Drizzle, auth OTP Supabase |
| Contenu | Content Collections, Markdown dans content/blog/ |
| Images | Docker Hub (jeanbapt/deal-ex-machina-web, images GPU) |
| Staging | Koyeb web et llama-gpu, scale-to-zero selon config |
| Front prod | Cloudflare Pages statique et Functions proxy vers Koyeb |
| Qualité | Biome, Vitest, Playwright, Lighthouse CI, porte AI Act au deploy |