76 lines
2.9 KiB
Python
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 |