# PDF → Chunk RAG-ready Converte PDF digitali in chunk semantici pronti per la vettorizzazione RAG, senza LLM né OCR. **Pipeline:** PDF → Markdown strutturato → chunk semantici → embedding ChromaDB **Stack:** Python · PyMuPDF · pdfplumber **Non supportati:** PDF scansionati (solo immagini), PDF protetti da password. --- ## Setup ```bash python -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` --- ## Flusso completo ### 1. Posiziona il PDF ``` sources/.pdf ``` ### 2. Converti il PDF in Markdown ```bash # Singolo documento .venv/bin/python conversione/ --stem # Tutti i PDF in sources/ .venv/bin/python conversione/ # Forza riesecuzione (sovrascrive output esistente) .venv/bin/python conversione/ --stem --force ``` Output in `conversione//`: | 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 | ### 3. Verifica la qualità del Markdown (opzionale) ```bash .venv/bin/python conversione/ validate --detail ``` 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 # Forza riesecuzione .venv/bin/python chunks/chunker.py --stem --force ``` La strategia di chunking (`h3_aware`, `h2_paragraph_split`, `paragraph`, `sliding_window`) viene scelta automaticamente da `structure_profile.json`. Output in `chunks//`: | 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 ``` 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 | ### 6. Correggi i problemi (se necessario) ```bash # Anteprima delle correzioni senza applicarle .venv/bin/python chunks/fix_chunks.py --stem --dry-run # Applica le correzioni (ricorsivo, fino a 3 iterazioni) .venv/bin/python chunks/fix_chunks.py --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. ### 7. Esegui l'ingestion Prima verifica che Ollama e i modelli siano pronti: ```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 # Più documenti → un'unica collection condivisa .venv/bin/python ingestion/ingest.py --collection --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 --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. 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: ```bash .venv/bin/python ollama/test_ollama.py ``` Il modello usato è quello configurato in `config.py` (`OLLAMA_MODEL`). Digita `exit` per uscire. --- ## 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 # Collection multi-documento .venv/bin/python retrieve.py --collection # Modifica il numero di chunk restituiti .venv/bin/python retrieve.py --stem --top-k 10 ``` Nel loop interattivo: | Comando | Effetto | |---------|---------| | `` | Mostra i chunk più simili con score di similarità (testo troncato) | | ` -f` | Testo completo dei chunk | | `exit` | Termina | --- ## RAG interattivo Risponde a domande in linguaggio naturale usando i chunk indicizzati in ChromaDB: ```bash # Singolo documento .venv/bin/python rag.py --stem # Collection multi-documento .venv/bin/python rag.py --collection ``` Nel loop interattivo: | Comando | Effetto | |---------|---------| | `` | Risposta generata dal LLM con contesto dai chunk | | ` -v` | Risposta + chunk recuperati con score di similarità e documento sorgente | | `exit` | Termina | --- ## Test ```bash .venv/bin/python -m pytest tests/ ``` --- ## Riferimenti - [`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