Files
flowdeck/docs/V69_Search_Ask_AI.md
T
bruno 1706ad1ee9
FlowDeck CI / lint (push) Successful in 1m48s
FlowDeck CI / test (push) Failing after 21m19s
FlowDeck CI / docker (push) Skipped
feat: v7.3.0 — cycle v6.8.0→v7.3.0 (Sites, Search, Automations, Calendar, SCIM, Wiki) + audit A9
- v6.8.0 Sites & Forms publics (migrations 24)
- v6.9.0 Recherche sémantique hybride + Ask AI (migration 25)
- v7.0.0 Automations v2 multi-étapes + Workers sandboxés (migration 26)
- v7.1.0 Calendar sync Google/CalDAV + Meeting Notes (migration 27)
- v7.2.0 Enterprise : SCIM 2.0, 2FA TOTP/passkeys, audit UI, agent approvals (migration 28)
- v7.3.0 Wiki/Teamspaces, verified pages, collab polish, charts, unfurl (migration 29)
- docs V68→V73, ROADMAP/CHANGELOG/WORKLOAD à jour, VERSION 7.3.0
- A9 : flowdeck.db, flowdeck_dev.db, test-commit.md, upload_test.txt et e2e/{node_modules,shots,test-results} désindexés + ignorés (.gitignore/.dockerignore)
2026-09-30 20:02:57 -04:00

70 lines
4.0 KiB
Markdown

# V6.9.0 — Recherche sémantique + Ask AI
> **Statut** : ✅ Livré en v6.9.0 (2026-09-28) — `app/services/semantic_search.py`, `app/routers/search_ai.py`, migration 25, 24 tests verts · **Roadmap** : `ROADMAP.md § v6.9.0`
> Note d'implémentation : table générique `semantic_embeddings(resource_type, resource_id, …)` au lieu de `page_embeddings(page_id, …)` — couvre aussi les collections ; encodeur hashed-TF `hash-256` (pas d'appel `/embeddings` externe) ; pièces jointes et onglets palette en follow-up.
> **Référence Notion** : Enterprise Search (Notion + Slack/Jira/Drive) + AI Q&A avec citations.
> **Existant** : FTS5 (`services/search.py`, `GET /api/search`, `GET /api/v2/search`), palette `Ctrl+K`, `AgentEngine` (ReAct 12 tours), `PermissionManager`, `llm_config` + `LLMClient` (9 providers).
---
## 1. Vision
`question → top-k chunks autorisés → réponse avec [[fdpage:ID]] cliquables`.
Hybride lexical + vectoriel (RRF), jamais de fuite ACL (filtrage avant prompt).
Hors scope : index temps réel < 1s, connecteurs Slack/Jira (v7.x si besoin forge d'abord).
## 2. Indexation
### 2.1 Schéma (migration 25)
```sql
CREATE TABLE page_embeddings (
page_id INTEGER NOT NULL REFERENCES pages(id) ON DELETE CASCADE,
chunk_id INTEGER NOT NULL, -- index du chunk (0..N)
chunk_text TEXT NOT NULL,
embedding BLOB NOT NULL, -- float32 serialisé
model TEXT NOT NULL DEFAULT 'local-tfidf',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (page_id, chunk_id)
);
CREATE TABLE search_index_state (page_id INTEGER PRIMARY KEY, indexed_at TIMESTAMP);
ALTER TABLE pages ADD COLUMN search_excluded BOOLEAN NOT NULL DEFAULT 0;
```
- Chunking : blocs → texte brut (~500 tokens, overlap 50), ignore `embed`/images (légende seule).
- Providers : `openai-compatible /embeddings` via `LLMClient` si clé user/workspace, sinon **TF-IDF local** (zéro dépendance, FR+EN stopwords) — même interface `embed(texts) -> vectors`.
- Job : scheduler 5 min, batch 50 (`updated_at > indexed_at`), `DELETE` embeddings si page trashée/exclue.
### 2.2 Contenus indexés
Pages `blocks` + `markdown`/`file` (résolution déjà `export.py`), pièces jointes texte (pdf via `pypdf`, docx via `python-docx`, txt/md — cap 1 MB/fichier), titres de lignes DB (sans valeurs privées si `property_permissions` restreint → chunk « titre seul »), issues Gitea/GitHub liées (titre + labels, pas de body privé sans grant).
## 3. Recherche hybride
`GET /api/v2/search/hybrid?q=&workspace_id=&type=&limit=20` :
1. FTS5 score (existants) ; 2. cosine top-50 ; 3. fusion RRF `k=60` ; 4. filtre ACL (`can_view_page`/`can_view_collection`) ; 5. `X-Total-Count`.
Filtres : `verified:1`, `type:page|collection|file`, `after:YYYY-MM-DD`.
Palette `Ctrl+K` : onglets `Pages / Fichiers / ✨ Réponses IA`.
## 4. Ask AI
`POST /api/v2/search/ask {question, workspace_id}` → `{answer_markdown, citations: [{page_id, title}]}` :
- top-k=8 chunks autorisés → prompt `system: réponds en français, cite [[fdpage:ID]]` → `LLMClient.chat()` (clé user, sinon mock déterministe « hors-ligne » comme `ai_writing.py`).
- Budget : 4k tokens contexte, timeout 60s, cache `(hash(question)+workspace)` 10 min.
- Citations résolues via `wiki/titles` (renommage propagé, « Deleted page » gérée).
## 5. UI / perfs / sécu
- Badge `✨` + temps de réponse, feedback 👍/👎 (`ask_feedback` log, futur fine-tune).
- ACL avant LLM (jamais de chunk interdit dans le prompt) ; `search_excluded` respecté partout ; audit `api_audit_log`.
- Perfs : embeddings lazy (pas au save, job fond), cosine en numpy si dispo sinon pur Python (DB < 10k pages OK).
## 6. Tests (`tests/test_v69_search_ask.py`, ~20)
Index chunks, hybride RRF ordre, ACL (page restricted exclue), `verified` filtre, exclusion flag, pièces jointes cap, ask citations valides, ask sans clé → fallback, cache hit, rate-limit, `X-Total-Count`.
## 7. Rollout
1. `embed()` + TF-IDF + job. 2. `/hybrid` + palette. 3. `/ask` + cache + feedback. 4. Docs `/help` + OpenAPI.