"""Générateur du rapport HTML interactif auto-contenu. Le rapport produit est un fichier HTML unique embarquant : - Toutes les données (JSON inline) - Chart.js et diff2html (depuis cdnjs) - CSS et JavaScript de l'application Vues disponibles ---------------- 1. Classement — tableau triable par colonne (CER, WER, MER, WIL) 2. Galerie — grille d'images avec badge CER coloré 3. Document — image zoomable + diff coloré GT / OCR par moteur 4. Analyses — histogramme CER + graphique radar Architecture ------------ Ce module est l'**orchestrateur**. Les responsabilités lourdes sont découpées en sous-modules : - :mod:`picarones.report.assets` — chargement vendor.js, encodage base64 d'images, externalisation lazy. - :mod:`picarones.report.report_data` — construction du dict JSON passé au template (engines, documents, statistiques, Pareto, etc.). - :mod:`picarones.report.render_helpers` — couleurs / SVG mutualisés. Rétrocompat ----------- Deux noms historiques sont **encore importés par des tests** sous leur préfixe ``_`` et doivent être préservés : - ``_build_report_data`` (importé par 14 fichiers de tests). - ``_cer_color`` (importé par ``tests/report/test_report.py``). Les autres noms ``_pct``, ``_safe``, ``_cer_bg``, ``_encode_image_b64``, ``_encode_images_b64_from_result``, ``_externalize_images_to_dir``, ``_load_vendor_js`` sont soit utilisés en interne (les 3 derniers, voir :meth:`ReportGenerator.generate`), soit accessibles via leur nom canonique dans :mod:`picarones.report.assets` ou :mod:`picarones.report.render_helpers`. """ from __future__ import annotations import json import logging from pathlib import Path from typing import Any, Optional from picarones.evaluation.benchmark_result import BenchmarkResult from picarones.evaluation.statistics import build_critical_difference_svg from picarones.reports._helpers.assets import ( encode_images_b64_from_result as _encode_images_b64_from_result, externalize_images_to_dir as _externalize_images_to_dir, load_vendor_js as _load_vendor_js, ) # Ré-exports rétrocompat consommés par les tests externes (cf. docstring # de module). La directive de fin de ligne documente l'intention de # ré-export et empêche ruff de marquer l'import comme inutilisé. from picarones.reports._helpers.render_helpers import cer_step_color as _cer_color # noqa: F401 from picarones.reports.html.data import build_report_data as _build_report_data # noqa: F401 logger = logging.getLogger(__name__) # --------------------------------------------------------------------------- # Rendu Jinja2 # --------------------------------------------------------------------------- # Depuis le Sprint 16, le template monolithique ~3100 lignes a été découpé en # fichiers externes dans ``picarones/report/templates/`` (CSS, JS, vues HTML). # ``base.html.j2`` assemble le tout via ``{% include %}``. _TEMPLATES_DIR = Path(__file__).parent / "templates" def _build_jinja_env(): """Construit l'Environment Jinja2 pour le rapport. Sprint S1 (Bandit B701, CWE-94) : autoescape activé via ``select_autoescape``. Les variables qui contiennent du HTML pré-construit (renderers thématiques, SVG, JSON) sont marquées avec ``| safe`` dans les templates ; les variables d'origine utilisateur sont auto-échappées. """ from jinja2 import Environment, FileSystemLoader, select_autoescape env = Environment( loader=FileSystemLoader(str(_TEMPLATES_DIR)), autoescape=select_autoescape(["html", "j2", "xml"]), keep_trailing_newline=True, ) return env def _safe_json_for_script_tag(data: object) -> str: """Sérialise data en JSON safe pour injection dans `` dans une chaîne JSON termine le tag