- 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)
4.0 KiB
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.0Note d'implémentation : table génériquesemantic_embeddings(resource_type, resource_id, …)au lieu depage_embeddings(page_id, …)— couvre aussi les collections ; encodeur hashed-TFhash-256(pas d'appel/embeddingsexterne) ; 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), paletteCtrl+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)
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 /embeddingsviaLLMClientsi clé user/workspace, sinon TF-IDF local (zéro dépendance, FR+EN stopwords) — même interfaceembed(texts) -> vectors. - Job : scheduler 5 min, batch 50 (
updated_at > indexed_at),DELETEembeddings 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 :
- 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. PaletteCtrl+K: ongletsPages / 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 » commeai_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_feedbacklog, futur fine-tune). - ACL avant LLM (jamais de chunk interdit dans le prompt) ;
search_excludedrespecté partout ; auditapi_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
embed()+ TF-IDF + job. 2./hybrid+ palette. 3./ask+ cache + feedback. 4. Docs/help+ OpenAPI.