diff --git a/.env.example b/.env.example index 035a249..be19490 100644 --- a/.env.example +++ b/.env.example @@ -14,4 +14,9 @@ ANTHROPIC_API_KEY= DEEPSEEK_API_KEY= OPENAI_API_KEY= +# Dipende dal sistema operativo +# windows: C:\Users\\.ollama +# mac: /Users//.ollama +# linux: /home//.ollama +# wsl: /usr/share/ollama/.ollama OLLAMA_MODELS_PATH= \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index ebb38d8..7de13cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,5 @@ # Vogliamo usare una versione di linux leggera con già uv installato # Infatti scegliamo l'immagine ufficiale di uv che ha già tutto configurato -# Nel caso in cui si volesse usare un'altra immagine di base che ha magari CUDA -# bisognerebbe installare uv manualmente come descritto nel README -#FROM pytorch/pytorch:2.6.0-cuda12.6-cudnn9-devel # Lo lascio qui nel caso FROM ghcr.io/astral-sh/uv:python3.12-alpine # Dopo aver definito la workdir mi trovo già in essa diff --git a/README.md b/README.md index 04d7eab..0fbc43c 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,88 @@ -# **Progetto di Esame: Da definire** -Questa è la repository per l'esame di Applicazioni Intelligenti che consiste in: -- Progetto per 2/3 del voto. -- Orale per 1/3 dei punti composto da: - - Presentazione (come se lo facessimo ad un cliente) di gruppo - - Orale singolo con domande del corso (teoria e strumenti visti) - -L'obiettivo di questo progetto è creare un sistema basato su **LLM Agents** e deve dimostrare la capacità di ragionare, adattarsi a eventi esterni e comunicare in modo intelligente. - -# Installazione -Per l'installazione si può utilizzare un approccio tramite **uv** (manuale) oppure utilizzare un ambiente **Docker** già pronto (automatico). - -Prima di avviare l'applicazione è però necessario configurare correttamente le API keys, altrimenti il progetto, anche se installato correttamente, non riuscirà a partire. -Le API Keys puoi ottenerle tramite i seguenti servizi: -- **Google AI**: [Google AI Studio](https://makersuite.google.com/app/apikey) (gratuito con limiti) -- **Anthropic**: [Anthropic Console](https://console.anthropic.com/) -- **DeepSeek**: [DeepSeek Platform](https://platform.deepseek.com/) -- **OpenAI**: [OpenAI Platform](https://platform.openai.com/api-keys) - -Nota che alcune API sono gratuite con limiti di utilizzo, altre sono a pagamento. Google offre attualmente l'accesso gratuito con limiti ragionevoli. - -### Variabili d'Ambiente - -**1. Copia il file di esempio**: -```sh -cp .env.example .env -``` - -**2. Modifica il file .env** creato con le tue API keys, inserendole nella variabile opportuna dopo l'uguale e ***senza*** spazi: -```dotenv -GOOGLE_API_KEY= -ANTHROPIC_API_KEY= -DEEPSEEK_API_KEY= -OPENAI_API_KEY= -``` - -### Opzione 1 UV -**1. Installazione uv**: Per prima cosa installa uv se non è già presente sul sistema: -```sh -# Windows (PowerShell) -powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" - -# macOS/Linux -curl -LsSf https://astral.sh/uv/install.sh | sh -``` - -**2. Ambiente e dipendenze**: uv installerà python e creerà automaticamente l'ambiente virtuale con le dipendenze corrette: -```sh -uv sync --frozen --no-cache -``` - -**3. Run**: Successivamente si può far partire il progetto tramite il comando: -```sh -uv run python src/app.py -``` - -### Opzione 2 Docker -Alternativamente, se si ha installato [Docker](https://www.docker.com), si può utilizzare il [Dockerfile](Dockerfile) e il [docker-compose.yaml](docker-compose.yaml) per creare il container con tutti i file necessari e già in esecuzione: - -**IMPORTANTE**: Assicurati di aver configurato il file `.env` come descritto sopra prima di avviare Docker. - -```sh -docker compose up --build -d -``` - -Il file `.env` verrà automaticamente caricato nel container grazie alla configurazione in `docker-compose.yaml`. - -# Applicazione -L'applicazione è attualmente in fase di sviluppo. Maggiori dettagli saranno aggiunti durante l'implementazione. +# **Progetto di Esame: Da definire** +Questa è la repository per l'esame di Applicazioni Intelligenti che consiste in: +- Progetto per 2/3 del voto. +- Orale per 1/3 dei punti composto da: + - Presentazione (come se lo facessimo ad un cliente) di gruppo + - Orale singolo con domande del corso (teoria e strumenti visti) + +L'obiettivo di questo progetto è creare un sistema basato su **LLM Agents** e deve dimostrare la capacità di ragionare, adattarsi a eventi esterni e comunicare in modo intelligente. + +# Installazione +Per l'installazione si può utilizzare un approccio tramite **uv** (manuale) oppure utilizzare un ambiente **Docker** già pronto (automatico). + +Prima di avviare l'applicazione è però necessario configurare correttamente le API keys e installare Ollama per l'utilizzo dei modelli locali, altrimenti il progetto, anche se installato correttamente, non riuscirà a partire. + +### API Keys +Le API Keys puoi ottenerle tramite i seguenti servizi: +- **Google AI**: [Google AI Studio](https://makersuite.google.com/app/apikey) (gratuito con limiti) +- **Anthropic**: [Anthropic Console](https://console.anthropic.com/) +- **DeepSeek**: [DeepSeek Platform](https://platform.deepseek.com/) +- **OpenAI**: [OpenAI Platform](https://platform.openai.com/api-keys) + +Nota che alcune API sono gratuite con limiti di utilizzo, altre sono a pagamento. Google offre attualmente l'accesso gratuito con limiti ragionevoli. + +### Ollama (Modelli Locali) +Per utilizzare modelli AI localmente, è necessario installare Ollama: + +**1. Installazione Ollama**: +- **Linux**: `curl -fsSL https://ollama.com/install.sh | sh` +- **macOS/Windows**: Scarica l'installer da [https://ollama.com/download/windows](https://ollama.com/download/windows) + +**2. GPU Support (Raccomandato)**: +Per utilizzare la GPU con Ollama, assicurati di avere NVIDIA CUDA Toolkit installato: +- **Download**: [NVIDIA CUDA Downloads](https://developer.nvidia.com/cuda-downloads?target_os=Windows&target_arch=x86_64&target_version=11&target_type=exe_local) +- **Documentazione WSL**: [CUDA WSL User Guide](https://docs.nvidia.com/cuda/wsl-user-guide/index.html) + +**3. Installazione Modelli**: +Esempio per installare un modello locale: `ollama pull gpt-oss` + +### Variabili d'Ambiente + +**1. Copia il file di esempio**: +```sh +cp .env.example .env +``` + +**2. Modifica il file .env** creato con le tue API keys e il path dei modelli Ollama, inserendoli nelle variabili opportune dopo l'uguale e ***senza*** spazi: +```dotenv +GOOGLE_API_KEY= +ANTHROPIC_API_KEY= +DEEPSEEK_API_KEY= +OPENAI_API_KEY= +# Path dove Ollama salva i modelli (es. /home/username/.ollama su Linux) +OLLAMA_MODELS_PATH= +``` + +### Opzione 1 UV +**1. Installazione uv**: Per prima cosa installa uv se non è già presente sul sistema: +```sh +# Windows (PowerShell) +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" + +# macOS/Linux +curl -LsSf https://astral.sh/uv/install.sh | sh +``` + +**2. Ambiente e dipendenze**: uv installerà python e creerà automaticamente l'ambiente virtuale con le dipendenze corrette: +```sh +uv sync --frozen --no-cache +``` + +**3. Run**: Successivamente si può far partire il progetto tramite il comando: +```sh +uv run python src/app.py +``` + +### Opzione 2 Docker +Alternativamente, se si ha installato [Docker](https://www.docker.com), si può utilizzare il [Dockerfile](Dockerfile) e il [docker-compose.yaml](docker-compose.yaml) per creare il container con tutti i file necessari e già in esecuzione: + +**IMPORTANTE**: Assicurati di aver configurato il file `.env` come descritto sopra prima di avviare Docker. + +```sh +docker compose up --build -d +``` + +Il file `.env` verrà automaticamente caricato nel container grazie alla configurazione in `docker-compose.yaml`. + +# Applicazione +L'applicazione è attualmente in fase di sviluppo. Maggiori dettagli saranno aggiunti durante l'implementazione. diff --git a/docker-compose.yaml b/docker-compose.yaml index ef127ff..fffd043 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -8,8 +8,30 @@ services: - .:/app env_file: - .env + # Aggiunte chiave: environment: + # Questa variabile dice alla tua app dove trovare il servizio Ollama + - OLLAMA_HOST=http://ollama:11434 + # Le tue API keys esistenti - GOOGLE_API_KEY=${GOOGLE_API_KEY} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY} - OPENAI_API_KEY=${OPENAI_API_KEY} + # Assicura che ollama parta prima della tua app + depends_on: + - ollama + + # Nuovo servizio per Ollama + ollama: + image: ollama/ollama + container_name: ollama + # Aggiungi il runtime NVIDIA per GPU support + runtime: nvidia + environment: + - NVIDIA_VISIBLE_DEVICES=all + ports: + - "11434:11434" + volumes: + # Mappa la cartella dei modelli del tuo PC a quella interna del container + # ${OLLAMA_MODELS_PATH} sarà letto dal file .env + - ${OLLAMA_MODELS_PATH}:/root/.ollama \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 6c1c7aa..eaf63ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,9 @@ dependencies = [ # altamente consigliata dato che ha anche tools integrati per fare scraping, calcoli e molto altro # oltre a questa è necessario installare anche le librerie specifiche per i modelli che si vogliono usare "agno", + # ✅ Modelli supportati e installati (aggiungere qui sotto quelli che si vogliono usare) "google-genai", + "ollama", "openai", "anthropic", "google", diff --git a/src/ollama_demo.py b/src/ollama_demo.py new file mode 100644 index 0000000..1e52f5f --- /dev/null +++ b/src/ollama_demo.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +""" +Demo di Ollama (Python) – mostra: + 1. Elenco dei modelli disponibili + 2. Generazione di testo semplice + 3. Chat con streaming + 4. Calcolo di embeddings + 5. Esempio (opzionale) di function calling / tools + +Uso: + python ollama_demo.py + +Requisiti: + pip install ollama + Avviare il server Ollama (es. 'ollama serve' o l'app desktop) e avere i modelli già pullati. +""" + +import ollama + +# Configurazione modelli +MODEL = 'gpt-oss:latest' # modello principale per testo/chat +EMBEDDING_MODEL = 'mxbai-embed-large:latest' # modello dedicato embeddings (richiede supporto embeddings) + +# 1. Elenco dei modelli ------------------------------------------------------- + +def list_models(): + """Stampa i modelli caricati nel server Ollama.""" + print("\n[1] Modelli disponibili:") + try: + response = ollama.list() + models = getattr(response, 'models', []) or (response.get('models', []) if isinstance(response, dict) else []) + if not models: + print(" (Nessun modello trovato)") + return + for m in models: + name = getattr(m, 'model', None) or (m.get('model') if isinstance(m, dict) else 'sconosciuto') + details = getattr(m, 'details', None) + fmt = getattr(details, 'format', None) if details else 'unknown' + print(f" • {name} – {fmt}") + except Exception as e: + print(f" ❌ Errore durante il listing: {e}") + + +# 2. Generazione di testo ------------------------------------------------------ + +def generate_text(model: str, prompt: str, max_tokens: int = 200) -> str: + """Genera testo dal modello indicato.""" + print(f"\n[2] Generazione testo con '{model}'") + response = ollama.chat( + model=model, + messages=[{"role": "user", "content": prompt}] + ) + text = response['message']['content'] + print("Risposta:\n" + text + "\n") + return text + + +# 3. Chat con streaming -------------------------------------------------------- + +def chat_streaming(model: str, messages: list) -> str: + """Esegue una chat mostrando progressivamente la risposta.""" + print(f"\n[3] Chat (streaming) con '{model}'") + stream = ollama.chat(model=model, messages=messages, stream=True) + full = "" + for chunk in stream: + if 'message' in chunk and 'content' in chunk['message']: + part = chunk['message']['content'] + full += part + print(part, end="", flush=True) + print("\n") + return full + + +# 4. Embeddings ---------------------------------------------------------------- + +def get_embedding(model: str, text: str): + """Calcola embedding del testo col modello specificato (se supportato).""" + print(f"\n[4] Embedding con '{model}'") + try: + r = ollama.embeddings(model=model, prompt=text) + except ollama.ResponseError as e: + print(f" ⚠️ Il modello '{model}' non supporta embeddings o errore API: {e}") + return None + emb = r['embedding'] + print(f"Dimensione embedding: {len(emb)} (prime 5: {emb[:5]})") + return emb + + +# 5. Function calling / Tools (opzionale) -------------------------------------- + +def try_tools(model: str): + """Esempio di function calling; se non supportato mostra messaggio informativo.""" + print(f"\n[5] Function calling / tools con '{model}'") + tools = [ + { + "type": "function", + "function": { + "name": "get_current_weather", + "description": "Ottiene condizioni meteo sintetiche di una località (demo)", + "parameters": { + "type": "object", + "properties": { + "location": {"type": "string", "description": "Città"}, + "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]} + }, + "required": ["location"] + } + } + } + ] + try: + response = ollama.chat( + model=model, + messages=[{"role": "user", "content": "Che tempo fa a Milano?"}], + tools=tools + ) + msg = response['message'] + if 'tool_calls' in msg and msg['tool_calls']: + tool_call = msg['tool_calls'][0] + print("Richiesta funzione:", tool_call['function']['name']) + print("Argomenti:", tool_call['function']['arguments']) + else: + print("Risposta modello senza tool call:", msg.get('content', '')) + except ollama.ResponseError as e: + if 'does not support tools' in str(e).lower(): + print("Il modello non supporta i tools.") + else: + print("Errore API:", e) + + +# Main ------------------------------------------------------------------------- +if __name__ == '__main__': + # 1. Elenco modelli + list_models() + + # 2. Prompt semplice + generate_text( + model=MODEL, + prompt="Scrivi una poesia breve su un tramonto al mare. Usa circa 40 parole." + ) + + # 3. Chat con streaming + chat_streaming( + model=MODEL, + messages=[ + {"role": "system", "content": "Sei un assistente conciso e utile."}, + {"role": "user", "content": "Suggerisci 3 consigli per un cappuccino cremoso a casa."} + ] + ) + + # 4. Embedding (usa modello dedicato se diverso) + if EMBEDDING_MODEL: + get_embedding( + model=EMBEDDING_MODEL, + text="L'intelligenza artificiale accelera l'innovazione in molti settori." + ) + else: + print("\n[4] Salto embedding: nessun modello embedding configurato.") + + # 5. Function calling (opzionale) + try_tools(MODEL) \ No newline at end of file