From 747848a475921588559c5ebaf983f9490bb5df4f Mon Sep 17 00:00:00 2001 From: Kazeia Team Date: Thu, 11 Jun 2026 22:51:30 +0200 Subject: [PATCH] =?UTF-8?q?feat(rag):=20syncDir=20=E2=80=94=20synchro=20co?= =?UTF-8?q?rpus=20fichiers=E2=86=92base=20=C3=A0=20chaque=20d=C3=A9marrage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L'auto-ingestion ne jouait qu'à base vide (1er démarrage) : une MAJ OTA du composant rag_corpus déposait les nouveaux fichiers mais le RAG continuait de servir l'ancien corpus, sans aucun déclencheur (sauf intent manuel rag_ingest). Rag.syncDir(dir) : ingère tout fichier .txt/.md absent de la base ou dont le texte diffère du brut stocké (comparaison exacte). Idempotent, n'embed que le delta → appelé à CHAQUE buildRag, remplace le cas spécial « base vide ». Ne supprime jamais (docs admin et docs retirés du dossier restent — suppression via l'admin). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../app/src/main/java/com/kazeia/rag/Rag.kt | 28 +++++++++++++++++++ .../java/com/kazeia/service/KazeiaService.kt | 8 ++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/kazeia-android/app/src/main/java/com/kazeia/rag/Rag.kt b/kazeia-android/app/src/main/java/com/kazeia/rag/Rag.kt index 35e6a51..45147f9 100644 --- a/kazeia-android/app/src/main/java/com/kazeia/rag/Rag.kt +++ b/kazeia-android/app/src/main/java/com/kazeia/rag/Rag.kt @@ -112,6 +112,34 @@ class Rag( return total } + /** + * Synchronise le corpus FICHIERS → base : ingère tout fichier .txt/.md absent + * de la base ou dont le texte a changé (comparaison exacte sur le brut stocké). + * Idempotent et incrémental : n'embed que le delta → appelé à CHAQUE buildRag, + * c'est ce qui fait qu'une mise à jour OTA du composant rag_corpus est prise + * en compte au redémarrage suivant (sans intent manuel). Ne supprime jamais : + * les docs admin (hors fichiers) et les docs retirés du dossier restent — + * suppression via l'admin. NB : si l'admin a édité un doc PORTANT LE NOM d'un + * fichier seed, le fichier regagne au redémarrage (les ajouts admin doivent + * utiliser des noms propres, pas écraser le seed). + */ + @Synchronized + fun syncDir(dir: String): Int { + val d = java.io.File(dir) + if (!d.isDirectory) { log("syncDir: '$dir' absent"); return 0 } + val files = d.listFiles { f -> f.isFile && (f.name.endsWith(".txt") || f.name.endsWith(".md")) } + ?.sortedBy { it.name } ?: emptyList() + var changed = 0 + for (f in files) { + val txt = try { f.readText() } catch (e: Exception) { log("syncDir: lecture ${f.name} échec"); continue } + val src = f.nameWithoutExtension + if (db.docText(src) == txt) continue // déjà à jour → zéro embed + ingest(src, txt); changed++ + } + if (changed > 0) log("syncDir '$dir': $changed doc(s) (ré)ingéré(s) sur ${files.size}") + return changed + } + /** * Récupère le contexte pertinent pour [query] et le formate en bloc prêt à * injecter, ou null si rien au-dessus du seuil. Le seuil évite d'injecter du diff --git a/kazeia-android/app/src/main/java/com/kazeia/service/KazeiaService.kt b/kazeia-android/app/src/main/java/com/kazeia/service/KazeiaService.kt index 209c4f9..74ac00a 100644 --- a/kazeia-android/app/src/main/java/com/kazeia/service/KazeiaService.kt +++ b/kazeia-android/app/src/main/java/com/kazeia/service/KazeiaService.kt @@ -2077,9 +2077,11 @@ Pas d'introduction, pas d'explication. Juste les 4 lignes en francais. /no_think val emb = com.kazeia.rag.EngineEmbedder(embModel, nThreads = 4, pooling = -1, queryPrefix = "query: ", passagePrefix = "passage: ", log = { m -> log(m) }) com.kazeia.rag.Rag(this@KazeiaService, emb, "e5-small") { m -> log(m) }.also { - // Auto-ingestion du corpus seed au 1er démarrage (base + docs vides). - if (it.isReady && it.count() == 0 && it.listDocs().isEmpty()) - it.ingestDir("${KazeiaApplication.MODELS_DIR}/../rag_corpus") + // Synchro corpus fichiers → base à CHAQUE build (idempotent, n'embed + // que le delta) : couvre le 1er démarrage ET les MAJ OTA du composant + // rag_corpus (nouveaux fichiers ingérés au redémarrage suivant). + if (it.isReady) + it.syncDir("${KazeiaApplication.MODELS_DIR}/../rag_corpus") it.reingestMissing() // embed les docs admin ajoutés hors-ligne rag = it com.kazeia.rag.RagHolder.instance = it