mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-08 12:41:54 +00:00
ADR-004 : embeddings locaux sur CPU (fastembed ONNX, paraphrase-multilingual-MiniLM-L12-v2, 384 dims — les textes du client ne quittent jamais le serveur), pgvector dans le Postgres existant (RagChunk possédé par Prisma, migration r5_ia + état de corpus sur Document), génération opt-in (mode extractif par défaut : la recette passe sans clé API), service siop2-ai jamais exposé — joint par l'API NestJS seule (X-Service-Token). apps/ai (FastAPI + uv) : pipeline PDF MinIO → texte paginé (pypdf) → anonymisation D4 (e-mails, téléphones marocains, noms connus de la base, insensible casse/accents — fonction pure testée) → découpage avec chevauchement (testé) → embeddings → RagChunk localisé (« p. 42 », « bilan du 17/07 »). Bilans codés clôturés ingérés. Exclusion de corpus (D3) appliquée à l'ingestion ET à la lecture. 14 pytest + ruff, embeddeur déterministe en CI (aucun téléchargement), job CI ai (uv), deploy en dépend. Vérifié en réel avec le vrai modèle : corpus seedé réindexé en 7 s (PDF réel → 31 extraits paginés + 3 bilans), recherche sémantique concluante, e-mails → ⟨contact⟩, 0 identité dans les chunks (contrôle SQL). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
30 lines
1.3 KiB
Markdown
30 lines
1.3 KiB
Markdown
# @siop/ai — service IA (R5)
|
|
|
|
FastAPI + uv (ADR-001), **jamais exposé** : seule l'API NestJS le contacte avec
|
|
`X-Service-Token` (ADR-004 §4). Maquettes et décisions D1-D5 validées le 17/07/2026.
|
|
|
|
## Lancer (dev)
|
|
|
|
```bash
|
|
cd apps/ai
|
|
uv sync --extra embeddings # le vrai modèle ONNX (CPU, ~120 Mo au premier run)
|
|
uv run uvicorn siop_ai.app:app --port 8000
|
|
# CI / tests : uv sync && uv run pytest (embeddeur déterministe, aucun téléchargement)
|
|
```
|
|
|
|
Variables (défauts dev dans `config.py`) : `DATABASE_URL`, `MINIO_*`,
|
|
`AI_SERVICE_TOKEN`, `AI_EMBEDDINGS=locale|deterministe`, `AI_GENERATION=off|api`.
|
|
|
|
## Ce que porte R5.1 (socle)
|
|
|
|
- **Ingestion anonymisée (D4)** : PDF de la bibliothèque (MinIO) page par page +
|
|
bilans codés clôturés → anonymisation (e-mails, téléphones, noms connus de la
|
|
base) → découpage → embeddings locaux → `RagChunk` (pgvector, schéma Prisma).
|
|
- **Recherche sémantique** `/internal/search` : extraits sourcés (document + page
|
|
ou bilan daté) avec score — la brique de « sourcé ou silencieux » (D2).
|
|
- `/internal/reindex` idempotent ; l'exclusion de corpus (`Document.inCorpus`,
|
|
D3) s'applique à l'ingestion ET à la lecture.
|
|
|
|
La suite : R5.2 assistant (mode extractif puis génération opt-in) + suggestion de
|
|
bilan ; R5.3 écrans ; durcissement : Dockerfile + compose Dokploy (`siop2-ai`).
|