# Chat SPBoucher AI 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). > 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. ## Phase zéro — ce qui a été vérifié avant de coder | | OpenAI | Anthropic | |---|---|---| | Modèles listés par l'API du compte | 140 | 14 | | Modèles de chat vérifiés (11 tests réels chacun) | 30 | 14 | | Listés mais **indisponibles** (404 « deprecated ») | 23 | 0 | | Spécialisés vérifiés (image / TTS / STT / embeddings / modération) | 18 | — | | Non exercés (realtime, vidéo, deep-research, completions) | 18 | — | 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`. 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é. ## Architecture ``` Internet → BHS64 (Caddy TLS, WireGuard) → M4M64c:8500 Next.js 16 (App Router, React 19) ├─ src/proxy.ts garde de session (cookie httpOnly SameSite=Strict) ├─ src/lib/auth.ts Argon2id, sessions révocables, rate-limit, Origin check ├─ src/lib/ai/ adapters OpenAI (Responses API) & Anthropic (Messages, adaptive thinking, │ fallback serveur), registre, routeur, coûts ├─ src/lib/chat/ moteur (streaming SSE, boucle d'outils, approbation, mémoire, titre, artefacts) ├─ src/lib/tools/ web_search (Tavily), fetch_page, python (sandbox-exec), search_documents (RAG), │ generate_image (gpt-image), save_memory ├─ src/lib/research/ recherche approfondie (plan → sources → extraction → synthèse citée) └─ PostgreSQL 17 + pgvector : conversations, messages (arbre), pièces jointes, chunks, mémoire, artefacts, usage_events, comparisons, research_runs, tool_executions ``` ## Développement ```bash pnpm install cp .env.example .env.local # puis remplir (clés API, DATABASE_URL local, SESSION_SECRET) createdb chat_spboucher && psql chat_spboucher -c 'CREATE EXTENSION vector' pnpm db:migrate # db/migrations/*.sql pnpm registry:refresh # charge les modèles (listing live + benchmarks) pnpm setup:owner # mot de passe du propriétaire (prompt masqué → hash Argon2id) pnpm dev # http://localhost:8500 node scripts/e2e/smoke.mjs # test navigateur (Playwright) : login, chat, palette, mobile ``` ## Production (MacLustr) 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. 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. ## Sécurité - 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. - 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`). - 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. - Mémoire : refus automatique des contenus ressemblant à des identifiants ; approbation optionnelle ; export/suppression. - Limites de dépenses locales (jour / mois) qui bloquent les nouvelles requêtes ; la facturation réelle des fournisseurs peut différer.