diff --git a/CLAUDE.md b/CLAUDE.md index 4208212..9f06295 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,17 +16,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Missione -Pipeline RAG su documenti accademici. La conversione PDF → Markdown è delegata a **MinerU** (tool esterno). Questo repository si occupa solo di: chunking, vettorizzazione e retrieval/generazione. +Pipeline RAG su documenti PDF, interamente in locale. La conversione PDF → Markdown è delegata a **MinerU** (tool esterno). Questo repository si occupa di: chunking, vettorizzazione, retrieval/generazione e GUI desktop. -``` -MinerU (esterno) → sources/_output/auto/.md - ↓ - chunker.py (chunks.json) - ↓ - ingest.py (embedding → ChromaDB) - ↓ - rag.py / retrieve.py -``` +Il PDF viene convertito da MinerU in Markdown strutturato. Il chunker lo analizza e produce chunk semantici. Il modulo di ingest genera gli embedding tramite Ollama e li indicizza in ChromaDB. Infine `rag/rag.py` (o la GUI) riceve la domanda, recupera i chunk più rilevanti e genera la risposta. --- @@ -34,20 +26,18 @@ MinerU (esterno) → sources/_output/auto/.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 i file in `sources/`. Il `chunker.py` scrive solo in `chunks//`. +- **Input immutabile:** Non modificare mai i file in `sources/`. Il chunker scrive solo in `chunks//`. --- ## Input — struttura MinerU -MinerU produce una cartella per ogni documento. Posizionarla in `sources/`: - ``` sources/_output/auto/.md ← Markdown strutturato (input della pipeline) sources/_output/auto/images/ ← immagini estratte ``` -`` = nome del documento, usato in tutti i comandi come identificatore. +`` = nome del documento, usato come identificatore in tutti i comandi. --- @@ -59,19 +49,28 @@ python -m venv .venv && source .venv/bin/activate && pip install -r requirements # Chunking .venv/bin/python chunks/chunker.py --stem -.venv/bin/python chunks/chunker.py # tutti gli stem in sources/ -.venv/bin/python chunks/chunker.py --stem --force # rigenera anche se già presente - -# Verifica qualità chunk -.venv/bin/python chunks/verify_chunks.py --stem +.venv/bin/python chunks/chunker.py # tutti gli stem in sources/ +.venv/bin/python chunks/chunker.py --stem --force # rigenera anche se già presente # Vettorizzazione (richiede Ollama attivo) .venv/bin/python ingestion/ingest.py --stem +.venv/bin/python ingestion/ingest.py --collection --stems doc1 doc2 doc3 .venv/bin/python ingestion/ingest.py --stem --force # RAG interattivo -.venv/bin/python rag.py --stem -.venv/bin/python retrieve.py --stem # retrieval puro, senza LLM +.venv/bin/python rag/rag.py --collection +.venv/bin/python rag/rag.py --stem + +# Retrieval puro (debug senza LLM) +.venv/bin/python rag/retrieve.py --stem +.venv/bin/python rag/retrieve.py --collection --top-k 10 + +# GUI desktop +.venv/bin/python gui/main.py +.venv/bin/python gui/main.py --collection + +# Verifica ambiente Ollama +.venv/bin/python ollama/check_env.py ``` --- @@ -82,42 +81,61 @@ python -m venv .venv && source .venv/bin/activate && pip install -r requirements | File | Responsabilità | |------|---------------| -| `chunker.py` | Legge `.md`, produce `chunks.json` con regole deterministiche | -| `config.py` | Parametri: `MAX_CHARS`, `MIN_CHARS`, `CONTEXT_DEPTH`, `SKIP_HEADINGS`, `ATOMIC_TYPES` | -| `verify_chunks.py` | Verifica qualità chunk (lunghezze, frasi spezzate, prefissi) | +| `chunker.py` | Entry point: legge `.md`, orchestra parser → segmenter → packer → validator | +| `parser.py` | Markdown → AST di `Block` tramite markdown-it-py | +| `segmenter.py` | AST → sequenza di `Block` con header_path e contesto heading | +| `packer.py` | `Block[]` → `Chunk[]` con packing min/target/max | +| `validator.py` | Verifica integrità e coerenza dei chunk prodotti | +| `models.py` | Dataclass: `Block`, `Chunk`, `Diagnostics`, `ChunkingResult` | +| `config.py` | `ChunkerConfig`: `max_chars`, `min_chars`, `target_chars`, `context_depth`, `skip_headings`, `atomic_types` | -Regole applicate dal chunker: -- 1 paragrafo = 1 chunk; paragrafi di sezioni diverse non si mescolano -- Split a confine di frase se il paragrafo supera `MAX_CHARS` -- Frasi spezzate tra paragrafi consecutivi vengono ri-fuse automaticamente -- Paragrafi brevi (< `MIN_CHARS`) vengono accorpati al successivo (stesso contesto) -- Sezioni in `SKIP_HEADINGS` saltate completamente; contenuto pre-heading saltato se `SKIP_PRE_HEADING=True` -- Tabelle, liste e code block sono blocchi atomici +Output per stem: `chunks//chunks.json`, `chunks//meta.json`, `chunks//report.json` -Output: `chunks//chunks.json`, `chunks//meta.json` +**Schema chunk** (`chunks.json`): -### Vettorizzazione — `ingestion/ingest.py` +| Campo | Descrizione | +|-------|-------------| +| `chunk_id` | Identificatore univoco | +| `content_for_embedding` | Testo con prefisso heading, usato per generare il vettore | +| `content_original` | Testo originale senza prefisso, memorizzato in ChromaDB | +| `header_path` | Lista di dict `{level, text}` — gerarchia heading del chunk | +| `content_type` | Tipo blocco dominante (`paragraph`, `table`, `code`, ecc.) | +| `flags` | Dict: `has_code`, `has_table`, `has_math`, `is_overflow` | +| `chunk_index` | Posizione ordinale nel documento | +| `start_line` / `end_line` | Righe sorgente nel Markdown | +| `chars` | Lunghezza in caratteri di `content_original` | -Legge `chunks//chunks.json`, genera embedding via Ollama (`EMBED_MODEL`), indicizza in ChromaDB persistente (`chroma_db/`). Supporta collection multi-documento (`--collection --stems doc1 doc2`). +### Vettorizzazione — `ingestion/` -### RAG — file radice +| File | Responsabilità | +|------|---------------| +| `ingest.py` | Legge `chunks.json`, genera embedding via Ollama, indicizza in ChromaDB | +| `config.py` | `EMBED_MODEL` (default: `bge-m3`), `EMBED_MAX_CHARS`, `OLLAMA_URL` | + +ChromaDB persistente in `chroma_db/`. Supporta collection multi-documento (`--collection`). + +### RAG — `rag/` | 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` | +| `config.py` | `TOP_K`, `TEMPERATURE`, `NO_THINK`, `OLLAMA_MODEL`, `OLLAMA_URL`, `SYSTEM_PROMPT` | -### Output per stem +### GUI — `gui/` -``` -chunks//chunks.json -chunks//meta.json -chroma_db// ← collection ChromaDB -``` +| File | Responsabilità | +|------|---------------| +| `main.py` | Entry point PySide6, argparse `--collection` | +| `chat_window.py` | `QMainWindow`: top bar (combo collection + toggle tema), `QWebEngineView`, input bar | +| `worker.py` | `QThread`: esegue retrieve + build_prompt + call_ollama in background | +| `chat.html` | Template HTML con marked.js + KaTeX (CDN); funzioni JS: `addMessage`, `addThinking`, `removeThinking`, `setTheme` | ---- +Temi light/dark gestiti via CSS custom properties in `chat.html` e stylesheet Qt in `chat_window.py`. -## Skills custom +### Utility — `ollama/` -- `/prepare-md ` — corregge il Markdown MinerU: sillabazione, artefatti, header malformati, gerarchia incoerente. Opera su una copia, non sull'originale. +| File | Responsabilità | +|------|---------------| +| `check_env.py` | Verifica che Ollama sia attivo e i modelli configurati siano disponibili | +| `test_ollama.py` | Test embedding e generazione end-to-end |