feat: pass LLM hybride pour DAS + interface admin référentiels RAG

Chantier 1 — Extraction DAS par LLM :
- Nouveau prompt expert DIM dans rag_search.py (extract_das_llm)
- Phase 4 dans cim10_extractor.py : détection DAS supplémentaires avant enrichissement RAG
- Cache persistant (clé hash du texte), validation CIM-10, déduplication
- Activé uniquement avec use_rag=True (--no-rag le désactive)

Chantier 2 — Admin référentiels :
- Config : REFERENTIELS_DIR, UPLOAD_MAX_SIZE_MB, ALLOWED_EXTENSIONS
- Chunking générique (PDF/CSV/Excel/TXT) + ajout incrémental FAISS dans rag_index.py
- ReferentielManager CRUD dans viewer/referentiels.py
- 5 routes Flask (listing, upload, indexation, suppression, rebuild)
- Template admin avec tableau interactif + lien sidebar

Fix : if cache → if cache is not None (OllamaCache vide évaluait à False)

410 tests passent (27 nouveaux, 0 régression).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
dom
2026-02-12 23:12:39 +01:00
parent bf92a0ce3e
commit f44216b95b
10 changed files with 1197 additions and 6 deletions

View File

@@ -112,6 +112,10 @@ def extract_medical_info(
_extract_imagerie(anonymized_text, dossier)
_extract_complications(anonymized_text, dossier, edsnlp_result)
# Phase 4 : pass LLM pour détecter des DAS supplémentaires
if use_rag:
_extract_das_llm(anonymized_text, dossier)
if use_rag:
_enrich_with_rag(dossier)
@@ -133,6 +137,79 @@ def extract_medical_info(
return dossier
def _extract_das_llm(text: str, dossier: DossierMedical) -> None:
"""Extrait des DAS supplémentaires via un pass LLM (avant enrichissement RAG)."""
try:
from .rag_search import extract_das_llm
from .ollama_cache import OllamaCache
from ..config import OLLAMA_CACHE_PATH, OLLAMA_MODEL
except ImportError:
logger.warning("Module RAG non disponible pour l'extraction DAS LLM")
return
try:
cache = OllamaCache(OLLAMA_CACHE_PATH, OLLAMA_MODEL)
# Construire le contexte
contexte = {
"sexe": dossier.sejour.sexe,
"age": dossier.sejour.age,
"duree_sejour": dossier.sejour.duree_sejour,
"imc": dossier.sejour.imc,
"antecedents": dossier.antecedents[:5],
"biologie_cle": [(b.test, b.valeur, b.anomalie) for b in dossier.biologie_cle],
"imagerie": [(i.type, (i.conclusion or "")[:200]) for i in dossier.imagerie],
"complications": dossier.complications,
}
# DAS existants (texte + code)
existing_das = []
existing_codes = set()
if dossier.diagnostic_principal and dossier.diagnostic_principal.cim10_suggestion:
existing_codes.add(dossier.diagnostic_principal.cim10_suggestion)
for d in dossier.diagnostics_associes:
label = d.texte
if d.cim10_suggestion:
label += f" ({d.cim10_suggestion})"
existing_codes.add(d.cim10_suggestion)
existing_das.append(label)
dp_texte = dossier.diagnostic_principal.texte if dossier.diagnostic_principal else ""
das_results = extract_das_llm(text, contexte, existing_das, dp_texte, cache=cache)
added = 0
for das in das_results:
texte = clean_diagnostic_text(das.get("texte", ""))
if not texte or not is_valid_diagnostic_text(texte):
continue
code = das.get("code_cim10")
if code:
code = normalize_code(code)
is_valid, _ = cim10_validate(code)
if not is_valid:
logger.info("DAS LLM : code %s invalide pour « %s », ignoré", code, texte)
continue
if code in existing_codes:
continue
existing_codes.add(code)
dossier.diagnostics_associes.append(Diagnostic(
texte=texte,
cim10_suggestion=code,
justification=das.get("justification"),
))
added += 1
if added:
logger.info("DAS LLM : %d diagnostics supplémentaires ajoutés", added)
cache.save()
except Exception:
logger.warning("Erreur lors de l'extraction DAS LLM", exc_info=True)
def _enrich_with_rag(dossier: DossierMedical) -> None:
"""Enrichit les diagnostics via le RAG (FAISS + Ollama)."""
try: