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:
2026-05-20 16:08:00 +02:00
parent 156b1ebba4
commit 98653464dd
2 changed files with 335 additions and 187 deletions
+25 -14
View File
@@ -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.
```
MinerU (esterno) → sources/<stem>/auto/<stem>.md
MinerU (esterno) → sources/<stem>/auto/
/prepare-md (pulizia)
chunker.py (chunking adattivo)
chunker.py (Stage 1: _clean.md + Stage 2: chunks.json)
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.
- **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/`:
```
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.jsondati intermedi di layout
sources/<stem>/auto/<stem>_content_list_v2.json ← struttura ricca (tipo, livello, bbox) [RICHIESTO]
sources/<stem>/auto/<stem>_model.json ← label di layout (doc_title, abstract…) [RACCOMANDATO]
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
```
@@ -61,9 +60,18 @@ sources/<stem>/auto/images/ ← immagini estratte
# Setup
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 # 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)
.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à |
|------|---------------|
| `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 |
| `chunker.py` | Entry point unificato: chiama `md_optimizer` (Stage 1) poi esegue il chunking (Stage 2) |
| `md_optimizer.py` | Modulo Stage 1: `_content_list_v2.json` + `_model.json``<stem>_clean.md` |
| `config.py` | Tutti i parametri: `MAX_CHARS`, `MIN_CHARS`, `OVERLAP_SENTENCES`, `FRONTMATTER_HEADINGS`, `SOMMARIO_PATTERNS`, label sets model.json |
| `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`
+309 -172
View File
@@ -1,19 +1,176 @@
# PDF → Chunk RAG-ready
# RAG su documenti accademici
Converte PDF digitali in chunk semantici pronti per la vettorizzazione RAG,
senza LLM né OCR.
Pipeline completa per trasformare PDF accademici in un sistema RAG interrogabile in linguaggio naturale.
**Pipeline:** PDF → Markdown strutturato → chunk semantici → embedding ChromaDB
**Stack:** Python · PyMuPDF · pdfplumber
**Non supportati:** PDF scansionati (solo immagini), PDF protetti da password.
**Stack:** Python · MinerU · ChromaDB · Ollama
**Chunking:** rule-based, deterministico, senza LLM
**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.103.13 | 3.11 |
| RAM | 16 GB | 32 GB+ |
| Disco | 20 GB (modelli inclusi) | 40 GB+ |
| GPU | opzionale | 48 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
```bash
git clone <questo-repo>
cd rag
python -m venv .venv
source .venv/bin/activate
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
```
@@ -21,226 +178,206 @@ pip install -r requirements.txt
## 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
# Singolo documento
.venv/bin/python conversione/ --stem <nome>
.venv/bin/python chunks/chunker.py --stem <stem>
# Tutti i PDF in sources/
.venv/bin/python conversione/
# Tutti i documenti in sources/
.venv/bin/python chunks/chunker.py
# Forza riesecuzione (sovrascrive output esistente)
.venv/bin/python conversione/ --stem <nome> --force
# Rigenera tutto da zero
.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 |
|------|-------------|
| `raw.md` | Markdown grezzo — **non modificare** |
| `clean.md` | Markdown pulito — input per il chunker |
| `structure_profile.json` | Struttura rilevata e strategia di chunking |
| `report.json` | Metriche di qualità della conversione |
**Stage 2 — Chunking semantico**:
- Un chunk per paragrafo — mai due paragrafi nello stesso chunk
- Split a confine di frase se il paragrafo supera `MAX_CHARS` (default 1200 chars)
- Overlap di 1 frase tra chunk consecutivi per continuità contestuale
- Tabelle e liste sono blocchi atomici (non vengono mai spezzati)
- 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
.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 |
|---------|-------------|-----------|
| `ok` | Nessun problema | Procedi alla vettorizzazione |
| `warnings_only` | Solo avvisi minori | Puoi procedere o eseguire il fix |
| `blocked` | Problemi bloccanti (chunk incompleti) | Esegui il fix |
| `warnings_only` | Solo avvisi minori (frasi lunghe) | Puoi procedere |
| `blocked` | Chunk incompleti o senza prefisso | Esegui il fix |
### 6. Correggi i problemi (se necessario)
### Passo 4 — Correggi i problemi (se verdict = `blocked`)
```bash
# Anteprima delle correzioni senza applicarle
.venv/bin/python chunks/fix_chunks.py --stem <nome> --dry-run
# Anteprima senza applicare
.venv/bin/python chunks/fix_chunks.py --stem <stem> --dry-run
# Applica le correzioni (ricorsivo, fino a 3 iterazioni)
.venv/bin/python chunks/fix_chunks.py --stem <nome>
# Applica le correzioni
.venv/bin/python chunks/fix_chunks.py --stem <stem>
```
Il fix gestisce automaticamente: chunk incompleti (frase spezzata), chunk
troppo corti (accorpa al successivo), chunk eccessivamente lunghi (spezza
su punteggiatura). Ogni chunk termina sempre su un confine di frase.
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.
### 7. Esegui l'ingestion
### Passo 5 — Vettorizzazione
Prima verifica che Ollama e i modelli siano pronti:
Verifica che Ollama sia attivo, poi:
```bash
.venv/bin/python ollama/check_env.py
```
Poi genera gli embedding e salva in ChromaDB:
```bash
# Singolo documento → collection con lo stesso nome
.venv/bin/python ingestion/ingest.py --stem <nome>
# Singolo documento → collection omonima
.venv/bin/python ingestion/ingest.py --stem <stem>
# 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
.venv/bin/python ingestion/ingest.py
# Rigenera dopo aver cambiato modello o aggiornato i chunk
.venv/bin/python ingestion/ingest.py --stem <nome> --force
# Rigenera dopo aver aggiornato i chunk o cambiato modello embedding
.venv/bin/python ingestion/ingest.py --stem <stem> --force
```
Con `--collection` i chunk di documenti diversi vengono uniti in una singola
collection. Il metadato `source` identifica il documento di provenienza di ogni chunk.
> Se cambi `EMBED_MODEL` in `config.py`, devi rilanciare l'ingestion con `--force`.
Output in `chroma_db/` (ignorata da git).
---
## 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:
### Passo 6 — Interrogazione
```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`).
Digita `exit` per uscire.
Comandi nel loop interattivo di `retrieve.py`:
---
## Retrieval puro (senza generazione)
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) |
| Input | Effetto |
|-------|---------|
| `<query>` | Chunk più simili con score (testo troncato) |
| `<query> -f` | Testo completo dei chunk |
| `exit` | Termina |
---
## RAG interattivo
## Configurazione
Risponde a domande in linguaggio naturale usando i chunk indicizzati in ChromaDB:
### Parametri di chunking — `chunks/config.py`
```bash
# Singolo documento
.venv/bin/python rag.py --stem <nome>
| Parametro | Default | Descrizione |
|-----------|---------|-------------|
| `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
.venv/bin/python rag.py --collection <nome-collection>
```
### Parametri RAG — `config.py`
Nel loop interattivo:
| Comando | Effetto |
|---------|---------|
| `<domanda>` | Risposta generata dal LLM con contesto dai chunk |
| `<domanda> -v` | Risposta + chunk recuperati con score di similarità e documento sorgente |
| `exit` | Termina |
| Parametro | Default | Descrizione |
|-----------|---------|-------------|
| `OLLAMA_MODEL` | `qwen3.5:4b` | Modello LLM per la generazione |
| `EMBED_MODEL` | `nomic-embed-text` | Modello embedding |
| `TOP_K` | 6 | Chunk recuperati per domanda |
| `TEMPERATURE` | 0.2 | Creatività del modello (0 = deterministico) |
| `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
- [`ingestion/README.md`](ingestion/README.md) — configurazione embedding, scelta modello, regole --force
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.
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)