# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Missione Ricostruire la struttura logica di PDF digitali e serializzarla in Markdown **stabile e valido per la vettorizzazione RAG**, senza LLM né OCR. Il Markdown è solo il formato di output finale — la pipeline deve operare su una rappresentazione intermedia strutturata. **Non supportato:** PDF scansionati (immagini), PDF protetti da password. --- ## Regole invarianti - **Lingua:** Rispondi sempre in italiano. - **Venv:** Usa `.venv/bin/python` o `source .venv/bin/activate`. Mai `pip`/`python` di sistema. - **`raw.md` immutabile:** Non modificare mai `raw.md`. La copia di lavoro è sempre `clean.md`. - **Niente LLM nella pipeline:** tutta la logica deve essere rule-based e riproducibile. --- ## Setup ```bash python -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` Dipendenze principali: - **PyMuPDF** (`fitz`) — estrazione primaria con metadati font e coordinate - **pdfplumber** — ricostruzione tabelle (opzionale, non per parsing generico) --- ## Comandi ```bash # Converti un PDF (posizionalo prima in sources/.pdf) .venv/bin/python conversione/ --stem # Forza riesecuzione (sovrascrive clean.md esistente) .venv/bin/python conversione/ --stem --force # Tutti i PDF in sources/ .venv/bin/python conversione/ # Validazione batch .venv/bin/python conversione/ validate .venv/bin/python conversione/ validate --detail # Rimuove l'output di uno stem bash conversione/clear.sh # Test suite .venv/bin/python -m pytest tests/ ``` `--stem` = nome file PDF senza estensione. --- ## Architettura ### Principio fondamentale La pipeline **non converte direttamente PDF → Markdown**. ``` PDF → Structured Document Tree → Markdown ``` Il Markdown è generato solo dall'albero documentale. Non dal testo grezzo. ### Modello dati intermedio ```python class Block: text: str page: int bbox: tuple font_size: float font_name: str is_bold: bool block_type: str # "header" | "paragraph" | "list" | "table" | "code" class Section: title: str level: int # 1, 2, 3 content: list[Block] children: list[Section] ``` Il Markdown si genera **solo** da `Section`. Mai da `Block` direttamente. --- ### I 9 stadi della pipeline #### Stage 1 — Metadata Extraction Usa `page.get_text("dict")` (o `"rawdict"`) di PyMuPDF. **Non usare estrazione plain text.** Per ogni span estrai: testo, font size, font name, flags, bbox, numero di pagina. Estrai anche: TOC del documento, bookmark, dimensioni pagina. #### Stage 2 — Layout Analysis Identifica i blocchi strutturali preservando l'ordine di lettura: headers, paragrafi, liste, tabelle, code block, interruzioni di pagina. #### Stage 3 — Font Analysis Inferisce la gerarchia visiva **per documento** (non hardcoded): - calcola il font size dominante del corpo - raggruppa i font size in cluster - identifica i candidati header per dimensione #### Stage 4 — Header Detection Segnali combinati (tutti richiesti): - font size > corpo testo - boldness / semibold - numerazione (`^\d+(\.\d+)*\s+`) - spaziatura verticale sopra/sotto - lunghezza riga corta #### Stage 5 — Hierarchy Inference Priorità delle regole (in ordine): 1. **Numerazione** — `1` → H1, `1.1` → H2, `1.1.1` → H3 (ha precedenza sul font size) 2. **TOC del PDF** — se presente, è autoritativo; allineare i header rilevati alla sua gerarchia 3. **Font size clustering** — fallback se né numerazione né TOC esistono #### Stage 6 — Document Tree Reconstruction Costruisce l'albero `Section` con relazioni parent-child, ordinamento e nesting. Ogni nodo contiene titolo, livello, contenuto e figli. #### Stage 7 — Markdown Generation Serializza l'albero in Markdown valido: - Header: `#`/`##`/`###` senza salti di livello - Liste: preserva nesting ordered/unordered - Tabelle: GitHub-compatible; fallback testo strutturato - Code block: fenced con language tag dove rilevabile #### Stage 8 — Hierarchy Normalization Ripara le inconsistenze strutturali: - salti di livello invalidi (`# A` → `#### B` diventa `# A` → `## B`) - header vuoti (rimuovi o mergia) - header consecutivi duplicati (collassa) - nesting rotto #### Stage 9 — Structural Validation Valida il Markdown finale: - nessun salto di livello heading - nessuna sezione vuota - liste correttamente annidate - tabelle con colonne consistenti - ordine uguale al PDF sorgente --- ## Cosa rende un Markdown perfetto per la vettorizzazione - **Struttura semantica:** ogni header è un confine naturale di chunk; ogni sezione è un'unità concettuale. - **Gerarchia corretta:** h1/h2/h3 riflettono la struttura logica, non il layout tipografico. - **Testo pulito:** nessun artefatto di encoding, footnote superscript, `
`, dot-leader, PUA. - **Paragrafi interi:** nessuna frase troncata da salto pagina. - **Output deterministico:** stessa pipeline su stesso PDF produce sempre lo stesso output. --- ## Linee guida per sviluppare la pipeline - Ogni stage deve essere **indipendentemente testabile**. - Le regex per header numbering e simili vanno compilate in `_constants.py`, mai inline. - PyMuPDF è il parser primario. pdfplumber si usa solo per tabelle complesse. - Ogni stage deve ricevere l'output del precedente come struttura tipizzata, non testo grezzo. - Prima di aggiungere un nuovo segnale di detection (Stage 4), validarlo su almeno 3 PDF diversi. ### Categorie di test richieste | Categoria | Input | Validazione attesa | |-----------|-------|-------------------| | Header reconstruction | PDF con H1/H2/H3 numerati | gerarchia corretta, no level skip | | TOC alignment | PDF con bookmark/TOC | markdown allineato al TOC | | Mixed font sizes | Font inconsistenti, bold nel corpo | body non classificato come header | | Broken layout | Header multi-riga, spacing irregolare | header mergiati, markdown valido | | Tables | Tabelle nel PDF | markdown table con colonne preservate | | Lists | Liste ordered/unordered annidate | nesting corretto | | Large documents | PDF tecnico voluminoso | output deterministico, memoria stabile | | Invalid hierarchy repair | `# A` + `#### B` artificiale | riparazione automatica in `# A` + `## B` | --- ## Pipeline attuale La pipeline in `conversione/_pipeline/` (basata su trasformazioni testo con `_apply.py`) è **deprecata** e deve essere sostituita dall'architettura a 9 stadi descritta sopra. Durante la migrazione: - separare estrazione da ricostruzione - introdurre strutture intermedie esplicite (`Block`, `Section`) - rimuovere l'architettura parser-centrica - ogni stage deve essere indipendente e testabile --- ## Skills custom - `/prepare-md ` — corregge `clean.md` quando la pipeline non basta: sillabazione, artefatti residui, header malformati, gerarchia incoerente.