chore: sauvegarde état courant avant merge des branches teammates

Modifications en cours : pipeline médical (cim10_extractor, dp_finalizer,
dp_selector, fusion, rag_search), viewer (helpers, detail.html),
cache ollama et référentiels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
dom
2026-03-08 12:36:54 +01:00
parent 214a5d1914
commit 0c38bc261b
12 changed files with 4365 additions and 82 deletions

View File

@@ -122,11 +122,23 @@ def _rerank(query: str, results: list[dict], top_k: int) -> list[dict]:
if not results:
return results
reranker = _get_reranker()
passages = [r.get("extrait", "") for r in results]
# Construire les paires (query, passage) pour le cross-encoder
pairs = [(query, r.get("extrait", "")) for r in results]
ce_scores = reranker.predict(pairs)
# Essayer le serveur distant d'abord
ce_scores = None
try:
from .remote_embed import rerank_remote
remote_scores = rerank_remote(query, passages)
if remote_scores is not None:
ce_scores = remote_scores
except ImportError:
pass
# Fallback local
if ce_scores is None:
reranker = _get_reranker()
pairs = [(query, p) for p in passages]
ce_scores = reranker.predict(pairs)
# Injecter le score cross-encoder et trier
for r, ce_score in zip(results, ce_scores):
@@ -138,10 +150,9 @@ def _rerank(query: str, results: list[dict], top_k: int) -> list[dict]:
def _embed_cached(texts: list[str]) -> "numpy.ndarray":
"""Calcule les embeddings avec cache. Retourne un array (N, dim)."""
"""Calcule les embeddings avec cache. Essaie le serveur distant d'abord."""
import numpy as np
model = _get_embed_model()
results = [None] * len(texts)
to_compute: list[tuple[int, str]] = []
@@ -155,8 +166,20 @@ def _embed_cached(texts: list[str]) -> "numpy.ndarray":
if to_compute:
new_texts = [t for _, t in to_compute]
new_vecs = model.encode(new_texts, normalize_embeddings=True, batch_size=64)
new_vecs = np.array(new_vecs, dtype=np.float32)
# Essayer le serveur distant d'abord
new_vecs = None
try:
from .remote_embed import embed_remote
new_vecs = embed_remote(new_texts)
except ImportError:
pass
# Fallback local
if new_vecs is None:
model = _get_embed_model()
new_vecs = model.encode(new_texts, normalize_embeddings=True, batch_size=64)
new_vecs = np.array(new_vecs, dtype=np.float32)
with _embedding_cache_lock:
for j, (i, t) in enumerate(to_compute):
@@ -703,6 +726,36 @@ def enrich_acte(acte: ActeCCAM, contexte: dict, cache: OllamaCache | None = None
logger.info("Ollama non disponible — sources FAISS CCAM conservées sans justification LLM")
def _smart_truncate(text: str, max_chars: int = 6000) -> str:
"""Troncature intelligente : garde le début + les sections finales importantes.
Pour les textes longs, on garde :
- Les premiers 60% de max_chars (début du document : identité, motif, histoire)
- Les derniers 40% (conclusion, synthèse, diagnostic de sortie, TTT)
Séparés par un marqueur [...] pour indiquer la troncature.
"""
if len(text) <= max_chars:
return text
head_size = int(max_chars * 0.6)
tail_size = max_chars - head_size - 30 # 30 chars pour le séparateur
# Chercher une fin de phrase propre pour le head
head = text[:head_size]
last_newline = head.rfind("\n")
if last_newline > head_size * 0.8:
head = head[:last_newline]
# Chercher un début de ligne propre pour le tail
tail_start = len(text) - tail_size
first_newline = text.find("\n", tail_start)
if first_newline > 0 and first_newline < tail_start + 200:
tail_start = first_newline + 1
tail = text[tail_start:]
return head + "\n\n[... texte tronqué ...]\n\n" + tail
def _build_prompt_das_extraction(text: str, contexte: dict, existing_das: list[str], dp_texte: str) -> str:
"""Construit le prompt pour l'extraction LLM de DAS supplémentaires."""
ctx_str = format_enriched_context(contexte)
@@ -712,7 +765,7 @@ def _build_prompt_das_extraction(text: str, contexte: dict, existing_das: list[s
dp_texte=dp_texte or "Non identifié",
existing_str=existing_str,
ctx_str=ctx_str,
text_medical=text[:4000],
text_medical=_smart_truncate(text, 6000),
)