adopt: état déployé sur M4M64c adopté comme source de vérité (remote-first, 2026-11-01)
31 changed files +20,001 −0
added
.env.example
+12 −0
@@ -0,0 +1,12 @@ | |||||
| 1 | +# Chat SPBoucher AI — copy to .env.local (dev) or .env.production (node). Never commit real values. | ||||
| 2 | +DATABASE_URL=postgres://chat_spb:CHANGE_ME@127.0.0.1:5432/chat_spboucher | ||||
| 3 | +SESSION_SECRET=CHANGE_ME_64_hex_chars # openssl rand -hex 32 | ||||
| 4 | +DATA_DIR=./data # uploads + generated files (mode 600) | ||||
| 5 | +OPENAI_API_KEY= | ||||
| 6 | +ANTHROPIC_API_KEY= | ||||
| 7 | +TAVILY_API_KEY= # optional: web search / page extraction tools | ||||
| 8 | +PYTHON_BIN=python3 # sandboxed python tool | ||||
| 9 | +APP_URL=https://chat.spboucher.ai | ||||
| 10 | +SESSION_TTL_DAYS=30 | ||||
| 11 | +MAX_UPLOAD_MB=50 | ||||
| 12 | +BENCHMARKS_DIR=./benchmarks | ||||
added
.env.production
+12 −0
@@ -0,0 +1,12 @@ | |||||
| 1 | +NODE_ENV=production | ||||
| 2 | +PORT=8500 | ||||
| 3 | +HOSTNAME=0.0.0.0 | ||||
| 4 | +DATABASE_URL=postgres://chat_spb:5efb1a670099bf3ba7584d379634b8d2a2a74ddfe270982b@127.0.0.1:5432/chat_spboucher | ||||
| 5 | +SESSION_SECRET=616e8f5bc0ff53785292f78d11536c95b68cb8ddf82d0c98db12f4a0ef333e22 | ||||
| 6 | +DATA_DIR=/Users/simon-pierreboucher/apps/chat-spboucher-ai/data | ||||
| 7 | +OPENAI_API_KEY=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 | ||||
| 8 | +ANTHROPIC_API_KEY=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 | ||||
| 9 | +TAVILY_API_KEY=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 | ||||
| 10 | +PYTHON_BIN=/opt/homebrew/bin/python3 | ||||
| 11 | +APP_URL=https://chat.spboucher.ai | ||||
| 12 | +BENCHMARKS_DIR=/Users/simon-pierreboucher/apps/chat-spboucher-ai/benchmarks | ||||
added
.gitignore
+9 −0
@@ -0,0 +1,9 @@ | |||||
| 1 | +node_modules | ||||
| 2 | +.env | ||||
| 3 | +.env.local | ||||
| 4 | +.env.*.local | ||||
| 5 | +.next | ||||
| 6 | +data/ | ||||
| 7 | +uploads/ | ||||
| 8 | +*.log | ||||
| 9 | +.DS_Store | ||||
added
.mldignore
+9 −0
@@ -0,0 +1,9 @@ | |||||
| 1 | +node_modules/ | ||||
| 2 | +.next/ | ||||
| 3 | +data/ | ||||
| 4 | +.env | ||||
| 5 | +.env.local | ||||
| 6 | +.env.production | ||||
| 7 | +e2e-shots/ | ||||
| 8 | +tsconfig.tsbuildinfo | ||||
| 9 | +.DS_Store | ||||
added
AGENTS.md
+9 −0
@@ -0,0 +1,9 @@ | |||||
| 1 | +<!-- BEGIN:nextjs-agent-rules --> | ||||
| 2 | + | ||||
| 3 | +## This is NOT the Next.js you know | ||||
| 4 | + | ||||
| 5 | +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices. | ||||
| 6 | + | ||||
| 7 | +This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean. | ||||
| 8 | + | ||||
| 9 | +<!-- END:nextjs-agent-rules --> | ||||
added
README.md
+62 −0
@@ -0,0 +1,62 @@ | |||||
| 1 | +# Chat SPBoucher AI | ||||
| 2 | + | ||||
| 3 | +Interface privée, multi-modèles et multimodale de Simon-Pierre Boucher — **https://chat.spboucher.ai** — déployée sur le cluster MacLustr (nœud M4M64c, PostgreSQL 17 + pgvector, MacLustr Tunnel via BHS64). | ||||
| 4 | + | ||||
| 5 | +> Un seul propriétaire. Tous les modèles OpenAI et Anthropic **vérifiés par requête réelle**. Mémoire persistante. Contrôle complet. | ||||
| 6 | + | ||||
| 7 | +## Phase zéro — ce qui a été vérifié avant de coder | ||||
| 8 | + | ||||
| 9 | +| | OpenAI | Anthropic | | ||||
| 10 | +|---|---|---| | ||||
| 11 | +| Modèles listés par l'API du compte | 140 | 14 | | ||||
| 12 | +| Modèles de chat vérifiés (11 tests réels chacun) | 30 | 14 | | ||||
| 13 | +| Listés mais **indisponibles** (404 « deprecated ») | 23 | 0 | | ||||
| 14 | +| Spécialisés vérifiés (image / TTS / STT / embeddings / modération) | 18 | — | | ||||
| 15 | +| Non exercés (realtime, vidéo, deep-research, completions) | 18 | — | | ||||
| 16 | + | ||||
| 17 | +Livrables dans `benchmarks/` : `model-discovery.json`, `openai-results.json`, `anthropic-results.json`, `modality-results.json`, `capability-matrix.json`, `pricing.json` (prix copiés des pages officielles le 2026-11-01), `benchmark-report.md`, `routing-recommendations.md`. Coût total du benchmark : ≈ 2,45 $. Relancer : `pnpm bench:discover && pnpm bench && pnpm bench:modalities && pnpm bench:report && pnpm registry:refresh`. | ||||
| 18 | + | ||||
| 19 | +Le **laboratoire de modèles** (`/models`) affiche ces données ; le **routeur** (`src/lib/ai/router.ts`) ne choisit jamais un modèle non vérifié. | ||||
| 20 | + | ||||
| 21 | +## Architecture | ||||
| 22 | + | ||||
| 23 | +``` | ||||
| 24 | +Internet → BHS64 (Caddy TLS, WireGuard) → M4M64c:8500 Next.js 16 (App Router, React 19) | ||||
| 25 | + ├─ src/proxy.ts garde de session (cookie httpOnly SameSite=Strict) | ||||
| 26 | + ├─ src/lib/auth.ts Argon2id, sessions révocables, rate-limit, Origin check | ||||
| 27 | + ├─ src/lib/ai/ adapters OpenAI (Responses API) & Anthropic (Messages, adaptive thinking, | ||||
| 28 | + │ fallback serveur), registre, routeur, coûts | ||||
| 29 | + ├─ src/lib/chat/ moteur (streaming SSE, boucle d'outils, approbation, mémoire, titre, artefacts) | ||||
| 30 | + ├─ src/lib/tools/ web_search (Tavily), fetch_page, python (sandbox-exec), search_documents (RAG), | ||||
| 31 | + │ generate_image (gpt-image), save_memory | ||||
| 32 | + ├─ src/lib/research/ recherche approfondie (plan → sources → extraction → synthèse citée) | ||||
| 33 | + └─ PostgreSQL 17 + pgvector : conversations, messages (arbre), pièces jointes, chunks, mémoire, | ||||
| 34 | + artefacts, usage_events, comparisons, research_runs, tool_executions | ||||
| 35 | +``` | ||||
| 36 | + | ||||
| 37 | +## Développement | ||||
| 38 | + | ||||
| 39 | +```bash | ||||
| 40 | +pnpm install | ||||
| 41 | +cp .env.example .env.local # puis remplir (clés API, DATABASE_URL local, SESSION_SECRET) | ||||
| 42 | +createdb chat_spboucher && psql chat_spboucher -c 'CREATE EXTENSION vector' | ||||
| 43 | +pnpm db:migrate # db/migrations/*.sql | ||||
| 44 | +pnpm registry:refresh # charge les modèles (listing live + benchmarks) | ||||
| 45 | +pnpm setup:owner # mot de passe du propriétaire (prompt masqué → hash Argon2id) | ||||
| 46 | +pnpm dev # http://localhost:8500 | ||||
| 47 | +node scripts/e2e/smoke.mjs # test navigateur (Playwright) : login, chat, palette, mobile | ||||
| 48 | +``` | ||||
| 49 | + | ||||
| 50 | +## Production (MacLustr) | ||||
| 51 | + | ||||
| 52 | +Suivre `docs/OPERATIONS.md` : manifeste `mld` (`deploy/mld-manifest.json` → `M1M32:~/dispatch/apps/chat-spboucher-ai.json`), `mld deploy chat-spboucher-ai --node M4M64c`, route tunnel `chat.spboucher.ai`, sauvegardes chiffrées nocturnes (`scripts/backup.sh`, restauration `scripts/restore.sh`), rafraîchissement du catalogue à 05 h 17. | ||||
| 53 | + | ||||
| 54 | +La source de vérité du code est le dépôt git **sur le nœud** (`M4M64c:~/apps/chat-spboucher-ai`, origin = spbgit `chat-spboucher-ai.git`) — règle remote-first MacLustr. | ||||
| 55 | + | ||||
| 56 | +## Sécurité | ||||
| 57 | + | ||||
| 58 | +- Accès privé : aucune inscription, un seul propriétaire, Argon2id (64 Mio, t=3), 5 échecs / 15 min par IP puis blocage, sessions révocables, `Clear-Site-Data` au logout. | ||||
| 59 | +- Secrets uniquement dans `.env.production` (mode 600) et le manifeste `mld` ; jamais dans git. La clé Anthropic collée dans le chat de conception renvoyait 401 : la clé du compte déjà utilisée par les autres apps a été employée (voir `~/Desktop/Cluster/secrets/chat-spboucher-ai.env`). | ||||
| 60 | +- Outils : Python exécuté sous `sandbox-exec` (pas de réseau, répertoire jetable, 20 s) ; `fetch_page` refuse les adresses privées ; les artefacts HTML/React s'affichent dans un iframe `sandbox="allow-scripts"` sans origine partagée. | ||||
| 61 | +- Mémoire : refus automatique des contenus ressemblant à des identifiants ; approbation optionnelle ; export/suppression. | ||||
| 62 | +- Limites de dépenses locales (jour / mois) qui bloquent les nouvelles requêtes ; la facturation réelle des fournisseurs peut différer. | ||||
added
benchmarks/anthropic-results.json
+2854 −0
Large diff (2,855 lines) is not loaded by default to keep the page fast.Load diff
added
benchmarks/artifacts/chatgpt-image-latest.png
+0 −0
Binary file not shown.
added
benchmarks/artifacts/gpt-image-1-mini.png
+0 −0
Binary file not shown.
added
benchmarks/artifacts/gpt-image-1.5.png
+0 −0
Binary file not shown.
added
benchmarks/artifacts/gpt-image-2.5-flare.png
+0 −0
Binary file not shown.
added
benchmarks/artifacts/gpt-image-2.5-sunburst.png
+0 −0
Binary file not shown.
added
benchmarks/artifacts/gpt-image-2.png
+0 −0
Binary file not shown.
added
benchmarks/artifacts/tts-sample.mp3
+0 −0
Binary file not shown.
added
benchmarks/benchmark-report.md
+228 −0
Large diff (228 lines) is not loaded by default to keep the page fast.Load diff
added
benchmarks/capability-matrix.json
+3610 −0
Large diff (3,611 lines) is not loaded by default to keep the page fast.Load diff
added
benchmarks/modality-results.json
+241 −0
Large diff (242 lines) is not loaded by default to keep the page fast.Load diff
added
benchmarks/model-discovery.json
+1940 −0
Large diff (1,941 lines) is not loaded by default to keep the page fast.Load diff
added
benchmarks/openai-results.json
+5869 −0
Large diff (5,870 lines) is not loaded by default to keep the page fast.Load diff
added
benchmarks/pricing.json
+98 −0
Large diff (98 lines) is not loaded by default to keep the page fast.Load diff
added
benchmarks/routing-recommendations.json
+89 −0
Large diff (90 lines) is not loaded by default to keep the page fast.Load diff
added
benchmarks/routing-recommendations.md
+38 −0
Large diff (38 lines) is not loaded by default to keep the page fast.Load diff
added
benchmarks/vision-test.png
+0 −0
Binary file not shown.
added
db/migrations/001_init.sql
+311 −0
Large diff (311 lines) is not loaded by default to keep the page fast.Load diff
added
deploy/mld-manifest.json
+18 −0
Large diff (18 lines) is not loaded by default to keep the page fast.Load diff
added
docs/OPERATIONS.md
+77 −0
Large diff (77 lines) is not loaded by default to keep the page fast.Load diff
added
eslint.config.mjs
+23 −0
Large diff (23 lines) is not loaded by default to keep the page fast.Load diff
added
next-env.d.ts
+7 −0
Large diff (7 lines) is not loaded by default to keep the page fast.Load diff
added
next.config.ts
+17 −0
Large diff (17 lines) is not loaded by default to keep the page fast.Load diff
added
package.json
+73 −0
Large diff (73 lines) is not loaded by default to keep the page fast.Load diff
added
pnpm-lock.yaml
+4395 −0
Large diff (4,395 lines) is not loaded by default to keep the page fast.Load diff
Diff truncated — file too large.