# Memoire projet Derniere mise a jour : 2026-04-22 ## Objet But du projet : anonymiser/pseudonymiser des documents medicaux de facon fiable, diffable, validable par des humains, avec une contrainte forte de conformite et de non-fuite. Ce fichier sert de point de reprise rapide pour ne pas perdre le fil entre deux sessions. ## Etat courant - La source de verite des dictionnaires par defaut est `config/dictionnaires.default.yml`. - La surcharge runtime/site est `config/dictionnaires.yml`. - Les dictionnaires hardcodes ont ete externalises vers `data/`. - Les regles d'administration ont un contrat dedie : - `config/admin_rules.default.yml` - `config/admin_rules.yml` - `schemas/admin_rules.schema.json` - `admin_rules.py` - Les regles admin sont branchees dans le moteur ONNX. - Le core legacy n'est pas encore aligne sur ce branchement admin. - La GUI conserve maintenant le chemin relatif des cas sous `anonymise/` au lieu d'ecraser les sorties homonymes. - La GUI ignore maintenant le sous-dossier `anonymise/` lors du scan recursif des entrees. - L'onglet Parametres de la GUI charge maintenant les listes effectives `default + overlay`, donc les phrases/termes par defaut sont visibles meme si `config/dictionnaires.yml` est vide. - L'onglet Parametres affiche aussi un resume chiffré des listes visibles et precise que le moteur applique d'autres regles automatiques non affichees dans ces champs. - La GUI expose maintenant un mode `masques PDF reutilisables` pour les documents formates : - ouverture d'un editeur de caviardage manuel depuis l'onglet Parametres - stockage persistant des templates dans `config/mask_templates/` - ouverture automatique du PDF courant quand l'utilisateur a selectionne un fichier PDF - selection d'un template dans la GUI pour l'appliquer a tous les PDF du lot avant anonymisation - La GUI expose maintenant aussi des `profils metier` : - definitions chargees depuis `config/profiles.default.yml` + `config/profiles.yml` - selection d'un profil dans l'onglet Parametres - surcharge de configuration appliquee au moteur pour le lot courant - options de poste utilisateur prises en compte comme `masque manuel requis` et `VLM desactive` - Le moteur anonymise maintenant correctement deux layouts reels supplementaires : - numero de venue BACTERIO rejete juste avant `IPP` - artefacts de noms de fichiers scannes `EXT2-...-1234567890.TIF` ## Validation deja en place - Suite rapide : `tests/synthetic_regression/` - Corpus complet de revue : `tests/synthetic_review/` - Runner de revue : `tools/run_synthetic_review_corpus.py` - Protocole humain : `docs/protocole-validation-humaine.md` - Fiche de revue : `docs/fiche-validation-humaine-modele.md` Tests ajoutes/maintenus : - `tests/unit/test_config_externalization.py` - `tests/unit/test_header_pii_detection.py` - `tests/unit/test_synthetic_regression.py` - `tests/unit/test_admin_rules_validator.py` - `tests/unit/test_admin_rules_integration.py` - `tests/unit/test_gui_batch_paths.py` ## Commits repere - `500ebc2` Externalize dictionaries and add anonymization review corpus - `b58d79f` Add project framing for anonymization - `0fc8665` Add human review protocol and admin rules contract - `df5dabf` Wire admin rules into ONNX anonymizer ## Dernier constat important La campagne lancee depuis la GUI sur le dossier global `tests/synthetic_regression/cases` n'est pas exploitable comme validation complete. Cause racine : - la GUI parcourt recursivement tous les fichiers supportes du dossier choisi - la GUI ecrit toutes les sorties dans un seul dossier `anonymise/` - les sorties sont nommees avec le seul `stem` du fichier source - comme chaque cas contient `input.txt`, `test.txt` et `expected.txt`, les sorties s'ecrasent entre elles Rapport detaille : - `docs/rapport-analyse-campagne-gui-2026-04-21.md` Conclusion : - seul le cas `010_spaced_establishment_header` restait encore verifiable - ce cas etait conforme - la campagne globale est non concluante pour les autres cas ## Correctif applique ensuite Le probleme de nommage GUI identifie ci-dessus a ete corrige dans `Pseudonymisation_Gui_V5.py`. Effets du correctif : - les sorties de campagne conservent desormais le sous-dossier relatif de chaque cas - le dossier `anonymise/` est exclu des entrees candidates, pour eviter les retraitements accidentels - le controle de fuite GUI relit desormais les `.pseudonymise.txt` de facon recursive Exemple attendu : - `anonymise/001_patient_header_and_birth/test.pseudonymise.txt` - `anonymise/002_contact_bundle/test.pseudonymise.txt` ## Echantillon reel CHUXX du 2026-04-22 Lot teste : - dossier source : `/home/dom/Téléchargements/II-1 Ctrl_T2A_2025_CHUXX_DocJustificatifs` - echantillon aleatoire reproductible de 30 documents - manifeste : `anonymise/_sample_manifest_2026-04-22_seed20260422.json` Resultat de traitement : - 27 documents anonymises avec succes - 3 echecs dus a des PDF proteges par mot de passe : - `149_23089771/ANAPATH 23089771.pdf` - `26_23127395/ANAPATH 23127395.pdf` - `29_23137897/ANAPATH 23137897.pdf` Validation apres correctifs moteur : - 2 fuites probables observees au premier passage ont ete corrigees : - `228_23176885/BACTERIO 23176885.pdf` - `84_23215994/trackare-16014215-23215994_16014215_23215994.pdf` - controle automatique final : 22 documents sans fuite detectee sur 27 - les 5 alertes restantes sont des faux positifs connus du `LeakScanner` - initiales d'une lettre dans l'audit (`A`, `F`, `S`) - code produit `16371071` dans une ligne CLARISCAN - ratio medical `1/10000` Rapports produits : - `anonymise/_sample_run_report_2026-04-22_seed20260422.json` - `anonymise/_sample_validation_report_2026-04-22_seed20260422.json` - `anonymise/_sample_validation_triage_2026-04-22_seed20260422.json` ## Prochaine action recommandee Relancer soit : - une nouvelle vague aleatoire de 30 documents reels CHUXX - soit la campagne de validation sur `tests/synthetic_regression/cases` Objectif : - separer les vrais ecarts moteur des faux positifs du validateur - prioriser ensuite une amelioration du `LeakScanner` pour ignorer les hits NOM mono-lettre et certains numeriques medicaux non patients Option recommandee : - verifier d'abord que la GUI ne traite plus `anonymise/` comme entree - lancer une passe complete sur le corpus - confirmer visuellement que chaque cas produit sa sortie dans son propre sous-dossier Amelioration utile ensuite : - ajouter un mode GUI "campagne de tests" qui ne traite que `test.txt` - generer automatiquement un rapport de comparaison contre les `expected.txt` ## Fichiers a relire en premier pour reprendre - `docs/cadrage-projet-anonymisation.md` - `docs/spec-regles-administration.md` - `docs/protocole-validation-humaine.md` - `docs/rapport-analyse-campagne-gui-2026-04-21.md` - `gui_batch_paths.py` - `anonymizer_core_refactored_onnx.py` - `Pseudonymisation_Gui_V5.py` ## Etat du worktree a ne pas confondre avec le chantier courant Il existe des changements hors perimetre qu'il ne faut pas ecraser par erreur : - suppressions sous `ano/pdf_natif/pseudonymise/` - gros volume non tracke sous `data/silver_annotations/` - sorties generees sous `tests/synthetic_review/actual/` - sorties GUI sous `tests/synthetic_regression/cases/anonymise/` ## Regle de reprise Avant toute nouvelle passe de validation humaine sur corpus : 1. verifier le mode de sortie de la GUI 2. eviter de traiter le dossier global tant que le nommage de sortie n'est pas corrige 3. preferer un cas a la fois si la GUI n'a pas encore ete corrigee ## Derniere avancee Les profils metier ne sont plus seulement lus depuis YAML : - la GUI permet maintenant de creer un nouveau profil - la GUI permet d'enregistrer les reglages courants dans le profil selectionne - les profils utilisateur sont ecrits dans `config/profiles.yml` - un profil peut memoriser : - les listes visibles de preservation / masquage / stop-words - le caractere obligatoire du masque manuel - la desactivation du VLM - le modele de masque PDF prefere Effet important : - la selection d'un profil recharge maintenant ses reglages visibles dans l'onglet Parametres - le lancement de traitement utilise les reglages courants de l'ecran via une config temporaire de lot, sans exiger un `Sauvegarder` prealable dans `dictionnaires.yml` Ergonomie GUI : - l'onglet `Parametres` a ete simplifie pour un usage bureautique - la navigation est maintenant organisee en trois onglets stables : - `Anonymisation` - `Parametres` - `Profils` - les listes manuelles sont revenues directement dans `Parametres` - la creation / edition / suppression / profil par defaut sont gerees directement dans l'onglet `Profils` - on evite ainsi les enchainements de popups pour le flux normal - l'onglet `Profils` expose maintenant explicitement le `masque PDF memorise par ce profil` - le sens de `masque manuel obligatoire` est documente dans l'UI : - cela n'impose pas un masque precis - cela bloque seulement le lancement si aucun masque PDF n'est selectionne Packaging Windows : - le build Windows a maintenant un point d'entree "un clic" : `build_windows_oneclick.bat` - ce lanceur appelle `scripts/build_windows_oneclick.ps1` - le packaging utilise `PyInstaller` via `anonymisation_onefile.spec` - le `.spec` n'est plus fige sur `C:\Users\dom\ai\anonymisation` ; il resolve maintenant le projet de facon portable - les repertoires de configuration, donnees, detecteurs, assets et modele ONNX sont embarques dans l'executable - sur la machine Windows de build, la sortie attendue est : - `dist\Anonymisation.exe` - `release\Anonymisation-Windows\` - `release\Anonymisation-Windows.zip` - `release\Anonymisation.exe.sha256.txt` - objectif produit : - les utilisateurs finaux n'ont pas besoin d'installer Python - le build doit en revanche etre realise depuis un poste Windows - risque Windows identifie : - un executable PyInstaller non signe peut declencher SmartScreen / Defender - meme signe, un nouveau hash peut encore afficher un avertissement de reputation selon les politiques Windows - `scripts/build_windows_oneclick.ps1` accepte maintenant une signature Authenticode via `-Sign` - un fichier local non versionne `build_signing.local.ps1` peut activer la signature automatiquement pour conserver le build en un clic - le modele de configuration est `build_signing.example.ps1` Build Windows realise le 2026-04-23 via SSH sur `dom@192.168.1.11` : - poste : `DESKTOP-58D5CAC` - chemin projet Windows : `C:\Users\dom\ai\anonymisation` - executable cree : `C:\Users\dom\ai\anonymisation\dist\Anonymisation.exe` - archive creee : `C:\Users\dom\ai\anonymisation\release\Anonymisation-Windows.zip` - hash : `C:\Users\dom\ai\anonymisation\release\Anonymisation.exe.sha256.txt` - SHA256 final : `8F3E3786D669F44824D24BF14AC06EF22CE19A8E900056DAB031891791871841` - taille exe : environ 697 MB - contenu OCR : `python-doctr`, `torchvision`, `opencv-python`, `scipy` embarques dans l'environnement de build - signature : non signee, car aucun certificat n'est configure - smoke test : lancement de l'exe OK ; processus encore vivant apres 45 secondes, puis arret volontaire Correctif build Windows du 2026-04-23 : - probleme constate au lancement utilisateur : `No module named admin_rules` - cause : `admin_rules.py` n'avait pas ete synchronise sur le poste Windows avant le build precedent - correction : transfert de `admin_rules.py` sur `C:\Users\dom\ai\anonymisation` - durcissement : `scripts/build_windows_oneclick.ps1` verifie maintenant la presence des modules source critiques avant PyInstaller - nouveau build cree : `C:\Users\dom\ai\anonymisation\dist\Anonymisation.exe` - nouveau SHA256 : `0EB97B1E2859D0BCD6E45DC420CFDC929C3B79B6B0AF123CF59F2230187F5712` - smoke test : lancement de l'exe OK ; processus encore vivant apres 60 secondes, puis arret volontaire Demarrage produit / installateur Windows du 2026-04-23 : - le lanceur conserve le splash visuel `aivanonym` existant - apres le splash natif PyInstaller, une fenetre de demarrage applicative reprend le meme visuel et affiche : - etapes numerotees de chargement - barre de progression - journal court des modules/dictionnaires charges - la fenetre de configuration initiale affiche aussi le visuel produit et un journal des chargements de modeles - les sorties `stdout/stderr` de type `tqdm` pendant le chargement EDS-Pseudo / GLiNER sont redirigees vers ce journal pour montrer les poids/modules en cours - un script Inno Setup a ete ajoute : `installer/Anonymisation.iss` - le build Windows peut maintenant produire un vrai installateur : `release\Anonymisation-Setup.exe` - l'installateur propose : - choix du dossier d'installation - installation utilisateur sans droit administrateur par defaut - raccourci menu Demarrer - option icone bureau - desinstallation Windows standard - `scripts/build_windows_oneclick.ps1` genere l'installateur si Inno Setup 6 est present ; sinon il conserve EXE/ZIP et affiche un avertissement - verification locale Linux : `python3 -m py_compile launcher.py Pseudonymisation_Gui_V5.py camembert_ner_manager.py eds_pseudo_manager.py gliner_manager.py` - smoke test local du nouveau splash : OK - build Windows non relance a ce stade : authentification SSH refusee lors de la tentative de reconnexion au poste Windows Build Windows installateur realise le 2026-04-23 via SSH sur `dom@192.168.1.11` : - Inno Setup 6.7.1 installe en mode utilisateur sur le poste Windows via `scripts/install_inno_setup_build_dep.ps1` - chemin Inno : `C:\Users\dom\AppData\Local\Programs\Inno Setup 6\ISCC.exe` - build relance avec `scripts\build_windows_oneclick.ps1 -SkipRequirements` - executable cree : `C:\Users\dom\ai\anonymisation\dist\Anonymisation.exe` - archive creee : `C:\Users\dom\ai\anonymisation\release\Anonymisation-Windows.zip` - installateur cree : `C:\Users\dom\ai\anonymisation\release\Anonymisation-Setup.exe` - taille executable : `730 483 452` octets, environ 696.6 MB - taille ZIP : `728 300 929` octets - taille installateur : `729 517 505` octets, environ 695.7 MB - SHA256 executable : `520EE614CD9B56EB7C748AB5BCCDF0DD4DAAD0726EF0EAB0EFE89177A84E5882` - SHA256 installateur : `A22B5D1A3AE10203DEEA7FB053C0184695A88084294603CF1EA643F123597FC1` - signature : non signee, car aucun certificat Authenticode n'est configure - smoke test Windows : lancement de `dist\Anonymisation.exe` OK ; deux processus `Anonymisation` repondants apres 60 secondes, puis arret volontaire