feat: mode hybride Ollama — gemma3:27b pour CPAM, 12b pour codage
Le pipeline utilise désormais gemma3:12b (rapide) pour le codage CIM-10 et gemma3:27b (meilleur raisonnement) pour la contre-argumentation CPAM. Configurable via OLLAMA_MODEL_CPAM et OLLAMA_TIMEOUT_CPAM. Inclut aussi : traçabilité source/page DAS, niveaux CMA ATIH, sévérité, page tracker PDF, améliorations fusion et filtres DAS. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -305,6 +305,13 @@ _SEVERITY_STYLES = {
|
||||
"leger": ("Léger", "#065f46", "#d1fae5"),
|
||||
}
|
||||
|
||||
_CMA_LEVEL_STYLES = {
|
||||
1: ("1", "#6b7280", "#f3f4f6"), # gris — pas CMA
|
||||
2: ("2", "#065f46", "#d1fae5"), # vert
|
||||
3: ("3", "#92400e", "#fef3c7"), # jaune/orange
|
||||
4: ("4", "#dc2626", "#fee2e2"), # rouge
|
||||
}
|
||||
|
||||
|
||||
def format_duration(seconds: float | None) -> str:
|
||||
"""Formate une durée en secondes vers un format lisible (ex: 2min 30s)."""
|
||||
@@ -330,13 +337,24 @@ def severity_badge(value: str | None) -> Markup:
|
||||
)
|
||||
|
||||
|
||||
def cma_level_badge(value: int | None) -> Markup:
|
||||
"""Badge CMA niveau 1-4 avec couleurs graduées."""
|
||||
if value is None or value < 1:
|
||||
return Markup("")
|
||||
level = min(value, 4)
|
||||
label, fg, bg = _CMA_LEVEL_STYLES.get(level, _CMA_LEVEL_STYLES[1])
|
||||
title = {1: "Pas CMA", 2: "CMA niveau 2", 3: "CMA niveau 3", 4: "CMA niveau 4"}.get(level, "")
|
||||
return Markup(
|
||||
f'<span title="{title}" style="display:inline-block;padding:2px 8px;border-radius:9999px;'
|
||||
f'font-size:0.75rem;font-weight:600;color:{fg};background:{bg}">'
|
||||
f'CMA {label}</span>'
|
||||
)
|
||||
|
||||
|
||||
def format_dossier_name(name: str) -> str:
|
||||
"""Transforme un nom de dossier en nom lisible (ex: 15_23096332 → Dossier 23096332)."""
|
||||
"""Retourne le nom complet du dossier (ex: 1_23096332)."""
|
||||
if name == "racine":
|
||||
return "Non classés"
|
||||
m = re.match(r"^\d+_(\d+)$", name)
|
||||
if m:
|
||||
return f"Dossier {m.group(1)}"
|
||||
return name
|
||||
|
||||
|
||||
@@ -364,6 +382,7 @@ def create_app() -> Flask:
|
||||
app.jinja_env.filters["confidence_badge"] = confidence_badge
|
||||
app.jinja_env.filters["confidence_label"] = confidence_label
|
||||
app.jinja_env.filters["severity_badge"] = severity_badge
|
||||
app.jinja_env.filters["cma_level_badge"] = cma_level_badge
|
||||
app.jinja_env.filters["format_duration"] = format_duration
|
||||
app.jinja_env.filters["format_dossier_name"] = format_dossier_name
|
||||
app.jinja_env.filters["format_doc_name"] = format_doc_name
|
||||
@@ -445,13 +464,16 @@ def create_app() -> Flask:
|
||||
return jsonify({"error": f"PDF source '{source_file}' introuvable"}), 404
|
||||
|
||||
try:
|
||||
anonymized_text, new_dossier, report = process_pdf(pdf_path)
|
||||
pdf_results = process_pdf(pdf_path)
|
||||
stem = pdf_path.stem.replace(" ", "_")
|
||||
subdir = None
|
||||
if pdf_path.parent != input_dir:
|
||||
subdir = pdf_path.parent.name
|
||||
write_outputs(stem, anonymized_text, new_dossier, report, subdir=subdir)
|
||||
return jsonify({"ok": True, "message": "Traitement terminé"})
|
||||
multi = len(pdf_results) > 1
|
||||
for part_idx, (anonymized_text, new_dossier, report) in enumerate(pdf_results):
|
||||
part_stem = f"{stem}_part{part_idx + 1}" if multi else stem
|
||||
write_outputs(part_stem, anonymized_text, new_dossier, report, subdir=subdir)
|
||||
return jsonify({"ok": True, "message": f"Traitement terminé ({len(pdf_results)} dossier(s))"})
|
||||
except Exception as e:
|
||||
logger.exception("Erreur lors du retraitement")
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
Reference in New Issue
Block a user