Porta da main la riscrittura completa di conversione/_pipeline/ (9 stadi PyMuPDF) e la suite tests/ senza modificare chunks/, step-8/, rag.py, ollama/, retrieve.py, config.py. requirements.txt: aggiunge PyMuPDF>=1.24.0 e pytest>=8.0, mantiene chromadb, rimuove opendataloader-pdf e pymupdf4llm. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.8 KiB
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/pythonosource .venv/bin/activate. Maipip/pythondi sistema. raw.mdimmutabile: Non modificare mairaw.md. La copia di lavoro è sempreclean.md.- Niente LLM nella pipeline: tutta la logica deve essere rule-based e riproducibile.
Setup
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
# Converti un PDF (posizionalo prima in sources/<nome>.pdf)
.venv/bin/python conversione/ --stem <nome>
# Forza riesecuzione (sovrascrive clean.md esistente)
.venv/bin/python conversione/ --stem <nome> --force
# Tutti i PDF in sources/
.venv/bin/python conversione/
# Validazione batch
.venv/bin/python conversione/ validate
.venv/bin/python conversione/ validate <stem> --detail
# Rimuove l'output di uno stem
bash conversione/clear.sh <nome>
# 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
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):
- Numerazione —
1→ H1,1.1→ H2,1.1.1→ H3 (ha precedenza sul font size) - TOC del PDF — se presente, è autoritativo; allineare i header rilevati alla sua gerarchia
- 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→#### Bdiventa# 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,
<br>, 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 <path|stem>— correggeclean.mdquando la pipeline non basta: sillabazione, artefatti residui, header malformati, gerarchia incoerente.