# Design - Optimisation de la Qualité d'Anonymisation ## 1. Vue d'Ensemble de l'Architecture ### 1.1 Architecture Actuelle (Baseline) ``` ┌─────────────────────────────────────────────────────────────┐ │ PDF d'entrée │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ EXTRACTION DE TEXTE (5 passes) │ │ pdfplumber → pdfminer → PyMuPDF → docTR OCR → tesseract │ │ + OCR word map (coordonnées normalisées 0→1) │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ DÉTECTION PII (4 couches) │ │ ├─ 1. Regex (EMAIL, TEL, NIR, IBAN, etc.) │ │ ├─ 2. VLM Ollama (qwen2.5vl:7b) — si PDF scanné │ │ │ • Analyse visuelle de chaque page (150 DPI) │ │ │ • 20+ catégories PII (manuscrit, mal orienté) │ │ │ • Masquage total si < 100 mots OCR │ │ ├─ 3. NER EDS-Pseudo (13 labels, F1=0.97) │ │ │ ou CamemBERT-NER ONNX (fallback) │ │ └─ 4. Extraction Trackare (champs structurés) │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ CONSOLIDATION GLOBALE │ │ Propagation des PII sur toutes les pages │ │ + Noms compagnons + Rescan sélectif │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ REDACTION PDF │ │ • Vector (PyMuPDF search_for) │ │ • Raster (OCR word map + matching flou pour VLM) │ │ Génération PDF raster + audit.jsonl │ └─────────────────────────────────────────────────────────────┘ ``` **Problèmes identifiés** : - ❌ Pas de validation post-anonymisation - ❌ Pas de métriques de qualité - ❌ VLM peut halluciner (pages manuscrites complexes) - ❌ Pas d'optimisation GPU pour VLM - ❌ Pas de tests de régression --- ### 1.2 Architecture Cible (Optimisée) ``` ┌─────────────────────────────────────────────────────────────┐ │ PDF d'entrée │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ EXTRACTION DE TEXTE (inchangé) │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ DÉTECTION HYBRIDE (5 passes + améliorations) │ │ ├─ 1. Regex améliorées (formats structurés) │ │ ├─ 2. VLM optimisé (GPU, prompt amélioré, anti-hallucination) │ │ ├─ 3. EDS-Pseudo (noms, contexte médical) - GPU │ │ ├─ 4. CamemBERT-NER (fallback) - GPU │ │ └─ 5. Détection contextuelle renforcée │ │ │ │ → Masquage progressif pour éviter doublons │ │ → Fusion intelligente des résultats │ │ → Validation croisée VLM ↔ NER pour réduire hallucinations│ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ CONSOLIDATION GLOBALE (inchangé) │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ REDACTION PDF │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ VALIDATION POST-ANONYMISATION (NOUVEAU) │ │ ├─ Scanner de fuite PII │ │ ├─ Vérification métadonnées │ │ ├─ Détection hallucinations VLM (cross-check NER) │ │ └─ Certificat de conformité │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ ÉVALUATION QUALITÉ (si ground truth disponible) │ │ ├─ Calcul Précision/Rappel/F1 par méthode │ │ ├─ Identification faux positifs/négatifs │ │ └─ Rapport de qualité │ └─────────────────────────────────────────────────────────────┘ ``` --- ## 2. Composants Détaillés ### 2.1 Dataset de Test Annoté #### 2.1.1 Structure des Données **Format d'annotation** : ```json { "pdf_path": "OGC_257/FC14.pdf", "metadata": { "annotator": "expert_1", "annotation_date": "2024-01-15", "document_type": "compte_rendu_hospitalier", "page_count": 3, "difficulty": "medium" }, "annotations": [ { "id": "ann_001", "page": 1, "type": "NOM", "text": "DUPONT", "bbox": [100.5, 200.3, 150.2, 220.8], "context": "Dr. DUPONT a examiné le patient", "mandatory": true, "difficulty": "easy", "detection_method_expected": ["regex", "ner", "contextual"] } ], "medical_terms_to_preserve": [ "Médecin DIM", "Service de cardiologie", "Praticien conseil" ], "statistics": { "total_pii": 45, "by_type": { "NOM": 12, "PRENOM": 8, "TEL": 3, "EMAIL": 2, "DATE": 15, "ADRESSE": 5 } } } ``` #### 2.1.2 Outil d'Annotation **Composant** : `annotation_tool.py` **Fonctionnalités** : - Interface CLI pour annoter les PDF - Extraction automatique du texte + affichage - Saisie guidée des annotations - Validation du format JSON - Export au format standardisé **Workflow d'annotation** : 1. Sélectionner un PDF du corpus 2. Extraire et afficher le texte page par page 3. Pour chaque PII identifié : - Saisir le type (NOM, TEL, EMAIL, etc.) - Saisir le texte exact - Saisir le contexte (fenêtre de 50 caractères) - Marquer comme obligatoire/optionnel - Estimer la difficulté (easy/medium/hard) 4. Lister les termes médicaux à préserver 5. Sauvegarder l'annotation --- ### 2.2 Système d'Évaluation #### 2.2.1 Évaluateur de Qualité **Composant** : `quality_evaluator.py` **Classes principales** : ```python @dataclass class EvaluationResult: true_positives: int false_positives: int false_negatives: int precision: float recall: float f1_score: float missed_pii: List[Dict] # Faux négatifs détaillés false_detections: List[Dict] # Faux positifs détaillés by_type: Dict[str, Dict] # Métriques par type de PII class QualityEvaluator: def evaluate(self, pdf_path: Path, audit_path: Path) -> EvaluationResult def compare(self, annotations: List, detected: List) -> tuple def generate_report(self, results: List[EvaluationResult]) -> str ``` **Algorithme de comparaison** : 1. Charger les annotations manuelles (ground truth) 2. Charger l'audit généré (détections) 3. Normaliser les textes (lowercase, strip) 4. Créer des clés de comparaison : `(page, type, texte_normalisé)` 5. Calculer les intersections : - TP = annotations ∩ détections - FN = annotations - détections (PII manqués) - FP = détections - annotations (sur-détection) 6. Calculer les métriques 7. Générer le rapport détaillé --- #### 2.2.2 Scanner de Fuite **Composant** : `leak_scanner.py` **Classes principales** : ```python @dataclass class LeakReport: is_safe: bool leak_count: int leaks: List[Dict] severity_counts: Dict[str, int] class LeakScanner: def scan(self, anonymized_pdf: Path, original_audit: Path) -> LeakReport def scan_text(self, text: str, original_pii: List) -> List[Dict] def scan_metadata(self, pdf_path: Path) -> List[Dict] ``` **Algorithme de scan** : 1. Extraire le texte du PDF anonymisé 2. Charger les PII originaux depuis l'audit 3. Vérifier que les PII originaux ne sont plus présents 4. Détecter de nouveaux PII non masqués (regex + NER) 5. Scanner les métadonnées PDF 6. Classer les fuites par sévérité : - CRITIQUE : PII original présent - HAUTE : Nouveau PII détecté - MOYENNE : Métadonnée suspecte --- #### 2.2.3 Benchmark de Performance **Composant** : `benchmark.py` **Métriques collectées** : - Temps de traitement (total, par page, par étape) - Utilisation CPU (%) - Utilisation RAM (MB) - Métriques de qualité (Précision, Rappel, F1) - Nombre de PII détectés par type **Format de sortie** : ```json { "benchmark_date": "2024-01-15T10:30:00", "system_info": { "cpu": "Intel i7-9700K", "ram_gb": 16, "python_version": "3.12.0" }, "results": [ { "pdf_path": "OGC_257/FC14.pdf", "processing_time_s": 12.5, "time_per_page_s": 4.2, "cpu_usage_percent": 85.3, "ram_usage_mb": 1024, "pii_detected": 45, "quality_metrics": { "precision": 0.98, "recall": 0.995, "f1_score": 0.987 } } ], "summary": { "avg_time_per_doc": 15.2, "avg_precision": 0.975, "avg_recall": 0.992, "avg_f1": 0.983 } } ``` --- ### 2.3 Détecteurs Améliorés #### 2.3.1 Regex Améliorées **Composant** : `improved_regex_detector.py` **Améliorations par type** : **A) Téléphones** : ```python RE_TEL_IMPROVED = re.compile( r"(? List[PiiHit]: # Étape 1 : Regex (priorité haute) hits = self.regex_detector.detect(text, page) masked_text = self._mask_zones(text, hits) # Étape 2 : EDS-Pseudo if self.eds_pseudo.is_loaded(): eds_hits = self._detect_with_eds(masked_text, page) hits.extend(eds_hits) masked_text = self._mask_zones(masked_text, eds_hits) # Étape 3 : CamemBERT-NER if self.camembert_ner.is_loaded(): camembert_hits = self._detect_with_camembert(masked_text, page) hits.extend(camembert_hits) masked_text = self._mask_zones(masked_text, camembert_hits) # Étape 4 : Contextuel context_hits = self.contextual_detector.detect(masked_text, page) hits.extend(context_hits) # Fusion et dédoplication return self._merge_hits(hits) ``` **Stratégie de fusion** : - Dédupliquer par position (même zone = même PII) - En cas de conflit de type, garder le plus spécifique - Tracer la méthode de détection pour chaque PII --- ### 2.4 Validation Post-Anonymisation **Composant** : `post_validation.py` **Workflow** : ```python def validate_anonymized_pdf( anonymized_pdf: Path, original_audit: Path, strict_mode: bool = True ) -> ValidationResult: # 1. Scanner les fuites leak_report = leak_scanner.scan(anonymized_pdf, original_audit) # 2. Vérifier la lisibilité readability_score = check_readability(anonymized_pdf) # 3. Générer le certificat if leak_report.is_safe and readability_score > 0.7: certificate = generate_certificate(anonymized_pdf) return ValidationResult( is_valid=True, certificate=certificate, leak_report=leak_report ) else: if strict_mode: raise ValidationError("Document non conforme") return ValidationResult( is_valid=False, leak_report=leak_report ) ``` **Certificat de conformité** : ```json { "certificate_id": "CERT-2024-01-15-001", "pdf_path": "OGC_257/FC14.redacted_raster.pdf", "validation_date": "2024-01-15T10:30:00", "is_compliant": true, "checks": { "no_pii_leak": true, "metadata_clean": true, "readability_ok": true }, "validator": "LeakScanner v2.0", "signature": "sha256:abc123..." } ``` --- ### 2.5 Reporting **Composant** : `quality_reporter.py` **Rapport HTML** : - Vue d'ensemble (métriques globales) - Graphiques (répartition PII, évolution qualité) - Tableau détaillé par document - Liste des faux négatifs (si disponible) - Liste des faux positifs (si disponible) - Recommandations d'amélioration **Template Jinja2** : ```html