Merge remote-tracking branch 'origin/ollama' into predictor
# Conflicts: # .env.example # pyproject.toml # src/app.py # src/example.py # uv.lock
This commit is contained in:
@@ -14,4 +14,9 @@ ANTHROPIC_API_KEY=
|
|||||||
DEEPSEEK_API_KEY=
|
DEEPSEEK_API_KEY=
|
||||||
OPENAI_API_KEY=
|
OPENAI_API_KEY=
|
||||||
|
|
||||||
|
# Dipende dal sistema operativo
|
||||||
|
# windows: C:\Users\<user>\.ollama
|
||||||
|
# mac: /Users/<user>/.ollama
|
||||||
|
# linux: /home/<user>/.ollama
|
||||||
|
# wsl: /usr/share/ollama/.ollama
|
||||||
OLLAMA_MODELS_PATH=
|
OLLAMA_MODELS_PATH=
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
# Vogliamo usare una versione di linux leggera con già uv installato
|
# Vogliamo usare una versione di linux leggera con già uv installato
|
||||||
# Infatti scegliamo l'immagine ufficiale di uv che ha già tutto configurato
|
# 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
|
FROM ghcr.io/astral-sh/uv:python3.12-alpine
|
||||||
|
|
||||||
# Dopo aver definito la workdir mi trovo già in essa
|
# Dopo aver definito la workdir mi trovo già in essa
|
||||||
|
|||||||
157
README.md
157
README.md
@@ -1,69 +1,88 @@
|
|||||||
# **Progetto di Esame: Da definire**
|
# **Progetto di Esame: Da definire**
|
||||||
Questa è la repository per l'esame di Applicazioni Intelligenti che consiste in:
|
Questa è la repository per l'esame di Applicazioni Intelligenti che consiste in:
|
||||||
- Progetto per 2/3 del voto.
|
- Progetto per 2/3 del voto.
|
||||||
- Orale per 1/3 dei punti composto da:
|
- Orale per 1/3 dei punti composto da:
|
||||||
- Presentazione (come se lo facessimo ad un cliente) di gruppo
|
- Presentazione (come se lo facessimo ad un cliente) di gruppo
|
||||||
- Orale singolo con domande del corso (teoria e strumenti visti)
|
- 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.
|
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
|
# Installazione
|
||||||
Per l'installazione si può utilizzare un approccio tramite **uv** (manuale) oppure utilizzare un ambiente **Docker** già pronto (automatico).
|
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.
|
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.
|
||||||
Le API Keys puoi ottenerle tramite i seguenti servizi:
|
|
||||||
- **Google AI**: [Google AI Studio](https://makersuite.google.com/app/apikey) (gratuito con limiti)
|
### API Keys
|
||||||
- **Anthropic**: [Anthropic Console](https://console.anthropic.com/)
|
Le API Keys puoi ottenerle tramite i seguenti servizi:
|
||||||
- **DeepSeek**: [DeepSeek Platform](https://platform.deepseek.com/)
|
- **Google AI**: [Google AI Studio](https://makersuite.google.com/app/apikey) (gratuito con limiti)
|
||||||
- **OpenAI**: [OpenAI Platform](https://platform.openai.com/api-keys)
|
- **Anthropic**: [Anthropic Console](https://console.anthropic.com/)
|
||||||
|
- **DeepSeek**: [DeepSeek Platform](https://platform.deepseek.com/)
|
||||||
Nota che alcune API sono gratuite con limiti di utilizzo, altre sono a pagamento. Google offre attualmente l'accesso gratuito con limiti ragionevoli.
|
- **OpenAI**: [OpenAI Platform](https://platform.openai.com/api-keys)
|
||||||
|
|
||||||
### Variabili d'Ambiente
|
Nota che alcune API sono gratuite con limiti di utilizzo, altre sono a pagamento. Google offre attualmente l'accesso gratuito con limiti ragionevoli.
|
||||||
|
|
||||||
**1. Copia il file di esempio**:
|
### Ollama (Modelli Locali)
|
||||||
```sh
|
Per utilizzare modelli AI localmente, è necessario installare Ollama:
|
||||||
cp .env.example .env
|
|
||||||
```
|
**1. Installazione Ollama**:
|
||||||
|
- **Linux**: `curl -fsSL https://ollama.com/install.sh | sh`
|
||||||
**2. Modifica il file .env** creato con le tue API keys, inserendole nella variabile opportuna dopo l'uguale e ***senza*** spazi:
|
- **macOS/Windows**: Scarica l'installer da [https://ollama.com/download/windows](https://ollama.com/download/windows)
|
||||||
```dotenv
|
|
||||||
GOOGLE_API_KEY=
|
**2. GPU Support (Raccomandato)**:
|
||||||
ANTHROPIC_API_KEY=
|
Per utilizzare la GPU con Ollama, assicurati di avere NVIDIA CUDA Toolkit installato:
|
||||||
DEEPSEEK_API_KEY=
|
- **Download**: [NVIDIA CUDA Downloads](https://developer.nvidia.com/cuda-downloads?target_os=Windows&target_arch=x86_64&target_version=11&target_type=exe_local)
|
||||||
OPENAI_API_KEY=
|
- **Documentazione WSL**: [CUDA WSL User Guide](https://docs.nvidia.com/cuda/wsl-user-guide/index.html)
|
||||||
```
|
|
||||||
|
**3. Installazione Modelli**:
|
||||||
### Opzione 1 UV
|
Esempio per installare un modello locale: `ollama pull gpt-oss`
|
||||||
**1. Installazione uv**: Per prima cosa installa uv se non è già presente sul sistema:
|
|
||||||
```sh
|
### Variabili d'Ambiente
|
||||||
# Windows (PowerShell)
|
|
||||||
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
**1. Copia il file di esempio**:
|
||||||
|
```sh
|
||||||
# macOS/Linux
|
cp .env.example .env
|
||||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
```
|
||||||
```
|
|
||||||
|
**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:
|
||||||
**2. Ambiente e dipendenze**: uv installerà python e creerà automaticamente l'ambiente virtuale con le dipendenze corrette:
|
```dotenv
|
||||||
```sh
|
GOOGLE_API_KEY=
|
||||||
uv sync --frozen --no-cache
|
ANTHROPIC_API_KEY=
|
||||||
```
|
DEEPSEEK_API_KEY=
|
||||||
|
OPENAI_API_KEY=
|
||||||
**3. Run**: Successivamente si può far partire il progetto tramite il comando:
|
# Path dove Ollama salva i modelli (es. /home/username/.ollama su Linux)
|
||||||
```sh
|
OLLAMA_MODELS_PATH=
|
||||||
uv run python src/app.py
|
```
|
||||||
```
|
|
||||||
|
### Opzione 1 UV
|
||||||
### Opzione 2 Docker
|
**1. Installazione uv**: Per prima cosa installa uv se non è già presente sul sistema:
|
||||||
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:
|
```sh
|
||||||
|
# Windows (PowerShell)
|
||||||
**IMPORTANTE**: Assicurati di aver configurato il file `.env` come descritto sopra prima di avviare Docker.
|
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
||||||
|
|
||||||
```sh
|
# macOS/Linux
|
||||||
docker compose up --build -d
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Il file `.env` verrà automaticamente caricato nel container grazie alla configurazione in `docker-compose.yaml`.
|
**2. Ambiente e dipendenze**: uv installerà python e creerà automaticamente l'ambiente virtuale con le dipendenze corrette:
|
||||||
|
```sh
|
||||||
# Applicazione
|
uv sync --frozen --no-cache
|
||||||
L'applicazione è attualmente in fase di sviluppo. Maggiori dettagli saranno aggiunti durante l'implementazione.
|
```
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|||||||
@@ -8,8 +8,30 @@ services:
|
|||||||
- .:/app
|
- .:/app
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
# Aggiunte chiave:
|
||||||
environment:
|
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}
|
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
|
||||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||||
- DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
|
- DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
|
||||||
- OPENAI_API_KEY=${OPENAI_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
|
||||||
@@ -27,7 +27,9 @@ dependencies = [
|
|||||||
# altamente consigliata dato che ha anche tools integrati per fare scraping, calcoli e molto altro
|
# 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
|
# oltre a questa è necessario installare anche le librerie specifiche per i modelli che si vogliono usare
|
||||||
"agno",
|
"agno",
|
||||||
|
# ✅ Modelli supportati e installati (aggiungere qui sotto quelli che si vogliono usare)
|
||||||
"google-genai",
|
"google-genai",
|
||||||
|
"ollama",
|
||||||
"openai",
|
"openai",
|
||||||
"anthropic",
|
"anthropic",
|
||||||
"google",
|
"google",
|
||||||
|
|||||||
161
src/ollama_demo.py
Normal file
161
src/ollama_demo.py
Normal file
@@ -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)
|
||||||
Reference in New Issue
Block a user