From a5f8b8d119e5fc2013c574430488b4febd0869f3 Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Mon, 13 Apr 2026 23:57:20 +0200 Subject: [PATCH] step-7: add check_env.py, README, update requirements - check_env.py: verifica ollama, embedding model, LLM model, chromadb - Rileva qualsiasi modello embedding/LLM installato (non lista fissa) - step-7/README.md: guida installazione/disinstallazione Ollama, modelli, chromadb - requirements.txt: aggiunge chromadb per step-8 --- README.md | 30 ++++---- requirements.txt | 3 + step-7/README.md | 168 +++++++++++++++++++++++++++++++++++++++++++ step-7/check_env.py | 169 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 357 insertions(+), 13 deletions(-) create mode 100644 step-7/README.md create mode 100644 step-7/check_env.py diff --git a/README.md b/README.md index 5b7a90c..06dca1a 100644 --- a/README.md +++ b/README.md @@ -469,30 +469,34 @@ Distribuzione lunghezze: **Tipo:** manuale (una volta sola) **Input:** nessuno -**Output:** ambiente locale funzionante +**Output:** ambiente locale funzionante +**Script:** `step-7/check_env.py` ```bash # Installa Ollama curl -fsSL https://ollama.com/install.sh | sh -# Scarica i modelli -ollama pull qwen3:8b # LLM — ~5 GB -ollama pull nomic-embed-text # Embedding — ~270 MB +# Scarica un modello di embedding e un LLM +ollama pull nomic-embed-text # Embedding — ~274 MB (consigliato) +ollama pull qwen3.5:4b # LLM — ~3.4 GB (consigliato per 8 GB RAM) -# Installa dipendenze Python +# Installa dipendenze Python nel venv +source .venv/bin/activate pip install -r requirements.txt -# Verifica -ollama list -# deve mostrare entrambi i modelli +# Verifica tutto +python step-7/check_env.py ``` -**Modelli usati:** +**Modelli consigliati per 8 GB RAM:** -| Modello | Ruolo | Dimensione | RAM occupata | -|---|---|---|---| -| `nomic-embed-text` | Converte testo in vettori | 270 MB | ~500 MB | -| `qwen3:8b` | Genera le risposte | 5 GB | ~6-7 GB | +| Modello | Ruolo | Dimensione | +|---|---|---| +| `nomic-embed-text` | Embedding | ~274 MB | +| `qwen3.5:4b` | LLM | ~3.4 GB | + +Per guide dettagliate su modelli alternativi, installazione e disinstallazione +di Ollama e ChromaDB, vedi [`step-7/README.md`](step-7/README.md). Questo step si esegue una volta sola. Da questo momento Ollama è sempre disponibile sul sistema. diff --git a/requirements.txt b/requirements.txt index a5686af..a30e6e4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,6 @@ pdfplumber==0.11.9 # Step 2 — Conversione PDF → Markdown pymupdf4llm + +# Step 8 — Vettorizzazione +chromadb diff --git a/step-7/README.md b/step-7/README.md new file mode 100644 index 0000000..2ebd3fd --- /dev/null +++ b/step-7/README.md @@ -0,0 +1,168 @@ +# Step 7 — Verifica ambiente + +Prima di procedere con la vettorizzazione (step 8) devi avere installato: + +- **Ollama** — server locale per LLM e embedding +- un **modello di embedding** (es. `nomic-embed-text`, `bge-m3`) +- un **modello LLM** (es. `qwen3.5:4b`, `qwen3:4b`) +- **chromadb** — libreria Python per il vector store + +--- + +## 1. Installa Ollama + +```bash +curl -fsSL https://ollama.com/install.sh | sh +``` + +Verifica che il servizio sia attivo: + +```bash +ollama list +``` + +### Disinstalla Ollama + +```bash +# Ferma e rimuovi il servizio systemd +sudo systemctl stop ollama +sudo systemctl disable ollama +sudo rm /etc/systemd/system/ollama.service +sudo systemctl daemon-reload + +# Rimuovi il binario +sudo rm /usr/local/bin/ollama + +# Rimuovi modelli e dati (opzionale — occupa spazio su disco) +# I modelli sono salvati sotto l'utente di sistema "ollama", non nella tua home +sudo rm -rf /usr/share/ollama + +# Rimuovi l'utente e il gruppo di sistema creati dall'installer (opzionale) +sudo userdel ollama +sudo groupdel ollama +``` + +--- + +## 2. Scarica i modelli + +### Modello di embedding + +Per testo in italiano usa **`bge-m3`** — addestrato su 100+ lingue, gestisce l'italiano meglio dei modelli English-first: + +```bash +ollama pull bge-m3 +``` + +Alternativa leggera (principalmente inglese, ~274 MB): + +```bash +ollama pull nomic-embed-text +``` + +| Modello | Dim | Dimensione | Lingue | +|---|---|---|---| +| `bge-m3` | 1024 | ~1.2 GB | 100+ lingue incl. IT | +| `nomic-embed-text` | 768 | ~274 MB | principalmente EN | +| `mxbai-embed-large` | 1024 | ~670 MB | principalmente EN | +| `all-minilm` | 384 | ~46 MB | principalmente EN | + +### Modello LLM + +Scegli in base alla RAM disponibile: + +```bash +ollama pull qwen3.5:4b # consigliato per 8 GB RAM +``` + +| Modello | RAM consigliata | Note | +|---|---|---| +| `qwen3:8b` | ≥ 10 GB | ottima qualità, troppo stretto su 8 GB | +| `qwen3.5:4b` | ≥ 5 GB | buon bilanciamento, **consigliato per 8 GB** | +| `qwen3:4b` | ≥ 5 GB | alternativa stabile | +| `phi4-mini` | ≥ 4 GB | ottimo per instruction following | +| `qwen3:1.7b` | ≥ 3 GB | leggero, qualità base | + +Se usi un modello diverso da `qwen3.5:4b`, aggiorna la costante `LLM_MODEL` in `step-9/rag.py`. + +### Disinstalla un modello + +```bash +ollama rm qwen3.5:4b +ollama rm nomic-embed-text +``` + +Per vedere tutti i modelli installati: + +```bash +ollama list +``` + +--- + +## 3. Installa chromadb nel venv + +```bash +source .venv/bin/activate +pip install chromadb +``` + +Aggiorna anche `requirements.txt`: + +```bash +pip freeze | grep chromadb >> requirements.txt +``` + +### Disinstalla chromadb + +```bash +source .venv/bin/activate + +# Rimuovi il pacchetto e le dipendenze non più necessarie +pip uninstall chromadb -y +pip autoremove 2>/dev/null || pip uninstall $(pip-autoremove chromadb -l 2>/dev/null) -y 2>/dev/null + +# Rimuovi i dati del vector store (opzionale — occupa spazio su disco) +rm -rf chroma_db/ +``` + +> `pip autoremove` richiede il pacchetto `pip-autoremove` (`pip install pip-autoremove`). +> In alternativa, elimina e ricrea il venv per una pulizia completa: +> ```bash +> deactivate +> rm -rf .venv +> python -m venv .venv +> source .venv/bin/activate +> pip install -r requirements.txt +> ``` + +--- + +## 4. Verifica tutto + +```bash +source .venv/bin/activate +python step-7/check_env.py +``` + +Output atteso se tutto è a posto: + +``` +✅ ollama trovato nel PATH +✅ ollama risponde correttamente +✅ modello embedding trovato: nomic-embed-text:latest +✅ modello LLM trovato: qwen3.5:4b + +✅ chromadb importabile + +✅ Ambiente pronto — procedi con la vettorizzazione: + python step-8/ingest.py --stem +``` + +--- + +## Prossimo step + +```bash +python step-8/ingest.py --stem nietzsche +``` diff --git a/step-7/check_env.py b/step-7/check_env.py new file mode 100644 index 0000000..cdda95b --- /dev/null +++ b/step-7/check_env.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +""" +Step 7 — Verifica ambiente + +Controlla che tutti i prerequisiti per la vettorizzazione siano soddisfatti: + 1. ollama è nel PATH e risponde + 2. Almeno un modello di embedding è scaricato + 3. Almeno un modello LLM è scaricato + 4. chromadb è importabile + +Output: report a schermo con ✅ / ❌ per ogni componente. +Nessun file scritto. Exit 0 se tutto OK, 1 altrimenti. + +Uso: + python step-7/check_env.py +""" + +import shutil +import subprocess +import sys + + +# Modelli riconosciuti come embedding (basta che uno sia presente) +# Tutto il resto viene considerato LLM +EMBED_MODELS = ["bge-m3", "nomic-embed-text", "mxbai-embed-large", "all-minilm"] + +REQUIRED_LIBS = ["chromadb"] + + +# ─── Checks ─────────────────────────────────────────────────────────────────── + +def check_ollama_in_path() -> bool: + """Verifica che ollama sia nel PATH.""" + found = shutil.which("ollama") is not None + if found: + print("✅ ollama trovato nel PATH") + else: + print("❌ ollama non trovato nel PATH") + print(" → Installa con: curl -fsSL https://ollama.com/install.sh | sh") + return found + + +def check_ollama_running() -> list[str] | None: + """ + Esegue 'ollama list' e ritorna la lista dei modelli disponibili. + Ritorna None se ollama non risponde. + """ + try: + result = subprocess.run( + ["ollama", "list"], + capture_output=True, text=True, timeout=10 + ) + if result.returncode != 0: + print("❌ ollama non risponde (errore all'avvio)") + print(" → Avvia il servizio con: ollama serve") + return None + lines = result.stdout.strip().splitlines() + models = [] + for line in lines[1:]: # salta l'header + parts = line.split() + if parts: + models.append(parts[0]) + print("✅ ollama risponde correttamente") + return models + except FileNotFoundError: + print("❌ ollama non trovato (FileNotFoundError)") + return None + except subprocess.TimeoutExpired: + print("❌ ollama non risponde (timeout)") + print(" → Avvia il servizio con: ollama serve") + return None + + +def _match(model_name: str, available: list[str]) -> str | None: + """ + Ritorna il nome completo del modello trovato in 'available' che corrisponde + a 'model_name' (confronto per prefisso), oppure None. + """ + for m in available: + if m == model_name or m.startswith(model_name + ":") or m.startswith(model_name + "-"): + return m + return None + + +def check_embed_model(available: list[str]) -> bool: + """Verifica che almeno un modello di embedding sia presente.""" + for candidate in EMBED_MODELS: + found = _match(candidate, available) + if found: + print(f"✅ modello embedding trovato: {found}") + return True + print("❌ nessun modello di embedding trovato") + print(f" → Consigliato per italiano: ollama pull bge-m3") + print(f" → Alternativa leggera: ollama pull nomic-embed-text") + return False + + +def check_llm_model(available: list[str]) -> bool: + """Verifica che almeno un modello non-embedding sia presente.""" + llm_candidates = [ + m for m in available + if not any(m == e or m.startswith(e + ":") or m.startswith(e + "-") + for e in EMBED_MODELS) + ] + if llm_candidates: + print(f"✅ modello LLM trovato: {llm_candidates[0]}") + return True + print("❌ nessun modello LLM trovato") + print(f" → Consigliato per 8 GB RAM: ollama pull qwen3.5:4b") + return False + + +def check_library(lib: str) -> bool: + """Verifica che una libreria Python sia importabile.""" + try: + __import__(lib) + print(f"✅ {lib} importabile") + return True + except ImportError: + print(f"❌ {lib} non importabile") + print(f" → Installa con: pip install {lib}") + return False + + +# ─── Entry point ────────────────────────────────────────────────────────────── + +def main() -> int: + print("─── Step 7 — Verifica ambiente ───────────────────────────────────────\n") + + results: list[bool] = [] + + # 1. ollama nel PATH + in_path = check_ollama_in_path() + results.append(in_path) + + # 2. ollama risponde + modelli + if in_path: + available = check_ollama_running() + if available is None: + results.extend([False, False, False]) + else: + results.append(True) + results.append(check_embed_model(available)) + results.append(check_llm_model(available)) + else: + results.extend([False, False, False]) + print("⚠️ modelli non verificabili (ollama non trovato)") + + # 3. Librerie Python + print() + for lib in REQUIRED_LIBS: + results.append(check_library(lib)) + + # ── Riepilogo ───────────────────────────────────────────────────────────── + print() + print("──────────────────────────────────────────────────────────────────────") + all_ok = all(results) + if all_ok: + print("✅ Ambiente pronto — procedi con la vettorizzazione:") + print(" python step-8/ingest.py --stem ") + else: + n_fail = sum(1 for r in results if not r) + print(f"⚠️ {n_fail} problema/i rilevato/i — risolvi prima di procedere con step-8.") + + return 0 if all_ok else 1 + + +if __name__ == "__main__": + sys.exit(main())