docs: riscrive README con abstract esteso, guida parametri e licenza MIT
Espande l'abstract con motivazione personale e contesto d'uso (manuali tecnici di ingegneria). Aggiunge guida pratica alla scelta dei parametri per chunking, embedding e RAG con tabelle di modelli Ollama e link al catalogo. Aggiunge file LICENSE MIT e relativo link nel README. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Davide Grilli
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
# RAG from scratch
|
# RAG from scratch
|
||||||
|
|
||||||
Esercizio pratico per costruire una pipeline RAG (Retrieval-Augmented Generation) completa a partire da documenti PDF, interamente in locale senza dipendenze cloud. L'obiettivo è avere un assistente che risponde a domande sui tuoi documenti usando solo il contenuto di quei documenti, senza allucinazioni.
|
Sono appassionato di intelligenza artificiale e questo progetto nasce dalla curiosita' di capire come funziona davvero un sistema RAG costruendolo da zero, senza usare framework che nascondono i dettagli. Nessuna API esterna, nessun dato che lascia la macchina: tutto gira in locale.
|
||||||
|
|
||||||
|
Il risultato e' una pipeline completa che trasforma PDF in un assistente interrogabile in linguaggio naturale. L'ho sviluppato e testato principalmente su manuali tecnici di ingegneria — documenti densi, con formule, tabelle e gerarchie di sezioni profonde — ma funziona su qualsiasi PDF ben strutturato: paper accademici, documentazione tecnica, archivi personali.
|
||||||
|
|
||||||
|
L'idea e' semplice: MinerU estrae il testo dal PDF producendo un Markdown strutturato, il chunker lo divide in blocchi semantici coerenti, gli embedding li trasformano in vettori numerici, ChromaDB li indicizza, e Ollama genera le risposte partendo dai chunk piu' rilevanti per la domanda. Ogni componente e' sostituibile e configurabile.
|
||||||
|
|
||||||
**Stack:** Python · MinerU · ChromaDB · Ollama
|
**Stack:** Python · MinerU · ChromaDB · Ollama
|
||||||
**Chunking:** AST-based, deterministico, senza LLM
|
**Chunking:** AST-based, deterministico, senza LLM
|
||||||
**Embedding + Generazione:** Ollama (locale, nessun dato inviato a server esterni)
|
**Embedding + Generazione:** Ollama (locale, nessun dato inviato a server esterni)
|
||||||
|
**Licenza:** [MIT](LICENSE)
|
||||||
|
|
||||||
```
|
```
|
||||||
PDF
|
PDF
|
||||||
@@ -22,8 +27,8 @@ PDF
|
|||||||
|---------|--------|------|
|
|---------|--------|------|
|
||||||
| Python | 3.10 – 3.13 | testato su 3.11 |
|
| Python | 3.10 – 3.13 | testato su 3.11 |
|
||||||
| RAM | 8 GB | 16 GB+ per modelli LLM grandi |
|
| RAM | 8 GB | 16 GB+ per modelli LLM grandi |
|
||||||
| Disco | 5 GB liberi | + spazio modelli Ollama |
|
| Disco | 5 GB liberi | + spazio modelli Ollama (~4 GB per bge-m3 + qwen3.5:4b) |
|
||||||
| GPU | non necessaria | accelera MinerU e modelli LLM |
|
| GPU | non necessaria | accelera MinerU e i modelli LLM in modo significativo |
|
||||||
| OS | Linux, macOS, Windows (WSL2) | |
|
| OS | Linux, macOS, Windows (WSL2) | |
|
||||||
|
|
||||||
**Dipendenze Python** — installate via `requirements.txt`:
|
**Dipendenze Python** — installate via `requirements.txt`:
|
||||||
@@ -35,18 +40,15 @@ PDF
|
|||||||
**Dipendenze esterne:**
|
**Dipendenze esterne:**
|
||||||
|
|
||||||
- [Ollama](https://ollama.com) — server locale per embedding e generazione LLM
|
- [Ollama](https://ollama.com) — server locale per embedding e generazione LLM
|
||||||
- [MinerU](https://github.com/opendatalab/MinerU) — conversione PDF → Markdown (opzionale se hai già i file `.md`)
|
- [MinerU](https://github.com/opendatalab/MinerU) — conversione PDF → Markdown (opzionale se hai gia' i file `.md`)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Setup ambiente
|
## Setup ambiente
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Crea e attiva il virtual environment
|
|
||||||
python -m venv .venv
|
python -m venv .venv
|
||||||
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||||
|
|
||||||
# Installa le dipendenze
|
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -54,11 +56,11 @@ pip install -r requirements.txt
|
|||||||
|
|
||||||
## Passo 1 — Converti i PDF con MinerU
|
## Passo 1 — Converti i PDF con MinerU
|
||||||
|
|
||||||
MinerU estrae il testo dai PDF producendo un Markdown strutturato con tabelle, formule ed immagini. Ci sono due modalità:
|
MinerU estrae il testo dai PDF producendo Markdown strutturato con tabelle, formule e immagini. Gestisce bene anche PDF scansionati tramite OCR.
|
||||||
|
|
||||||
### Opzione A — Google Colab (consigliata, usa la GPU gratuita di Google)
|
### Opzione A — Google Colab (consigliata, usa la GPU gratuita di Google)
|
||||||
|
|
||||||
Il notebook `mineru.ipynb` esegue MinerU su Colab sfruttando la GPU messa a disposizione gratuitamente. Utile se non hai una GPU locale o se i PDF sono pesanti.
|
Il notebook `mineru.ipynb` esegue MinerU su Colab sfruttando la GPU gratuita. E' la scelta piu' comoda se non hai una GPU locale o se i PDF sono pesanti.
|
||||||
|
|
||||||
1. Apri `mineru.ipynb` su Google Colab
|
1. Apri `mineru.ipynb` su Google Colab
|
||||||
2. Carica i PDF nella cartella `input/` indicata nelle celle
|
2. Carica i PDF nella cartella `input/` indicata nelle celle
|
||||||
@@ -69,17 +71,17 @@ Il notebook `mineru.ipynb` esegue MinerU su Colab sfruttando la GPU messa a disp
|
|||||||
sources/
|
sources/
|
||||||
└── <stem>_output/
|
└── <stem>_output/
|
||||||
└── auto/
|
└── auto/
|
||||||
├── <stem>.md ← questo è l'input della pipeline
|
├── <stem>.md ← input della pipeline
|
||||||
└── images/
|
└── images/
|
||||||
```
|
```
|
||||||
|
|
||||||
### Opzione B — Installazione locale
|
### Opzione B — Installazione locale
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install "mineru[all]" # installa MinerU (scarica ~15 GB di modelli al primo avvio)
|
pip install "mineru[all]" # scarica ~15 GB di modelli al primo avvio
|
||||||
|
|
||||||
mineru -p documento.pdf -o sources/<stem>_output/ -b pipeline
|
mineru -p documento.pdf -o sources/<stem>_output/ -b pipeline
|
||||||
# Con GPU:
|
# Con GPU CUDA:
|
||||||
mineru -p documento.pdf -o sources/<stem>_output/ -b hybrid-auto-engine
|
mineru -p documento.pdf -o sources/<stem>_output/ -b hybrid-auto-engine
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -87,35 +89,35 @@ mineru -p documento.pdf -o sources/<stem>_output/ -b hybrid-auto-engine
|
|||||||
|
|
||||||
## Passo 2 — Chunking
|
## Passo 2 — Chunking
|
||||||
|
|
||||||
Il chunker analizza il Markdown con un parser AST, divide il testo in blocchi semantici e li impacchetta in chunk ottimizzati per il retrieval.
|
Il chunker analizza il Markdown con un parser AST, identifica blocchi semantici (paragrafi, tabelle, formule, codice) e li impacchetta in chunk ottimizzati per il retrieval.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Singolo documento
|
python chunks/chunker.py --stem <stem> # singolo documento
|
||||||
python chunks/chunker.py --stem <stem>
|
python chunks/chunker.py # tutti i documenti in sources/
|
||||||
|
python chunks/chunker.py --stem <stem> --force # rigenera anche se esiste gia'
|
||||||
# Tutti i documenti presenti in sources/ in una volta
|
|
||||||
python chunks/chunker.py
|
|
||||||
|
|
||||||
# Rigenera anche se chunks.json esiste già
|
|
||||||
python chunks/chunker.py --stem <stem> --force
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Output in `chunks/<stem>/`: `chunks.json`, `meta.json`, `report.json`.
|
Output in `chunks/<stem>/`: `chunks.json`, `meta.json`, `report.json`.
|
||||||
|
|
||||||
### Configurazione — `chunks/config.py`
|
### Configurazione — `chunks/config.py`
|
||||||
|
|
||||||
Modifica i parametri nella classe `ChunkerConfig` se necessario:
|
|
||||||
|
|
||||||
| Parametro | Default | Descrizione |
|
| Parametro | Default | Descrizione |
|
||||||
|-----------|---------|-------------|
|
|-----------|---------|-------------|
|
||||||
| `max_chars` | `1200` | Dimensione massima di un chunk (caratteri) |
|
| `max_chars` | `1200` | Dimensione massima di un chunk (caratteri) |
|
||||||
| `min_chars` | `80` | Soglia minima; chunk piu' piccoli vengono accorpati |
|
| `min_chars` | `80` | Soglia minima; chunk piu' piccoli vengono accorpati al successivo |
|
||||||
| `target_chars` | `800` | Dimensione target per il packing greedy |
|
| `target_chars` | `800` | Dimensione target per il packing dei blocchi |
|
||||||
| `context_depth` | `3` | Livelli di heading inclusi come prefisso nel testo per l'embedding |
|
| `context_depth` | `3` | Livelli di heading inclusi come prefisso nel testo per l'embedding |
|
||||||
| `skip_headings` | vedi file | Sezioni saltate completamente (indice, sommario, ecc.) |
|
| `skip_headings` | vedi file | Sezioni saltate completamente (indice, sommario, ecc.) |
|
||||||
| `skip_pre_heading` | `True` | Salta il contenuto prima del primo heading (frontespizi, ecc.) |
|
| `skip_pre_heading` | `True` | Salta il contenuto prima del primo heading (copertine, ecc.) |
|
||||||
| `atomic_types` | `table, code, list, math, html` | Tipi di blocco che non vengono mai spezzati |
|
| `atomic_types` | `table, code, list, math, html` | Tipi di blocco che non vengono mai spezzati |
|
||||||
|
|
||||||
|
**Come scegliere i parametri di chunking:**
|
||||||
|
|
||||||
|
- **`max_chars` e `target_chars`**: dipendono dalla lunghezza media dei paragrafi del tuo documento e dalla finestra di contesto del modello di embedding. Con `bge-m3` (8192 token) i valori di default vanno bene per la maggior parte dei manuali tecnici. Se i tuoi paragrafi sono molto corti (documentazione stile reference), abbassa `target_chars` a 400–500 per evitare chunk troppo eterogenei. Se sono molto lunghi (testi narrativi), puoi salire fino a 1500–2000.
|
||||||
|
- **`context_depth`**: determina quanti livelli di heading vengono preposti al testo nell'embedding (es. "Capitolo 3 > Sezione 3.2 > contenuto"). Valore 2–3 e' ottimale per documenti con gerarchia profonda come manuali tecnici. Con documenti piatti (un solo livello di heading) metti 1.
|
||||||
|
- **`skip_headings`**: aggiungi i titoli delle sezioni che non vuoi indicizzare (indici, bibliografie, ringraziamenti). Il confronto e' case-insensitive e per prefisso, quindi `"appendice"` cattura anche "Appendice A", "Appendice B", ecc.
|
||||||
|
- **`min_chars`**: lascia il default a meno che il documento non abbia molti paragrafi di una riga (caption, label) che vuoi escludere — in quel caso alzalo a 150–200.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Passo 3 — Vettorizzazione (ingest)
|
## Passo 3 — Vettorizzazione (ingest)
|
||||||
@@ -123,30 +125,39 @@ Modifica i parametri nella classe `ChunkerConfig` se necessario:
|
|||||||
Genera gli embedding dei chunk e li indicizza in ChromaDB. Richiede Ollama attivo.
|
Genera gli embedding dei chunk e li indicizza in ChromaDB. Richiede Ollama attivo.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Avvia Ollama (se non e' gia' in esecuzione)
|
ollama serve # avvia Ollama se non e' gia' in esecuzione
|
||||||
ollama serve
|
ollama pull bge-m3 # modello embedding (una volta sola)
|
||||||
|
|
||||||
# Installa il modello di embedding (una volta sola)
|
python ingestion/ingest.py --stem <stem> # singolo documento
|
||||||
ollama pull bge-m3
|
python ingestion/ingest.py --collection <nome> --stems doc1 doc2 doc3 # multi-documento
|
||||||
|
python ingestion/ingest.py --stem <stem> --force # rigenera dopo modifiche
|
||||||
# Indicizza un singolo documento
|
|
||||||
python ingestion/ingest.py --stem <stem>
|
|
||||||
|
|
||||||
# Indicizza piu' documenti in una collection condivisa (RAG cross-documento)
|
|
||||||
python ingestion/ingest.py --collection <nome> --stems doc1 doc2 doc3
|
|
||||||
|
|
||||||
# Rigenera dopo aver aggiornato i chunk o cambiato modello embedding
|
|
||||||
python ingestion/ingest.py --stem <stem> --force
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Con `--collection` tutti i documenti vengono indicizzati insieme e sono interrogabili con un'unica query — utile quando i temi si sovrappongono o vuoi fare confronti tra documenti.
|
||||||
|
|
||||||
### Configurazione — `ingestion/config.py`
|
### Configurazione — `ingestion/config.py`
|
||||||
|
|
||||||
| Parametro | Default | Descrizione |
|
| Parametro | Default | Descrizione |
|
||||||
|-----------|---------|-------------|
|
|-----------|---------|-------------|
|
||||||
| `EMBED_MODEL` | `bge-m3` | Modello Ollama per gli embedding. Se lo cambi, riesegui l'ingest con `--force` |
|
| `EMBED_MODEL` | `bge-m3` | Modello Ollama per gli embedding |
|
||||||
| `EMBED_MAX_CHARS` | `6000` | Caratteri massimi inviati al modello per ogni chunk |
|
| `EMBED_MAX_CHARS` | `6000` | Caratteri massimi inviati al modello per chunk |
|
||||||
| `OLLAMA_URL` | `http://localhost:11434` | URL del server Ollama |
|
| `OLLAMA_URL` | `http://localhost:11434` | URL del server Ollama |
|
||||||
|
|
||||||
|
**Come scegliere il modello di embedding:**
|
||||||
|
|
||||||
|
Il catalogo completo e' disponibile su [ollama.com/search?c=embedding](https://ollama.com/search?c=embedding). Alcuni punti di riferimento:
|
||||||
|
|
||||||
|
| Modello | Dim. | Note |
|
||||||
|
|---------|------|------|
|
||||||
|
| `bge-m3` | ~1 GB | Consigliato: multilingua, robusto su testi tecnici, finestra 8192 token |
|
||||||
|
| `nomic-embed-text` | ~274 MB | Leggero, buono per prove rapide; solo inglese |
|
||||||
|
| `mxbai-embed-large` | ~670 MB | Qualita' alta su benchmark inglesi |
|
||||||
|
| `bge-large` | ~670 MB | Variante grande di bge, multilingua |
|
||||||
|
| `snowflake-arctic-embed` | ~670 MB | Ottimizzato per retrieval su testi lunghi |
|
||||||
|
| `all-minilm` | ~46 MB | Molto leggero, qualita' ridotta |
|
||||||
|
|
||||||
|
**Attenzione:** se cambi `EMBED_MODEL` devi rieseguire l'ingest con `--force` su tutti i documenti — i vettori generati da modelli diversi non sono compatibili.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Passo 4 — Interrogazione
|
## Passo 4 — Interrogazione
|
||||||
@@ -154,28 +165,25 @@ python ingestion/ingest.py --stem <stem> --force
|
|||||||
### Da terminale
|
### Da terminale
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Installa il modello LLM (una volta sola)
|
ollama pull qwen3.5:4b # modello LLM (una volta sola)
|
||||||
ollama pull qwen3.5:4b
|
|
||||||
|
|
||||||
# RAG interattivo — retrieval + risposta generata dal modello
|
python rag/rag.py --collection <nome> # RAG interattivo
|
||||||
python rag/rag.py --collection <nome>
|
|
||||||
python rag/rag.py --stem <stem> # scorciatoia per collection a documento singolo
|
python rag/rag.py --stem <stem> # scorciatoia per collection a documento singolo
|
||||||
|
|
||||||
# Retrieval puro senza LLM (utile per debug)
|
python rag/retrieve.py --collection <nome> # retrieval puro senza LLM (debug)
|
||||||
python rag/retrieve.py --collection <nome>
|
|
||||||
python rag/retrieve.py --stem <stem> --top-k 10
|
python rag/retrieve.py --stem <stem> --top-k 10
|
||||||
```
|
```
|
||||||
|
|
||||||
Nel loop interattivo: digita la domanda e premi Invio. Aggiungi `-v` alla fine per vedere i chunk recuperati con i relativi score di similarita'.
|
Nel loop: digita la domanda e premi Invio. Aggiungi `-v` alla fine per vedere i chunk recuperati con i relativi score di similarita'.
|
||||||
|
|
||||||
### Con la GUI desktop
|
### Con la GUI desktop
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python gui/main.py
|
python gui/main.py
|
||||||
python gui/main.py --collection <nome> # apre direttamente la collection
|
python gui/main.py --collection <nome>
|
||||||
```
|
```
|
||||||
|
|
||||||
La GUI mostra le risposte con Markdown e formule matematiche renderizzate. Il tema chiaro/scuro e' selezionabile dal pulsante in alto a destra.
|
La GUI mostra le risposte con Markdown e formule matematiche renderizzate (KaTeX). Il tema chiaro/scuro e' selezionabile dal pulsante in alto a destra.
|
||||||
|
|
||||||
### Configurazione — `rag/config.py`
|
### Configurazione — `rag/config.py`
|
||||||
|
|
||||||
@@ -188,33 +196,23 @@ La GUI mostra le risposte con Markdown e formule matematiche renderizzate. Il te
|
|||||||
| `OLLAMA_URL` | `http://localhost:11434` | URL del server Ollama |
|
| `OLLAMA_URL` | `http://localhost:11434` | URL del server Ollama |
|
||||||
| `SYSTEM_PROMPT` | vedi file | Istruzioni di sistema inviate al modello prima del contesto |
|
| `SYSTEM_PROMPT` | vedi file | Istruzioni di sistema inviate al modello prima del contesto |
|
||||||
|
|
||||||
---
|
**Come scegliere i parametri RAG:**
|
||||||
|
|
||||||
## Struttura del repository
|
- **`OLLAMA_MODEL`**: il catalogo completo e' su [ollama.com/library](https://ollama.com/library). Scegli in base alla RAM disponibile:
|
||||||
|
|
||||||
```
|
| Modello | RAM indicativa | Note |
|
||||||
rag/
|
|---------|---------------|------|
|
||||||
├── sources/ ← output MinerU (una cartella per documento)
|
| `qwen3:1.7b` | ~1.5 GB | Minimo; buono solo per domande semplici |
|
||||||
├── chunks/
|
| `phi4-mini` | ~2.5 GB | Compatto ma sorprendentemente capace |
|
||||||
│ ├── chunker.py ← orchestrazione pipeline AST
|
| `qwen3.5:4b` | ~2.5 GB | Default consigliato: buon equilibrio qualita'/velocita' |
|
||||||
│ ├── config.py ← parametri di chunking
|
| `gemma3:4b` | ~3 GB | Alternativa Google, buono in italiano |
|
||||||
│ ├── parser.py ← markdown-it-py + dollarmath
|
| `llama3.2:3b` | ~2 GB | Veloce, buono per inglese |
|
||||||
│ ├── segmenter.py ← token stream -> Block[]
|
| `mistral:7b` | ~4.5 GB | Solido su testi tecnici in italiano e inglese |
|
||||||
│ ├── packer.py ← Block[] -> Chunk[]
|
| `qwen3:8b` | ~5 GB | Qualita' alta, richiede 16+ GB RAM totali |
|
||||||
│ └── validator.py ← invarianti e metriche
|
| `llama3.1:8b` | ~5 GB | Meta, ottimo ragionamento, inglese principalmente |
|
||||||
├── ingestion/
|
| `deepseek-r1:8b` | ~5 GB | Reasoning avanzato; piu' lento ma preciso su domande complesse |
|
||||||
│ ├── ingest.py ← embedding -> ChromaDB
|
|
||||||
│ └── config.py ← parametri embedding
|
- **`TOP_K`**: quanti chunk vengono recuperati e inclusi nel contesto. Valori bassi (3–4) danno risposte piu' precise ma rischiano di perdere informazioni distribuite su piu' sezioni. Valori alti (8–10) danno piu' contesto ma aumentano il tempo di generazione e possono introdurre rumore. 6 e' un buon default per manuali tecnici.
|
||||||
├── rag/
|
- **`TEMPERATURE`**: per domande fattuali su documenti tecnici tienila bassa (0.1–0.2). Valori piu' alti (0.5–0.7) sono utili solo se vuoi risposte piu' discorsive o comparative.
|
||||||
│ ├── rag.py ← loop RAG interattivo
|
- **`NO_THINK`**: `True` rende le risposte piu' rapide disabilitando il ragionamento interno dei modelli Qwen3. Mettilo a `False` per domande complesse che richiedono ragionamento multi-step.
|
||||||
│ ├── retrieve.py ← retrieval puro (debug)
|
- **`SYSTEM_PROMPT`**: personalizzalo in base al tipo di documento. Il default e' calibrato per documenti tecnici in italiano. Se usi documenti in inglese o vuoi risposte piu' strutturate, modificalo direttamente nel file.
|
||||||
│ └── config.py ← parametri RAG e system prompt
|
|
||||||
├── gui/
|
|
||||||
│ ├── main.py ← entry point GUI
|
|
||||||
│ ├── chat_window.py ← finestra principale PySide6
|
|
||||||
│ ├── worker.py ← thread per il pipeline RAG
|
|
||||||
│ └── chat.html ← template HTML (Markdown + KaTeX)
|
|
||||||
├── chroma_db/ ← database vettoriale (non tracciato da git)
|
|
||||||
├── mineru.ipynb ← notebook Colab per conversione PDF
|
|
||||||
└── requirements.txt
|
|
||||||
```
|
|
||||||
|
|||||||
Reference in New Issue
Block a user