refactor: rimuove pipeline conversione PDF→MD, delegata a MinerU
Elimina conversione/ (9 stadi PyMuPDF) e tests/ (tutti unit/integration). Il repository gestisce ora solo: pulizia MD, chunking, vettorizzazione e RAG. Aggiorna CLAUDE.md e .gitignore per il nuovo flusso MinerU-first. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,33 +8,50 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
- **Lingua:** Rispondi sempre in italiano.
|
||||
- **Prima di eseguire qualsiasi istruzione**, esponi:
|
||||
1. Come intendi procedere (approccio, file coinvolti, stadi modificati).
|
||||
1. Come intendi procedere (approccio, file coinvolti).
|
||||
2. Se l'istruzione ha problemi concettuali — e perché — con una proposta alternativa.
|
||||
3. Aspetta conferma o correzione prima di toccare il codice, salvo che l'istruzione sia banale (rinomina, formattazione).
|
||||
|
||||
Esempio di risposta corretta a "aggiungi OCR al parser":
|
||||
> "L'OCR contraddice il vincolo 'Niente LLM né OCR nella pipeline' di questo progetto, che richiede output deterministico e riproducibile. Se il problema sono i PDF scansionati, l'approccio corretto è rilevare il caso e restituire un errore esplicito. Procedo in questo senso?"
|
||||
|
||||
---
|
||||
|
||||
## Missione
|
||||
|
||||
Ricostruire la struttura logica di PDF digitali e serializzarla in Markdown **stabile e valido per la vettorizzazione RAG**, senza LLM né OCR.
|
||||
Pipeline RAG su documenti accademici. La conversione PDF → Markdown è delegata a **MinerU** (tool esterno). Questo repository si occupa solo di: pulizia Markdown, chunking, vettorizzazione e retrieval/generazione.
|
||||
|
||||
```
|
||||
PDF → Structured Document Tree → Markdown → Chunks → ChromaDB → RAG
|
||||
MinerU (esterno) → sources/<stem>/auto/<stem>.md
|
||||
↓
|
||||
/prepare-md (pulizia)
|
||||
↓
|
||||
chunker.py (chunking adattivo)
|
||||
↓
|
||||
ingest.py (embedding → ChromaDB)
|
||||
↓
|
||||
rag.py / retrieve.py
|
||||
```
|
||||
|
||||
**Non supportato:** PDF scansionati (immagini), PDF protetti da password.
|
||||
|
||||
---
|
||||
|
||||
## Regole invarianti
|
||||
|
||||
- **Venv:** Usa `.venv/bin/python`. 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.
|
||||
- **Markdown generato solo dall'albero:** Mai da `Block` direttamente — sempre da `Section`.
|
||||
- **Niente LLM nella pipeline:** chunking e pulizia devono essere rule-based e riproducibili.
|
||||
- **Input immutabile:** Non modificare mai `sources/<stem>/auto/<stem>.md` direttamente — usare `/prepare-md` che lavora su una copia.
|
||||
|
||||
---
|
||||
|
||||
## Input — struttura MinerU
|
||||
|
||||
MinerU produce una cartella per ogni documento. Posizionarla in `sources/`:
|
||||
|
||||
```
|
||||
sources/<stem>/auto/<stem>.md ← Markdown principale (input pipeline)
|
||||
sources/<stem>/auto/<stem>_content_list_v2.json ← struttura ricca (chunk, bbox, tipo)
|
||||
sources/<stem>/auto/<stem>_middle.json ← dati intermedi di layout
|
||||
sources/<stem>/auto/images/ ← immagini estratte
|
||||
```
|
||||
|
||||
`<stem>` = nome del documento, usato in tutti i comandi come identificatore.
|
||||
|
||||
---
|
||||
|
||||
@@ -44,107 +61,58 @@ PDF → Structured Document Tree → Markdown → Chunks → ChromaDB → RAG
|
||||
# Setup
|
||||
python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt
|
||||
|
||||
# Converti un PDF (posizionalo prima in sources/<nome>.pdf)
|
||||
.venv/bin/python conversione/ --stem <nome>
|
||||
.venv/bin/python conversione/ --stem <nome> --force # sovrascrive output
|
||||
|
||||
# Chunking
|
||||
.venv/bin/python chunks/chunker.py --stem <nome>
|
||||
# Chunking (legge sources/<stem>/auto/<stem>.md)
|
||||
.venv/bin/python chunks/chunker.py --stem <stem>
|
||||
.venv/bin/python chunks/chunker.py # tutti gli stem
|
||||
|
||||
# Vettorizzazione (richiede Ollama attivo)
|
||||
.venv/bin/python ingestion/ingest.py --stem <nome>
|
||||
.venv/bin/python ingestion/ingest.py --stem <stem>
|
||||
.venv/bin/python ingestion/ingest.py --stem <stem> --force
|
||||
|
||||
# RAG interattivo
|
||||
.venv/bin/python rag.py --stem <nome>
|
||||
.venv/bin/python retrieve.py --stem <nome> # retrieval puro, senza LLM
|
||||
|
||||
# Validazione
|
||||
.venv/bin/python conversione/ validate
|
||||
.venv/bin/python conversione/ validate <stem> --detail
|
||||
|
||||
# Test
|
||||
.venv/bin/python -m pytest tests/
|
||||
.venv/bin/python -m pytest tests/unit/test_stage4.py # singolo file
|
||||
|
||||
# Pulizia output
|
||||
bash conversione/clear.sh <nome>
|
||||
.venv/bin/python rag.py --stem <stem>
|
||||
.venv/bin/python retrieve.py --stem <stem> # retrieval puro, senza LLM
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architettura
|
||||
|
||||
### Pipeline di conversione — `conversione/_pipeline/`
|
||||
|
||||
9 stadi in sequenza, ognuno riceve l'output tipizzato del precedente:
|
||||
|
||||
| Stage | File | Responsabilità |
|
||||
|-------|------|----------------|
|
||||
| 1 | `stage1_metadata.py` | Estrazione span da PyMuPDF (`get_text("dict")`), TOC, dimensioni pagina |
|
||||
| 2 | `stage2_layout.py` | Analisi layout, reading order, tipo blocco |
|
||||
| 3 | `stage3_font.py` | Font profile per documento (body size, cluster, header sizes) |
|
||||
| 4 | `stage4_headers.py` | Classificazione header_candidate (font+bold+numerazione+spacing) |
|
||||
| 5 | `stage5_hierarchy.py` | Inferenza livello H1/H2/H3 (priorità: numerazione > TOC > font size) |
|
||||
| 6 | `stage6_tree.py` | Costruzione albero `Section` con parent-child |
|
||||
| 7 | `stage7_markdown.py` | Serializzazione albero → Markdown raw |
|
||||
| 8 | `stage8_normalize.py` | Riparazione gerarchia (level jump, header vuoti, duplicati) |
|
||||
| 9 | `stage9_validate.py` | Validazione struttura finale |
|
||||
|
||||
Orchestrazione: `runner.py`. Entry point: `conversione/__main__.py`.
|
||||
|
||||
### Modello dati — `conversione/_pipeline/models.py`
|
||||
|
||||
```python
|
||||
Block # span estratto: text, page, bbox, font_size, is_bold, block_type, level
|
||||
Section # nodo albero: title, level, content: list[Block], children: list[Section]
|
||||
FontProfile # body_size, cluster_map, header_sizes
|
||||
```
|
||||
|
||||
### Pipeline RAG — file radice
|
||||
### Chunking — `chunks/`
|
||||
|
||||
| File | Responsabilità |
|
||||
|------|---------------|
|
||||
| `chunks/chunker.py` | Chunking adattivo da `clean.md` + `structure_profile.json` |
|
||||
| `chunks/config.py` | Parametri chunking (TARGET_CHARS, OVERLAP, STRATEGY_OVERRIDES) |
|
||||
| `ingestion/ingest.py` | Embedding Ollama → ChromaDB |
|
||||
| `retrieve.py` | Retrieval puro (debug retrieval senza LLM) |
|
||||
| `rag.py` | Loop RAG interattivo (retrieval + generazione Ollama) |
|
||||
| `config.py` | Parametri globali RAG (TOP_K, TEMPERATURE, OLLAMA_MODEL, EMBED_MODEL) |
|
||||
| `chunker.py` | Chunking adattivo del Markdown; legge `structure_profile.json` per scegliere la strategia |
|
||||
| `config.py` | Parametri: `TARGET_CHARS`, `OVERLAP_SENTENCES`, `CHUNK_TOLERANCE`, `STRATEGY_OVERRIDES` |
|
||||
| `verify_chunks.py` | Verifica qualità chunk (copertura, lunghezze, overlap) |
|
||||
| `fix_chunks.py` | Correzioni post-chunking |
|
||||
|
||||
Output: `chunks/<stem>/chunks.json`, `chunks/<stem>/meta.json`, `chunks/<stem>/report.json`
|
||||
|
||||
### Vettorizzazione — `ingestion/ingest.py`
|
||||
|
||||
Legge `chunks/<stem>/chunks.json`, genera embedding via Ollama (`EMBED_MODEL`), indicizza in ChromaDB persistente (`chroma_db/`). Supporta collection multi-documento (`--collection <nome> --stems doc1 doc2`).
|
||||
|
||||
### RAG — file radice
|
||||
|
||||
| File | Responsabilità |
|
||||
|------|---------------|
|
||||
| `rag.py` | Loop interattivo: retrieval + generazione Ollama |
|
||||
| `retrieve.py` | Retrieval puro (debug senza LLM) |
|
||||
| `config.py` | `TOP_K`, `TEMPERATURE`, `OLLAMA_MODEL`, `EMBED_MODEL`, `SYSTEM_PROMPT`, `OLLAMA_URL` |
|
||||
|
||||
### Output per stem
|
||||
|
||||
```
|
||||
conversione/<stem>/raw.md # immutabile, output stage 7
|
||||
conversione/<stem>/clean.md # con frontmatter YAML, output stage 8-9
|
||||
conversione/<stem>/structure_profile.json
|
||||
conversione/<stem>/report.json
|
||||
chunks/<stem>/chunks.json
|
||||
chroma_db/<stem>/ # collection ChromaDB
|
||||
chunks/<stem>/meta.json
|
||||
chunks/<stem>/report.json
|
||||
chroma_db/<stem>/ ← collection ChromaDB
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Linee guida per la pipeline
|
||||
|
||||
- Le regex per header numbering vanno in `_constants.py`, mai inline.
|
||||
- PyMuPDF è il parser primario. pdfplumber solo per tabelle complesse.
|
||||
- Ogni stage deve essere indipendentemente testabile.
|
||||
- Prima di aggiungere un nuovo segnale a Stage 4, validarlo su almeno 3 PDF.
|
||||
|
||||
### Test richiesti
|
||||
|
||||
| Categoria | Validazione attesa |
|
||||
|-----------|-------------------|
|
||||
| Header numerati | gerarchia corretta, no level skip |
|
||||
| TOC presente | markdown allineato al TOC del PDF |
|
||||
| Font inconsistenti | body non classificato come header |
|
||||
| Header multi-riga | header mergiati, markdown valido |
|
||||
| Tabelle | markdown table con colonne preservate |
|
||||
| Gerarchia rotta artificiale | riparazione automatica |
|
||||
|
||||
---
|
||||
|
||||
## Skills custom
|
||||
|
||||
- `/prepare-md <path|stem>` — corregge `clean.md` quando la pipeline non basta: sillabazione, artefatti, header malformati, gerarchia incoerente.
|
||||
- `/prepare-md <path|stem>` — corregge il Markdown MinerU: sillabazione, artefatti, header malformati, gerarchia incoerente. Opera su una copia, non sull'originale.
|
||||
- `/post-chunk` — verifica e perfeziona i chunk prima della vettorizzazione.
|
||||
|
||||
Reference in New Issue
Block a user