File size: 6,149 Bytes
31b7256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

import pandas as pd
import re
import PyPDF2
from dizionario_acronimi import acronimi
import unicodedata

class DocumentProcessor:
    """
    Classe per elaborare il testo dei documenti:
    - Rimuove righe inutili basandosi su ESCLUDI_RE.
    - Unisce righe spezzate in paragrafi coerenti, mantenendo gli elenchi puntati al paragrafo precedente.
    - Suddivide il testo in paragrafi ben formattati.
    """

    # 🔹 Lista di espressioni regolari per rimuovere righe indesiderate
    ESCLUDI_RE = [
        r'Pagina\s+\d+\s+di\s+\d+',  # "Pagina x di y"
        r'^Foglio\s+\d+',             # "Foglio 3"
        r'^\s*$',                     # Righe vuote
        r'^Codice\s+Documento:\s+\w+', # "Codice Documento: ABC123"
        r'^Firma\s+Digitale',          # "Firma Digitale"
    ]
    @staticmethod
    def normalizza_testo_avanzato(testo):
        if pd.isna(testo):
            return ""
        testo = str(testo).strip()
        testo = testo.replace("’", "'").replace("‘", "'")  # Sostituire tipi diversi di apostrofi
        testo = unicodedata.normalize("NFKD", testo)  # Normalizza Unicode (es: accenti, simboli)
        return " ".join(testo.split())  # Rimuove spazi multipli

    @staticmethod
    def spezza_in_frammenti(testo: str, numero_frammenti : int = 1)  ->list :
        if numero_frammenti <= 0:
            raise ValueError("Il numero di frammenti deve essere un intero positivo.")

        lunghezza_testo = len(testo)
        if numero_frammenti > lunghezza_testo:
            return []  # Restituisce una lista vuota se non è possibile dividere

        lunghezza_frammento = lunghezza_testo // numero_frammenti  # Divisione intera
        resto = lunghezza_testo % numero_frammenti  # Calcola il resto
        frammenti = []
        inizio = 0
        for i in range(numero_frammenti):
            fine = inizio + lunghezza_frammento + (1 if i < resto else 0)  # Gestisce il resto
            frammenti.append(testo[inizio:fine])
            inizio = fine

        return frammenti
    
    def estrai_da_pdf(self, pdf_file_path) :  
       with open(pdf_file_path, "rb") as f:
            reader = PyPDF2.PdfReader(f)
            full_text = ""
            for page in reader.pages:
                page_text = page.extract_text() or ""
                full_text += page_text 
            for acr, espansione in acronimi.items():
                full_text = full_text.replace(acr,espansione)
       return full_text

    def chunk_text_by_paragraph(self,text: str):
        """
        Suddivide il testo in paragrafi basandosi su newline.
        Mantiene uniti gli elenchi puntati e numerati con il paragrafo precedente.
        """
        paragraphs = text.split("\n")
        docs = []
        for i, para in enumerate(paragraphs):
            para = para.strip()
            if para:
                docs.append({"id": str(i), "text": para})
        return docs

    
    
    def scomponi_in_frammenti(self, testo:str, numero_frammenti: int = 1):
        raise NotImplementedError("Questo metodo deve essere implementato nelle sottoclassi.")
    
    def unify_lines(self, text):
        """
        Metodo da implementare nelle sottoclassi per suddividere il testo in paragrafi.
        """
        return  "\n".join(self.dividi_in_paragrafi(text))
    
    def dividi_in_paragrafi(self,pdf_text: str) :

        """
        Unisce righe spezzate in paragrafi coerenti, evitando di separare gli elenchi puntati dal paragrafo precedente.
        Filtra le righe che corrispondono a qualsiasi espressione regolare contenuta in ESCLUDI_RE.
        """
        lines = pdf_text.splitlines()
        paragraphs = []
        current_line = ""
        end_punctuations = (".", "?", "!", ":", ";")
        inside_list = False  # 🟢 Indica se stiamo dentro un elenco puntato

        for line in lines:
            line = line.strip()

            # 🛑 Rimuove le righe che corrispondono a una delle regex in ESCLUDI_RE
            if any(re.search(pattern, line, re.IGNORECASE) for pattern in DocumentProcessor.ESCLUDI_RE):
                continue  # ❌ Salta la riga


            # 🟢 Riconosce un elemento di un elenco puntato (es. "- testo", "• testo", "1. testo")
            is_list_item = re.match(r"^(\d+\.\s+|[-•*]\s+).+", line)

            # 🟢 Se la riga è vuota e abbiamo testo nel buffer, chiudiamo il paragrafo
            if not line:
                if current_line:
                    paragraphs.append(current_line.strip())
                    current_line = ""
                    inside_list = False  # 🛑 Reset della modalità elenco
                continue

            # 🟢 Se è un elemento di elenco, lo aggiungiamo direttamente al paragrafo precedente
            if is_list_item:
                inside_list = True  # 🟢 Indichiamo che siamo dentro un elenco
                current_line += " " + line  # 🔄 Aggiunge la riga all'elenco senza creare un nuovo paragrafo
            elif inside_list:
                # 🛑 Se eravamo dentro un elenco e ora la riga NON fa parte dell'elenco
                current_line += " " + line  # ✅ Manteniamo tutto unito
                inside_list = False  # 🔄 Reset della modalità elenco
            elif line.endswith(end_punctuations):
                current_line += " " + line
                paragraphs.append(current_line.strip())
                current_line = ""
            else:
                current_line += " " + line  # ✅ Unisce righe normali

        if current_line.strip():
            paragraphs.append(current_line.strip())
        #i = 0
        #for par in paragraphs:
        #    print(f"Paragrafo {i} - {par}")
        #    i = i+1
        return paragraphs
    
class ParagraphDocumentProcessor(DocumentProcessor):

    def scomponi_in_frammenti(self, testo:str, numero_frammenti: int = 1):
        return self.dividi_in_paragrafi(testo)
    
class WholeTextDocumentProcessor(DocumentProcessor) :
        def scomponi_in_frammenti(self, testo:str, numero_frammenti: int = 1):
            print("WholeTextDocumeptProcessor !!!")
            return [testo]