docs: README dettagliato MinerU + CLAUDE.md aggiornato per pipeline Stage 1+2
README.md: sezione MinerU espansa con requisiti di sistema, installazione (pip/conda/Docker), CLI completo con tutti i flag, tabella comparativa backend (pipeline/hybrid-auto-engine/vlm-auto-engine), configurazione avanzata, struttura output e limitazioni note. CLAUDE.md: aggiornato diagramma pipeline, input RICHIESTO/RACCOMANDATO, comandi con --force e --skip-optimize, architettura chunker/md_optimizer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,11 +19,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
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.
|
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.
|
||||||
|
|
||||||
```
|
```
|
||||||
MinerU (esterno) → sources/<stem>/auto/<stem>.md
|
MinerU (esterno) → sources/<stem>/auto/
|
||||||
↓
|
↓
|
||||||
/prepare-md (pulizia)
|
chunker.py (Stage 1: _clean.md + Stage 2: chunks.json)
|
||||||
↓
|
|
||||||
chunker.py (chunking adattivo)
|
|
||||||
↓
|
↓
|
||||||
ingest.py (embedding → ChromaDB)
|
ingest.py (embedding → ChromaDB)
|
||||||
↓
|
↓
|
||||||
@@ -36,7 +34,7 @@ MinerU (esterno) → sources/<stem>/auto/<stem>.md
|
|||||||
|
|
||||||
- **Venv:** Usa `.venv/bin/python`. Mai `pip`/`python` di sistema.
|
- **Venv:** Usa `.venv/bin/python`. Mai `pip`/`python` di sistema.
|
||||||
- **Niente LLM nella pipeline:** chunking e pulizia devono essere rule-based e riproducibili.
|
- **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 immutabile:** Non modificare mai i file originali in `sources/<stem>/auto/`. Il `chunker.py` scrive solo `_clean.md` (prodotto derivato) nella stessa cartella e `chunks.json` in `chunks/<stem>/`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -45,9 +43,10 @@ MinerU (esterno) → sources/<stem>/auto/<stem>.md
|
|||||||
MinerU produce una cartella per ogni documento. Posizionarla in `sources/`:
|
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 (tipo, livello, bbox) [RICHIESTO]
|
||||||
sources/<stem>/auto/<stem>_content_list_v2.json ← struttura ricca (chunk, bbox, tipo)
|
sources/<stem>/auto/<stem>_model.json ← label di layout (doc_title, abstract…) [RACCOMANDATO]
|
||||||
sources/<stem>/auto/<stem>_middle.json ← dati intermedi di layout
|
sources/<stem>/auto/<stem>.md ← Markdown grezzo (non usato dalla pipeline)
|
||||||
|
sources/<stem>/auto/<stem>_middle.json ← dati intermedi (non usato)
|
||||||
sources/<stem>/auto/images/ ← immagini estratte
|
sources/<stem>/auto/images/ ← immagini estratte
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -61,9 +60,18 @@ sources/<stem>/auto/images/ ← immagini estratte
|
|||||||
# Setup
|
# Setup
|
||||||
python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt
|
python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt
|
||||||
|
|
||||||
# Chunking (legge sources/<stem>/auto/<stem>.md)
|
# Chunking unificato: Stage 1 (_clean.md) + Stage 2 (chunks.json)
|
||||||
.venv/bin/python chunks/chunker.py --stem <stem>
|
.venv/bin/python chunks/chunker.py --stem <stem>
|
||||||
.venv/bin/python chunks/chunker.py # tutti gli stem
|
.venv/bin/python chunks/chunker.py # tutti gli stem in sources/
|
||||||
|
.venv/bin/python chunks/chunker.py --stem <stem> --force # rigenera tutto
|
||||||
|
.venv/bin/python chunks/chunker.py --stem <stem> --skip-optimize # salta Stage 1
|
||||||
|
|
||||||
|
# Solo Stage 1 (se serve rigenerare solo il _clean.md)
|
||||||
|
.venv/bin/python chunks/md_optimizer.py --stem <stem> --force
|
||||||
|
|
||||||
|
# Verifica e correzione chunk
|
||||||
|
.venv/bin/python chunks/verify_chunks.py --stem <stem>
|
||||||
|
.venv/bin/python chunks/fix_chunks.py --stem <stem>
|
||||||
|
|
||||||
# Vettorizzazione (richiede Ollama attivo)
|
# Vettorizzazione (richiede Ollama attivo)
|
||||||
.venv/bin/python ingestion/ingest.py --stem <stem>
|
.venv/bin/python ingestion/ingest.py --stem <stem>
|
||||||
@@ -82,10 +90,13 @@ python -m venv .venv && source .venv/bin/activate && pip install -r requirements
|
|||||||
|
|
||||||
| File | Responsabilità |
|
| File | Responsabilità |
|
||||||
|------|---------------|
|
|------|---------------|
|
||||||
| `chunker.py` | Chunking adattivo del Markdown; legge `structure_profile.json` per scegliere la strategia |
|
| `chunker.py` | Entry point unificato: chiama `md_optimizer` (Stage 1) poi esegue il chunking (Stage 2) |
|
||||||
| `config.py` | Parametri: `TARGET_CHARS`, `OVERLAP_SENTENCES`, `CHUNK_TOLERANCE`, `STRATEGY_OVERRIDES` |
|
| `md_optimizer.py` | Modulo Stage 1: `_content_list_v2.json` + `_model.json` → `<stem>_clean.md` |
|
||||||
| `verify_chunks.py` | Verifica qualità chunk (copertura, lunghezze, overlap) |
|
| `config.py` | Tutti i parametri: `MAX_CHARS`, `MIN_CHARS`, `OVERLAP_SENTENCES`, `FRONTMATTER_HEADINGS`, `SOMMARIO_PATTERNS`, label sets model.json |
|
||||||
| `fix_chunks.py` | Correzioni post-chunking |
|
| `verify_chunks.py` | Verifica qualità chunk (lunghezze, frasi spezzate, prefissi) |
|
||||||
|
| `fix_chunks.py` | Correzioni post-chunking (merge incompleti, split lunghi) |
|
||||||
|
|
||||||
|
`md_optimizer.py` è generico rispetto al documento: usa le strutture comuni di tutti gli output MinerU (`_content_list_v2.json` e `_model.json`) senza dipendere da pattern testuali lingua-specifici. I parametri documento-specifici (es. `FRONTMATTER_HEADINGS` per documenti italiani) sono in `config.py`.
|
||||||
|
|
||||||
Output: `chunks/<stem>/chunks.json`, `chunks/<stem>/meta.json`, `chunks/<stem>/report.json`
|
Output: `chunks/<stem>/chunks.json`, `chunks/<stem>/meta.json`, `chunks/<stem>/report.json`
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,176 @@
|
|||||||
# PDF → Chunk RAG-ready
|
# RAG su documenti accademici
|
||||||
|
|
||||||
Converte PDF digitali in chunk semantici pronti per la vettorizzazione RAG,
|
Pipeline completa per trasformare PDF accademici in un sistema RAG interrogabile in linguaggio naturale.
|
||||||
senza LLM né OCR.
|
|
||||||
|
|
||||||
**Pipeline:** PDF → Markdown strutturato → chunk semantici → embedding ChromaDB
|
**Stack:** Python · MinerU · ChromaDB · Ollama
|
||||||
**Stack:** Python · PyMuPDF · pdfplumber
|
**Chunking:** rule-based, deterministico, senza LLM
|
||||||
**Non supportati:** PDF scansionati (solo immagini), PDF protetti da password.
|
**Embedding + Generazione:** Ollama (locale)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prerequisiti
|
||||||
|
|
||||||
|
### 1. MinerU — conversione PDF → Markdown strutturato
|
||||||
|
|
||||||
|
MinerU è il tool esterno che converte i PDF in Markdown + metadati strutturati.
|
||||||
|
Repository: [https://github.com/opendatalab/MinerU](https://github.com/opendatalab/MinerU)
|
||||||
|
|
||||||
|
#### Requisiti di sistema
|
||||||
|
|
||||||
|
| Risorsa | Minimo | Raccomandato |
|
||||||
|
|---------|--------|--------------|
|
||||||
|
| Python | 3.10–3.13 | 3.11 |
|
||||||
|
| RAM | 16 GB | 32 GB+ |
|
||||||
|
| Disco | 20 GB (modelli inclusi) | 40 GB+ |
|
||||||
|
| GPU | opzionale | 4–8 GB VRAM (CUDA) |
|
||||||
|
| OS | Linux, macOS, Windows | Linux / WSL2 per Docker |
|
||||||
|
|
||||||
|
#### Installazione
|
||||||
|
|
||||||
|
**pip (raccomandato):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install mineru[all]
|
||||||
|
# oppure con uv (più veloce):
|
||||||
|
uv pip install -U "mineru[all]"
|
||||||
|
```
|
||||||
|
|
||||||
|
**conda:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
conda create -n mineru python=3.11
|
||||||
|
conda activate mineru
|
||||||
|
pip install mineru[all]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Docker (Linux / WSL2 only):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# CPU
|
||||||
|
docker run --rm -v /percorso/locale:/data opendatalab/mineru mineru -p /data/doc.pdf -o /data/output
|
||||||
|
|
||||||
|
# GPU (richiede nvidia-container-toolkit)
|
||||||
|
docker run --rm --gpus all -v /percorso/locale:/data opendatalab/mineru:cuda mineru -p /data/doc.pdf -o /data/output
|
||||||
|
```
|
||||||
|
|
||||||
|
Al primo avvio MinerU scarica automaticamente i modelli (~15 GB). Per forzare il download manuale:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mineru-models-download
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Uso — CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mineru -p <input> -o <output_dir> [opzioni]
|
||||||
|
```
|
||||||
|
|
||||||
|
| Flag | Descrizione | Default |
|
||||||
|
|------|-------------|---------|
|
||||||
|
| `-p` | Percorso PDF, cartella di PDF, o URL | — |
|
||||||
|
| `-o` | Cartella di output | — |
|
||||||
|
| `-b` | Backend di conversione (vedi sotto) | `pipeline` |
|
||||||
|
| `-m` | Metodo di estrazione: `auto`, `txt`, `ocr` | `auto` |
|
||||||
|
| `-l` | Lingua per OCR (es. `it`, `en`, `zh`) | `en` |
|
||||||
|
| `-s` | Pagina iniziale (0-based) | 0 |
|
||||||
|
| `-e` | Pagina finale (0-based, inclusa) | ultima |
|
||||||
|
| `--formula` | Attiva/disattiva riconoscimento formule | config |
|
||||||
|
| `--table` | Attiva/disattiva riconoscimento tabelle | config |
|
||||||
|
|
||||||
|
**Esempio tipico:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mineru -p articolo.pdf -o sources/articolo/
|
||||||
|
# Output in sources/articolo/auto/
|
||||||
|
```
|
||||||
|
|
||||||
|
Per estrarre solo alcune pagine:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mineru -p documento.pdf -o sources/documento/ -s 10 -e 50
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Backend di conversione
|
||||||
|
|
||||||
|
| Backend | Descrizione | Accuratezza | GPU richiesta |
|
||||||
|
|---------|-------------|-------------|---------------|
|
||||||
|
| `pipeline` | CPU-only, modelli leggeri | ~86% | No |
|
||||||
|
| `hybrid-auto-engine` | Combina pipeline + VLM selettivo | ~95%+ | Raccomandato |
|
||||||
|
| `vlm-auto-engine` | VLM completo su tutte le pagine | massima | Sì |
|
||||||
|
| `pipeline-http` / `vlm-http` | Come sopra ma via API remota | — | Remota |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Raccomandato se si ha una GPU con ≥ 4 GB VRAM
|
||||||
|
mineru -p doc.pdf -o output/ -b hybrid-auto-engine
|
||||||
|
|
||||||
|
# Solo CPU
|
||||||
|
mineru -p doc.pdf -o output/ -b pipeline
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Configurazione avanzata
|
||||||
|
|
||||||
|
File di configurazione utente: `~/mineru.json`
|
||||||
|
|
||||||
|
Variabili d'ambiente principali:
|
||||||
|
|
||||||
|
| Variabile | Valori | Effetto |
|
||||||
|
|-----------|--------|---------|
|
||||||
|
| `MINERU_FORMULA_ENABLE` | `0` / `1` | Abilita/disabilita OCR formule matematiche |
|
||||||
|
| `MINERU_TABLE_ENABLE` | `0` / `1` | Abilita/disabilita riconoscimento tabelle |
|
||||||
|
| `MINERU_DEVICE` | `cpu`, `cuda`, `mps` | Forza il dispositivo di inferenza |
|
||||||
|
|
||||||
|
#### Output di MinerU
|
||||||
|
|
||||||
|
MinerU produce per ogni PDF una cartella con questa struttura:
|
||||||
|
|
||||||
|
```
|
||||||
|
<stem>/
|
||||||
|
└── auto/
|
||||||
|
├── <stem>.md ← Markdown grezzo (non usato dalla pipeline)
|
||||||
|
├── <stem>_content_list_v2.json ← struttura ricca: tipo, livello, bbox [RICHIESTO]
|
||||||
|
├── <stem>_model.json ← label di layout: doc_title, abstract… [RACCOMANDATO]
|
||||||
|
├── <stem>_middle.json ← dati intermedi (non usato)
|
||||||
|
├── <stem>_content_list.json ← formato v1 flat (non usato)
|
||||||
|
├── <stem>_layout.pdf ← PDF annotato con i bounding box
|
||||||
|
├── <stem>_span.pdf ← PDF con span di testo evidenziati
|
||||||
|
└── images/ ← immagini estratte
|
||||||
|
```
|
||||||
|
|
||||||
|
`<stem>` è il nome del documento, usato come identificatore in tutta la pipeline.
|
||||||
|
|
||||||
|
I file usati dalla pipeline di questo repository sono:
|
||||||
|
|
||||||
|
- **`_content_list_v2.json`** ← struttura ad albero: ogni blocco ha `type` (title/paragraph/table/list/image), `level` (per i titoli: 1=capitolo, 2=sezione), `content` con il testo, e `bbox` per la posizione sulla pagina.
|
||||||
|
- **`_model.json`** ← label semantiche per bounding box: `doc_title`, `paragraph_title`, `abstract`, `header`, `number`, `text`, `aside_text`… Usato per arricchire la classificazione del testo (es. riconoscere SOMMARIO interni, prefissi di capitolo).
|
||||||
|
|
||||||
|
#### Limitazioni note di MinerU
|
||||||
|
|
||||||
|
- **Testo verticale** (CJK ruotato, riviste asiatiche): qualità ridotta.
|
||||||
|
- **Testo scritto a mano**: accuratezza molto bassa.
|
||||||
|
- **Fumetti e album d'arte**: non supportati.
|
||||||
|
- **Blocchi di codice**: non sempre preservati correttamente (indentazione può essere persa).
|
||||||
|
- **PDF scansionati senza OCR**: richiede backend con OCR attivo (`-m ocr`).
|
||||||
|
- **Formule matematiche complesse**: dipendono dalla qualità del rendering PDF originale.
|
||||||
|
|
||||||
|
### 2. Ollama — embedding e generazione
|
||||||
|
|
||||||
|
Scarica e avvia [Ollama](https://ollama.com), poi installa i modelli:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ollama pull nomic-embed-text # embedding (obbligatorio)
|
||||||
|
ollama pull qwen3.5:4b # generazione LLM (o altro modello)
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
git clone <questo-repo>
|
||||||
|
cd rag
|
||||||
|
|
||||||
python -m venv .venv
|
python -m venv .venv
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -21,226 +178,206 @@ pip install -r requirements.txt
|
|||||||
|
|
||||||
## Flusso completo
|
## Flusso completo
|
||||||
|
|
||||||
### 1. Posiziona il PDF
|
|
||||||
|
|
||||||
```
|
```
|
||||||
sources/<nome>.pdf
|
PDF
|
||||||
|
│
|
||||||
|
▼ (MinerU — esterno)
|
||||||
|
sources/<stem>/auto/
|
||||||
|
│
|
||||||
|
▼ python chunks/chunker.py --stem <stem>
|
||||||
|
│ Stage 1: _content_list_v2.json + _model.json → <stem>_clean.md
|
||||||
|
│ Stage 2: <stem>_clean.md → chunks/<stem>/chunks.json
|
||||||
|
│
|
||||||
|
▼ python chunks/verify_chunks.py --stem <stem>
|
||||||
|
│ Verifica qualità chunk
|
||||||
|
│
|
||||||
|
▼ python chunks/fix_chunks.py --stem <stem> [se necessario]
|
||||||
|
│ Correzioni automatiche
|
||||||
|
│
|
||||||
|
▼ python ingestion/ingest.py --stem <stem>
|
||||||
|
│ Embedding → ChromaDB
|
||||||
|
│
|
||||||
|
▼ python rag.py --stem <stem>
|
||||||
|
Interrogazione in linguaggio naturale
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Converti il PDF in Markdown
|
---
|
||||||
|
|
||||||
|
### Passo 1 — Converti il PDF con MinerU
|
||||||
|
|
||||||
|
Usa MinerU per convertire il PDF e posiziona la cartella di output in `sources/`:
|
||||||
|
|
||||||
|
```
|
||||||
|
sources/
|
||||||
|
└── <stem>/
|
||||||
|
└── auto/
|
||||||
|
├── <stem>_content_list_v2.json
|
||||||
|
├── <stem>_model.json
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Passo 2 — Chunking (Stage 1 + Stage 2)
|
||||||
|
|
||||||
|
Un singolo comando esegue entrambe le fasi:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Singolo documento
|
# Singolo documento
|
||||||
.venv/bin/python conversione/ --stem <nome>
|
.venv/bin/python chunks/chunker.py --stem <stem>
|
||||||
|
|
||||||
# Tutti i PDF in sources/
|
# Tutti i documenti in sources/
|
||||||
.venv/bin/python conversione/
|
.venv/bin/python chunks/chunker.py
|
||||||
|
|
||||||
# Forza riesecuzione (sovrascrive output esistente)
|
# Rigenera tutto da zero
|
||||||
.venv/bin/python conversione/ --stem <nome> --force
|
.venv/bin/python chunks/chunker.py --stem <stem> --force
|
||||||
|
|
||||||
|
# Salta Stage 1 (usa il _clean.md già presente)
|
||||||
|
.venv/bin/python chunks/chunker.py --stem <stem> --skip-optimize
|
||||||
```
|
```
|
||||||
|
|
||||||
Output in `conversione/<nome>/`:
|
**Stage 1 — Ottimizzazione Markdown** (`md_optimizer.py` interno):
|
||||||
|
- Legge `_content_list_v2.json` e `_model.json`
|
||||||
|
- Riconosce la gerarchia heading (H1 = capitolo, H2 = sezione, H3 = sottosezione)
|
||||||
|
- Fonde titoli di capitolo multipli: `CAPITOLO 2` + `Il titolo` → `# CAPITOLO 2 — Il titolo`
|
||||||
|
- Rimuove TOC, frontespizio, copyright, indici e sommari interni
|
||||||
|
- Produce `sources/<stem>/auto/<stem>_clean.md`
|
||||||
|
|
||||||
| File | Descrizione |
|
**Stage 2 — Chunking semantico**:
|
||||||
|------|-------------|
|
- Un chunk per paragrafo — mai due paragrafi nello stesso chunk
|
||||||
| `raw.md` | Markdown grezzo — **non modificare** |
|
- Split a confine di frase se il paragrafo supera `MAX_CHARS` (default 1200 chars)
|
||||||
| `clean.md` | Markdown pulito — input per il chunker |
|
- Overlap di 1 frase tra chunk consecutivi per continuità contestuale
|
||||||
| `structure_profile.json` | Struttura rilevata e strategia di chunking |
|
- Tabelle e liste sono blocchi atomici (non vengono mai spezzati)
|
||||||
| `report.json` | Metriche di qualità della conversione |
|
- Ogni chunk include un prefisso `[Sezione > Titolo]` per il retrieval
|
||||||
|
|
||||||
### 3. Verifica la qualità del Markdown (opzionale)
|
Output in `chunks/<stem>/`:
|
||||||
|
|
||||||
|
| File | Contenuto |
|
||||||
|
|------|-----------|
|
||||||
|
| `chunks.json` | Lista di chunk con testo, sezione, titolo, n_chars |
|
||||||
|
| `meta.json` | Parametri usati (max_chars, overlap, strategia) |
|
||||||
|
| `report.json` | Statistiche e anomalie (generato da verify) |
|
||||||
|
|
||||||
|
### Passo 3 — Verifica i chunk
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
.venv/bin/python conversione/ validate <nome> --detail
|
.venv/bin/python chunks/verify_chunks.py --stem <stem>
|
||||||
```
|
```
|
||||||
|
|
||||||
Se lo score è ≥ 80 e `valid=true`, procedi. Altrimenti usa `/prepare-md` per
|
|
||||||
correzioni manuali (sillabazione residua, header malformati, ecc.).
|
|
||||||
|
|
||||||
### 4. Genera i chunk
|
|
||||||
|
|
||||||
```bash
|
|
||||||
.venv/bin/python chunks/chunker.py --stem <nome>
|
|
||||||
|
|
||||||
# Forza riesecuzione
|
|
||||||
.venv/bin/python chunks/chunker.py --stem <nome> --force
|
|
||||||
```
|
|
||||||
|
|
||||||
La strategia di chunking (`h3_aware`, `h2_paragraph_split`, `paragraph`,
|
|
||||||
`sliding_window`) viene scelta automaticamente da `structure_profile.json`.
|
|
||||||
|
|
||||||
Output in `chunks/<nome>/`:
|
|
||||||
|
|
||||||
| File | Descrizione |
|
|
||||||
|------|-------------|
|
|
||||||
| `chunks.json` | Lista di chunk con testo, sezione, titolo e metadati |
|
|
||||||
| `report.json` | Statistiche e anomalie del chunking |
|
|
||||||
|
|
||||||
### 5. Verifica i chunk
|
|
||||||
|
|
||||||
```bash
|
|
||||||
.venv/bin/python chunks/verify_chunks.py --stem <nome>
|
|
||||||
```
|
|
||||||
|
|
||||||
Verdict possibili:
|
|
||||||
|
|
||||||
| Verdict | Significato | Cosa fare |
|
| Verdict | Significato | Cosa fare |
|
||||||
|---------|-------------|-----------|
|
|---------|-------------|-----------|
|
||||||
| `ok` | Nessun problema | Procedi alla vettorizzazione |
|
| `ok` | Nessun problema | Procedi alla vettorizzazione |
|
||||||
| `warnings_only` | Solo avvisi minori | Puoi procedere o eseguire il fix |
|
| `warnings_only` | Solo avvisi minori (frasi lunghe) | Puoi procedere |
|
||||||
| `blocked` | Problemi bloccanti (chunk incompleti) | Esegui il fix |
|
| `blocked` | Chunk incompleti o senza prefisso | Esegui il fix |
|
||||||
|
|
||||||
### 6. Correggi i problemi (se necessario)
|
### Passo 4 — Correggi i problemi (se verdict = `blocked`)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Anteprima delle correzioni senza applicarle
|
# Anteprima senza applicare
|
||||||
.venv/bin/python chunks/fix_chunks.py --stem <nome> --dry-run
|
.venv/bin/python chunks/fix_chunks.py --stem <stem> --dry-run
|
||||||
|
|
||||||
# Applica le correzioni (ricorsivo, fino a 3 iterazioni)
|
# Applica le correzioni
|
||||||
.venv/bin/python chunks/fix_chunks.py --stem <nome>
|
.venv/bin/python chunks/fix_chunks.py --stem <stem>
|
||||||
```
|
```
|
||||||
|
|
||||||
Il fix gestisce automaticamente: chunk incompleti (frase spezzata), chunk
|
Il fix risolve automaticamente: chunk incompleti (frase spezzata), chunk troppo corti (accorpati al successivo), chunk troppo lunghi (spezzati su punteggiatura). Itera fino alla convergenza o per un massimo di `FIX_MAX_ITERATIONS` passate.
|
||||||
troppo corti (accorpa al successivo), chunk eccessivamente lunghi (spezza
|
|
||||||
su punteggiatura). Ogni chunk termina sempre su un confine di frase.
|
|
||||||
|
|
||||||
### 7. Esegui l'ingestion
|
### Passo 5 — Vettorizzazione
|
||||||
|
|
||||||
Prima verifica che Ollama e i modelli siano pronti:
|
Verifica che Ollama sia attivo, poi:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
.venv/bin/python ollama/check_env.py
|
# Singolo documento → collection omonima
|
||||||
```
|
.venv/bin/python ingestion/ingest.py --stem <stem>
|
||||||
|
|
||||||
Poi genera gli embedding e salva in ChromaDB:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Singolo documento → collection con lo stesso nome
|
|
||||||
.venv/bin/python ingestion/ingest.py --stem <nome>
|
|
||||||
|
|
||||||
# Più documenti → un'unica collection condivisa
|
# Più documenti → un'unica collection condivisa
|
||||||
.venv/bin/python ingestion/ingest.py --collection <nome-collection> --stems doc1 doc2 doc3
|
.venv/bin/python ingestion/ingest.py --collection <nome> --stems doc1 doc2 doc3
|
||||||
|
|
||||||
# Tutti i documenti in chunks/ → collection separate
|
# Rigenera dopo aver aggiornato i chunk o cambiato modello embedding
|
||||||
.venv/bin/python ingestion/ingest.py
|
.venv/bin/python ingestion/ingest.py --stem <stem> --force
|
||||||
|
|
||||||
# Rigenera dopo aver cambiato modello o aggiornato i chunk
|
|
||||||
.venv/bin/python ingestion/ingest.py --stem <nome> --force
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Con `--collection` i chunk di documenti diversi vengono uniti in una singola
|
> Se cambi `EMBED_MODEL` in `config.py`, devi rilanciare l'ingestion con `--force`.
|
||||||
collection. Il metadato `source` identifica il documento di provenienza di ogni chunk.
|
|
||||||
|
|
||||||
Output in `chroma_db/` (ignorata da git).
|
### Passo 6 — Interrogazione
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Configurazione del chunking
|
|
||||||
|
|
||||||
Tutti i parametri sono in [`chunks/config.py`](chunks/config.py):
|
|
||||||
|
|
||||||
```python
|
|
||||||
TARGET_CHARS = 600 # dimensione target dei chunk
|
|
||||||
CHUNK_TOLERANCE = 0.25 # ±25% → range accettabile [450, 750]
|
|
||||||
OVERLAP_SENTENCES = 1 # frasi di overlap tra chunk consecutivi
|
|
||||||
PROTECT_TABLES = True # tabelle emesse come chunk atomici
|
|
||||||
FIX_MAX_ITERATIONS = 3 # iterazioni massime del fix ricorsivo
|
|
||||||
```
|
|
||||||
|
|
||||||
Per ogni strategia è possibile definire valori diversi tramite `STRATEGY_OVERRIDES`.
|
|
||||||
Modificare solo questo file — chunker, verify e fix si aggiornano automaticamente.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Configurazione modelli
|
|
||||||
|
|
||||||
Tutti i parametri LLM e embedding sono in [`config.py`](config.py):
|
|
||||||
|
|
||||||
```python
|
|
||||||
OLLAMA_MODEL = "qwen3.5:4b" # modello LLM per la generazione
|
|
||||||
EMBED_MODEL = "nomic-embed-text" # modello embedding (deve coincidere con l'ingestion)
|
|
||||||
TEMPERATURE = 0.2 # 0.0 = deterministico, valori alti = più creativo
|
|
||||||
NO_THINK = True # True = risposta diretta (più veloce), False = con ragionamento
|
|
||||||
TOP_K = 6 # numero di chunk recuperati per ogni domanda
|
|
||||||
OLLAMA_URL = "http://localhost:11434"
|
|
||||||
```
|
|
||||||
|
|
||||||
> Se cambi `EMBED_MODEL` devi rieseguire l'ingestion con `--force` — gli embedding
|
|
||||||
> devono essere prodotti dallo stesso modello usato nel retrieval.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testare il modello (senza RAG)
|
|
||||||
|
|
||||||
Verifica che il modello LLM risponda correttamente prima di coinvolgere la pipeline:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
.venv/bin/python ollama/test_ollama.py
|
# RAG interattivo
|
||||||
|
.venv/bin/python rag.py --stem <stem>
|
||||||
|
.venv/bin/python rag.py --collection <nome>
|
||||||
|
|
||||||
|
# Retrieval puro (debug, senza generazione LLM)
|
||||||
|
.venv/bin/python retrieve.py --stem <stem>
|
||||||
|
.venv/bin/python retrieve.py --stem <stem> --top-k 10
|
||||||
```
|
```
|
||||||
|
|
||||||
Il modello usato è quello configurato in `config.py` (`OLLAMA_MODEL`).
|
Comandi nel loop interattivo di `retrieve.py`:
|
||||||
Digita `exit` per uscire.
|
|
||||||
|
|
||||||
---
|
| Input | Effetto |
|
||||||
|
|-------|---------|
|
||||||
## Retrieval puro (senza generazione)
|
| `<query>` | Chunk più simili con score (testo troncato) |
|
||||||
|
|
||||||
Utile per verificare che i chunk giusti vengano recuperati prima di diagnosticare
|
|
||||||
risposte sbagliate:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Singolo documento
|
|
||||||
.venv/bin/python retrieve.py --stem <nome>
|
|
||||||
|
|
||||||
# Collection multi-documento
|
|
||||||
.venv/bin/python retrieve.py --collection <nome-collection>
|
|
||||||
|
|
||||||
# Modifica il numero di chunk restituiti
|
|
||||||
.venv/bin/python retrieve.py --stem <nome> --top-k 10
|
|
||||||
```
|
|
||||||
|
|
||||||
Nel loop interattivo:
|
|
||||||
|
|
||||||
| Comando | Effetto |
|
|
||||||
|---------|---------|
|
|
||||||
| `<query>` | Mostra i chunk più simili con score di similarità (testo troncato) |
|
|
||||||
| `<query> -f` | Testo completo dei chunk |
|
| `<query> -f` | Testo completo dei chunk |
|
||||||
| `exit` | Termina |
|
| `exit` | Termina |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## RAG interattivo
|
## Configurazione
|
||||||
|
|
||||||
Risponde a domande in linguaggio naturale usando i chunk indicizzati in ChromaDB:
|
### Parametri di chunking — `chunks/config.py`
|
||||||
|
|
||||||
```bash
|
| Parametro | Default | Descrizione |
|
||||||
# Singolo documento
|
|-----------|---------|-------------|
|
||||||
.venv/bin/python rag.py --stem <nome>
|
| `MAX_CHARS` | 1200 | Lunghezza massima chunk in caratteri |
|
||||||
|
| `MIN_CHARS` | 80 | Soglia minima (warning sotto questa soglia) |
|
||||||
|
| `OVERLAP_SENTENCES` | 1 | Frasi di overlap tra chunk consecutivi |
|
||||||
|
| `MIN_CONTENT_CHARS` | 2500 | Soglia per distinguere frontespizio da contenuto reale |
|
||||||
|
| `FRONTMATTER_HEADINGS` | set italiano | Sezioni da rimuovere (Sommario, Indice, Autori…) — svuotare per documenti non italiani |
|
||||||
|
| `SOMMARIO_PATTERNS` | 5 lingue | Pattern regex per sommari interni da saltare |
|
||||||
|
| `CHAPTER_PREFIX_PATTERNS` | 4 lingue | Pattern per prefissi di capitolo come paragrafi separati |
|
||||||
|
| `MODEL_SKIP_LABELS` | set | Label `_model.json` da ignorare (header, number…) |
|
||||||
|
|
||||||
# Collection multi-documento
|
### Parametri RAG — `config.py`
|
||||||
.venv/bin/python rag.py --collection <nome-collection>
|
|
||||||
```
|
|
||||||
|
|
||||||
Nel loop interattivo:
|
| Parametro | Default | Descrizione |
|
||||||
|
|-----------|---------|-------------|
|
||||||
| Comando | Effetto |
|
| `OLLAMA_MODEL` | `qwen3.5:4b` | Modello LLM per la generazione |
|
||||||
|---------|---------|
|
| `EMBED_MODEL` | `nomic-embed-text` | Modello embedding |
|
||||||
| `<domanda>` | Risposta generata dal LLM con contesto dai chunk |
|
| `TOP_K` | 6 | Chunk recuperati per domanda |
|
||||||
| `<domanda> -v` | Risposta + chunk recuperati con score di similarità e documento sorgente |
|
| `TEMPERATURE` | 0.2 | Creatività del modello (0 = deterministico) |
|
||||||
| `exit` | Termina |
|
| `OLLAMA_URL` | `localhost:11434` | URL server Ollama |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Test
|
## Struttura del repository
|
||||||
|
|
||||||
```bash
|
```
|
||||||
.venv/bin/python -m pytest tests/
|
rag/
|
||||||
|
├── sources/ ← output di MinerU (una cartella per documento)
|
||||||
|
│ └── <stem>/auto/
|
||||||
|
├── chunks/
|
||||||
|
│ ├── chunker.py ← pipeline unificata (Stage 1 + Stage 2)
|
||||||
|
│ ├── md_optimizer.py ← Stage 1: JSON MinerU → _clean.md
|
||||||
|
│ ├── config.py ← tutti i parametri di chunking
|
||||||
|
│ ├── verify_chunks.py ← verifica qualità
|
||||||
|
│ └── fix_chunks.py ← correzioni automatiche
|
||||||
|
├── ingestion/
|
||||||
|
│ └── ingest.py ← embedding → ChromaDB
|
||||||
|
├── ollama/
|
||||||
|
│ └── check_env.py ← verifica ambiente Ollama
|
||||||
|
├── chroma_db/ ← database vettoriale (ignorato da git)
|
||||||
|
├── config.py ← parametri RAG (modelli, TOP_K, prompt)
|
||||||
|
├── rag.py ← loop RAG interattivo
|
||||||
|
└── retrieve.py ← retrieval puro (debug)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Riferimenti
|
## Note su generalità e adattamento
|
||||||
|
|
||||||
- [`conversione/README.md`](conversione/README.md) — dettagli sulla pipeline PDF→Markdown e sui tipi di documento supportati
|
La pipeline è progettata per funzionare con **qualsiasi output MinerU**, non solo per documenti in italiano. MinerU produce sempre la stessa struttura di file (`_content_list_v2.json`, `_model.json`) indipendentemente dal documento sorgente.
|
||||||
- [`ingestion/README.md`](ingestion/README.md) — configurazione embedding, scelta modello, regole --force
|
|
||||||
|
Per adattare a documenti in altre lingue o con struttura diversa, modificare in `chunks/config.py`:
|
||||||
|
|
||||||
|
- **`FRONTMATTER_HEADINGS`**: impostare `set()` per disabilitare, o aggiungere i nomi delle sezioni da rimuovere nella lingua del documento
|
||||||
|
- **`SOMMARIO_PATTERNS`**: aggiungere/rimuovere pattern regex per i sommari interni
|
||||||
|
- **`CHAPTER_PREFIX_PATTERNS`**: aggiungere pattern per la lingua del documento
|
||||||
|
- **`MIN_CONTENT_CHARS`**: alzare se il documento ha lunghe sezioni di copyright/prefazione da escludere
|
||||||
|
- **`MIN_TOC_HEADINGS`**: abbassare se il documento ha pochi capitoli (es. 3-4)
|
||||||
|
|||||||
Reference in New Issue
Block a user