Files
Presidio/refiners/location_address_refiner.py
2025-09-07 12:29:08 +02:00

76 lines
2.9 KiB
Python

from typing import List, Optional, Tuple
from presidio_analyzer import RecognizerResult
from abc import ABC, abstractmethod
import logging
logger = logging.getLogger(__name__)
class EntityRefiner(ABC):
"""Classe de base pour le recadrage d'entités"""
def __init__(self, entity_type: str):
self.entity_type = entity_type
@abstractmethod
def refine(self, text: str, start: int, end: int) -> Optional[Tuple[int, int]]:
"""
Recadre une entité détectée
Args:
text: Le texte complet
start: Position de début de l'entité détectée
end: Position de fin de l'entité détectée
Returns:
Tuple (nouveau_start, nouveau_end) ou None si l'entité doit être ignorée
"""
pass
def should_process(self, entity_type: str) -> bool:
"""Vérifie si ce raffineur doit traiter ce type d'entité"""
return entity_type == self.entity_type
class LocationAddressRefiner(EntityRefiner):
"""
Refiner pour filtrer les doublons entre LOCATION et BE_ADDRESS/FR_ADDRESS.
Ce refiner ne modifie pas les positions mais peut supprimer des entités.
"""
def __init__(self):
super().__init__("LOCATION") # Ne traite que les LOCATION
self.address_entities = {'BE_ADDRESS', 'FR_ADDRESS'}
self.location_entity = 'LOCATION'
# Cache pour stocker les adresses détectées
self._detected_addresses = []
def refine(self, text: str, start: int, end: int) -> Optional[Tuple[int, int]]:
"""
Vérifie si cette LOCATION fait partie d'une adresse déjà détectée.
Args:
text: Le texte complet
start: Position de début de la LOCATION
end: Position de fin de la LOCATION
Returns:
Tuple (start, end) si la location doit être conservée, None sinon
"""
location_text = text[start:end].strip().lower()
# Ignorer les locations trop courtes ou non significatives
if len(location_text) <= 3 or location_text in ['tel', 'fax', 'gsm']:
logger.debug(f"Ignoring short/insignificant location: '{location_text}'")
return None
# Chercher des adresses dans le texte (simple heuristique)
# Cette approche est limitée car on n'a accès qu'à une entité à la fois
# Une meilleure approche serait de modifier l'architecture globale
# Pour l'instant, on garde toutes les locations valides
# et on laisse un post-processing global gérer les doublons
logger.debug(f"Keeping location: '{location_text}'")
return (start, end)
def should_process(self, entity_type: str) -> bool:
"""Ne traite que les entités LOCATION"""
return entity_type == self.location_entity