File size: 5,010 Bytes
aabd32c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#Questo documento incapsula la logica per l'estrazione delle NE e del testo strutturato

from gliner import GLiNER
import torch
import logging
from processingPdf.loader import get_layout_extractor, load_pdf_from_bytes
from processingPdf.logicSections import extract_logical_sections

logger = logging.getLogger(__name__)

class PDFExtractor:
    def __init__(self):
        self.layout_extractor = get_layout_extractor()

    def extract_sections(self, file_path: str):
        # Legge il file in bytes per spaCyLayout
        with open(file_path, "rb") as f:
            pdf_bytes = f.read()
        
        # Carica il documento ed estrae il layout
        doc = load_pdf_from_bytes(pdf_bytes, self.layout_extractor)
        
        # Suddivide in sezioni logiche
        if doc:
            return extract_logical_sections(doc)
        return {}

class EntityExtractor:
    _model = None
    @staticmethod
    def get_model():
        if EntityExtractor._model is None:
            logger.info("Caricamento del modello GLiNER...")
            device = "cuda" if torch.cuda.is_available() else "cpu"
            EntityExtractor._model = GLiNER.from_pretrained("urchade/gliner_medium-v2.1").to(device)
        return EntityExtractor._model
    
    @staticmethod
    def extract_ne(text: str):
        model = EntityExtractor.get_model()

        labels = [
    # --- GENERAL & IDENTIFIERS ---
    "Person", "Organization", "Location", "Date", "Time", 
    "Product", "Event", "Nationality", "Language",

    # --- BUROCRATICO, NORMATIVO & BANDI ---
    "Normative Reference",      # Articoli di legge, decreti, commi
    "Public Body",              # Enti pubblici (es. Ministero, Commissione Europea)
    "Deadline",                 # Scadenze per bandi, domande o pagamenti
    "Requirement",              # Requisiti di partecipazione o criteri di accesso
    "Amount",                   # Cifre monetarie, borse di studio, tasse
    "Evaluation Criteria",      # Criteri di punteggio o valutazione
    "Document Type",            # Es. ISEE, Marca da bollo, Certificato di laurea

    # --- TECNICO & MANUALE DI ISTRUZIONI ---
    "Component",                # Parti di macchinari o componenti hardware
    "Technical Specification",   # Es. 220V, 50Hz, risoluzione 4K, velocità rotazione
    "Error Code",               # Codici errore (es. E04, 404, Fault-01)
    "Safety Instruction",       # Avvertenze di sicurezza o pericoli
    "Tool",                     # Strumenti necessari (es. chiave inglese, cacciavite)
    "Operation Mode",           # Modalità operative (es. Standby, Manuale, Eco)

    # --- SCIENTIFICO, CHIMICO & FISICO ---
    "Scientific Term",          # Termini tecnici generali
    "Chemical Compound",        # Formule e nomi di sostanze (es. H2O, Glucosio)
    "Theory/Law",               # Leggi fisiche o teorie (es. Legge di Ohm, Relatività)
    "Measurement Unit",         # Unità di misura (es. Joule, Watt, Nanometri)
    "Phenomenon",               # Fenomeni naturali o reazioni (es. Ossidazione, Gravità)

    # --- MEDICO & CLINICO ---
    "Clinical Condition",       # Malattie, patologie o sintomi
    "Medical Parameter",        # Es. Glicemia, Pressione Arteriosa, Frequenza Cardiaca
    "Anatomical Structure",     # Organi, ossa, muscoli o tessuti
    "Drug/Medication",          # Nomi di farmaci o principi attivi
    "Diagnostic Test",          # Es. Risonanza Magnetica, Analisi del sangue

    # --- ACCADEMICO & SCOLASTICO ---
    "Academic Subject",         # Materie (es. Storia Moderna, Fisica Quantistica)
    "Exam/Test Name",           # Titoli di esami o test (es. Test TOLC, Prova Scritta)
    "Degree Course",            # Corsi di laurea o diplomi
    "Bibliographic Source",     # Citazioni, autori o titoli di testi universitari

    # --- STORICO & NARRATIVO (FANTASCIENZA) ---
    "Historical Period",        # Ere, secoli o movimenti (es. Illuminismo, Paleolitico)
    "Fictional Species",        # Es. Androidi, Alieni, Specie di fantasia
    "Technological Concept",    # Tecnologie immaginarie o concetti futuristici

    # --- QUANTITATIVO ---
    "Percentage",               # Percentuali e tassi
    "Quantity",                 # Quantità generiche non monetarie
    "Distance"                  # Distanze e lunghezze
]
        
        entities_found = model.predict_entities(text, labels, threshold=0.5)

        entities = []
        seen = set() # Per tracciare i duplicati nello stesso chunk

        for ent in entities_found:
            text_clean = ent["text"].strip().lower()
            label_clean = ent["label"].upper().replace(" ", "_")
            
            # Creiamo una chiave univoca per il set
            entity_key = (text_clean, label_clean)
            
            if entity_key not in seen:
                entities.append({
                    "text": text_clean,
                    "label": label_clean
                })
                seen.add(entity_key)
            
        return entities