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:
@@ -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),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user