Décision Dom 2026-06-29 (honnêteté UI) : - « Téléphones / e-mails » → « Téléphones » : EMAIL reste toujours masqué (non-toggleable), le label ne le promet plus. - hint « Adresses / CP » : « Voie, ville, code » → « Voie + code postal » : VILLE reste toujours masquée (décision 1b), le hint ne la promet plus. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
118 lines
4.1 KiB
Python
118 lines
4.1 KiB
Python
"""État de configuration de la GUI V6 (G3-B), testable sans display ni fichiers.
|
|
|
|
Détient les options simples exposées par l'onglet Configuration et sait produire
|
|
des :class:`EngineSettings`. La résolution des profils s'appuie sur
|
|
``profile_defaults`` (jamais modifié) avec injection possible pour les tests.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Callable, FrozenSet, List, Optional
|
|
|
|
from gui_v6.engine_bridge import EngineSettings
|
|
|
|
# Mapping centralisé champ ConfigState → CATÉGORIE moteur (Plan 1b / P1-2).
|
|
#
|
|
# Les 7 catégories doivent matcher EXACTEMENT le set accepté par
|
|
# ``anonymizer_core_refactored_onnx.process_pdf(disabled_kinds=...)`` :
|
|
# {"NOM", "DATE_NAISSANCE", "ETAB", "ADRESSE", "NIR", "TEL", "ADHERENT"}.
|
|
#
|
|
# Sémantique des booléens ``detect_*`` : True = « détecter cette catégorie »
|
|
# (= masquer, comportement par défaut). False = laisser en clair → la catégorie
|
|
# entre dans ``disabled_kinds``. Note : CODE_POSTAL suit le toggle ADRESSE côté
|
|
# moteur (décision Dom 2026-06-26), aucun toggle dédié n'est exposé.
|
|
#
|
|
# L'ordre suit les 7 lignes de ``tab_config._DETECTION_OPTIONS`` :
|
|
# Noms/prénoms · Dates de naissance · Établissements · Adresses/CP ·
|
|
# N° sécurité sociale · Téléphones · N° adhérent mutuelle.
|
|
CATEGORY_FIELDS = {
|
|
"detect_nom": "NOM",
|
|
"detect_date_naissance": "DATE_NAISSANCE",
|
|
"detect_etab": "ETAB",
|
|
"detect_adresse": "ADRESSE",
|
|
"detect_nir": "NIR",
|
|
"detect_tel": "TEL",
|
|
"detect_adherent": "ADHERENT",
|
|
}
|
|
# Catégories canoniques (ordre = ordre des toggles UI).
|
|
DETECTION_CATEGORIES = tuple(CATEGORY_FIELDS.values())
|
|
|
|
|
|
@dataclass
|
|
class ConfigState:
|
|
"""Options de configuration utilisateur (réglages simples G3-B)."""
|
|
|
|
profile: Optional[str] = None
|
|
raster_burn: bool = True
|
|
use_local_ner: bool = True
|
|
enable_eds: bool = False
|
|
enable_gliner: bool = False
|
|
output_dir: Optional[Path] = None
|
|
ogc_label: Optional[str] = None
|
|
manual_mask_required: bool = False
|
|
manual_mask_template: Optional[Path] = None
|
|
mask_color: str = "#000000"
|
|
mask_marker_style: str = "brackets"
|
|
mask_margin_x: int = 2
|
|
mask_margin_y: int = 1
|
|
mask_rounded_corners: bool = False
|
|
|
|
# 7 toggles « Données à détecter » — tous ON par défaut (zéro changement).
|
|
detect_nom: bool = True
|
|
detect_date_naissance: bool = True
|
|
detect_etab: bool = True
|
|
detect_adresse: bool = True
|
|
detect_nir: bool = True
|
|
detect_tel: bool = True
|
|
detect_adherent: bool = True
|
|
|
|
def disabled_kinds(self) -> FrozenSet[str]:
|
|
"""Set des CATÉGORIES décochées (laissées en clair).
|
|
|
|
Défaut (tous les toggles ON) ⇒ ``frozenset()`` (no-op moteur).
|
|
"""
|
|
return frozenset(
|
|
category
|
|
for field_name, category in CATEGORY_FIELDS.items()
|
|
if not getattr(self, field_name)
|
|
)
|
|
|
|
def to_engine_settings(self, config_path: Optional[Path] = None) -> EngineSettings:
|
|
return EngineSettings(
|
|
make_vector_redaction=False,
|
|
also_make_raster_burn=self.raster_burn,
|
|
config_path=config_path,
|
|
use_local_ner=self.use_local_ner,
|
|
enable_eds=self.enable_eds,
|
|
enable_gliner=self.enable_gliner,
|
|
ogc_label=self.ogc_label,
|
|
profile=self.profile,
|
|
disabled_kinds=self.disabled_kinds(),
|
|
)
|
|
|
|
|
|
def list_profile_keys(lister: Optional[Callable[[], dict]] = None) -> List[str]:
|
|
"""Liste triée des clés de profils. Best-effort : [] si indisponible."""
|
|
if lister is None:
|
|
from profile_defaults import list_effective_profiles
|
|
|
|
lister = list_effective_profiles
|
|
try:
|
|
return sorted(lister().keys())
|
|
except Exception:
|
|
return []
|
|
|
|
|
|
def default_profile_key(getter: Optional[Callable[[], str]] = None) -> Optional[str]:
|
|
"""Clé du profil par défaut, ou None si indisponible."""
|
|
if getter is None:
|
|
from profile_defaults import get_default_profile_key
|
|
|
|
getter = get_default_profile_key
|
|
try:
|
|
return getter()
|
|
except Exception:
|
|
return None
|