Spaces:
Running
Running
| #Questa parte si occupa di suddividere il documento processato in sezioni logiche | |
| #(capitoli, sottosezioni, etc.) sfruttando le etichette di layout. | |
| import logging | |
| from typing import Dict, Any | |
| logger = logging.getLogger(__name__) | |
| #Suddivide il documneto spaCy in sezioni logiche basandosi sulle etichette di layout. Il "doc" è il documento spaCy processato da load_pdf_from_bytes | |
| #Ritorna un dizionario dove la chiave è il titolo della sezione e il valore è il testo associato | |
| def extract_logical_sections(doc: Any) -> Dict[str, Any]: | |
| sections = {} | |
| #Questo è un titolo segnaposto per eventuale contenuto iniziale non etichettato da un header | |
| current_title = "preambolo_documento" | |
| sections[current_title] = "" | |
| #Etichette che indicano l'inizio di una NUOVA SEZIONE LOGICA | |
| SECTION_LABELS = ("SECTION_HEADER", "TITLE", "BOLD", "BOLD_CAPTION") | |
| #Etichette di Contenuto (da trattare come corpo testuale) | |
| CONTENT_LABELS = ("TEXT", "LIST", "PARAGRAPH") | |
| if not hasattr(doc, 'spans') or not doc.spans.get ("layout"): | |
| if hasattr(doc, 'text') and doc.text.strip(): | |
| logger.warning("Nessun layout distinto trovato, restituisco il documento completo come sezione unica.") | |
| return {"documento_completo": doc.text.strip()} | |
| return {} | |
| #Itera su tutti gli span etichettati | |
| for span in doc.spans.get("layout", []): | |
| label = span.label_.upper() | |
| span_text = span.text.strip() | |
| if not span_text: | |
| continue | |
| #1. Identificazione e cambio di sezione | |
| if label in SECTION_LABELS: | |
| potential_title = span_text.lower() | |
| #Assicuriamo l'unicità e un minimo di lunghezza | |
| if len(potential_title) > 3 and potential_title not in sections: | |
| current_title = potential_title | |
| sections[current_title] = "" | |
| elif current_title in sections: | |
| #Se il titolo non cambia, aggiungiamo il testo (utile per titoli multi-linea) | |
| sections[current_title] += span_text + "\n" | |
| #2. Gestione Esplicita di informazioni tabulari e immagini | |
| elif label == "TABLE_CAPTION": | |
| #Usiamo la caption come nuovo titolo di sezione temporaneo | |
| current_title = f"tabella: {span_text.lower()[:100]}" | |
| if current_title not in sections: | |
| sections[current_title] = span_text + "\n" | |
| elif label == "FIGURE_CAPTION": | |
| #Usiamo la caption come nuovo titolo di sezione temporaneo (per immagini ora) | |
| current_title = f"figura: {span_text.lower()[:100]}" | |
| if current_title not in sections: | |
| sections[current_title] = span_text + "\n" | |
| #3. Gestione del Testo del Corpo/Contenuto | |
| elif label in CONTENT_LABELS: | |
| #Aggiunge il testo sotto la sezione corrente o preambolo | |
| sections[current_title] += span_text + "\n" | |
| #4. Blocchi di contenuto generici (Es. Table o Figure senza caption) | |
| elif label in ("TABLE", "FIGURE"): | |
| # Se la label è TABLE o FIGURE e non abbiamo ancora una caption, | |
| # usiamo un titolo generico per non perdere il testo. | |
| if "tabella:" not in current_title and "figura:" not in current_title: | |
| current_title = f"blocco_generico_{label.lower()}" | |
| if current_title not in sections: | |
| sections[current_title] = "" | |
| sections[current_title] += span_text + "\n" | |
| #Pulisce le sezioni vuote e rimuove spazi iniziali/finali | |
| cleaned_sections = {k: v.strip() for k, v in sections.items() if v.strip()} | |
| #Gestisce il caso di documenti con molto rumore o layout non convenzionale | |
| if not cleaned_sections and hasattr(doc, 'text') and doc.text.strip(): | |
| logger.warning("Suddivisione per layout fallita, ritorno il documento completo come sezione unica.") | |
| return {"documento_completo": doc.text.strip()} | |
| logger.info(f"Documento suddiviso in {len(cleaned_sections)} sezioni logiche.") | |
| return cleaned_sections |