From 48502fc6c7a3ab7c3de0c0f674a97641573416f1 Mon Sep 17 00:00:00 2001 From: Berack96 Date: Thu, 25 Sep 2025 22:24:24 +0200 Subject: [PATCH] !! Broken for now !! Refactor environment variables and remove unused API key checks; introduce Models enum for supported models. --- .env.example | 8 ---- src/app.py | 29 ++---------- src/app/agents/market_agent.py | 2 - src/app/agents/predictor_agent.py | 3 -- src/app/models.py | 78 +++++++++++++++++++++++++++++++ src/app/tool.py | 20 +++++--- 6 files changed, 96 insertions(+), 44 deletions(-) create mode 100644 src/app/models.py diff --git a/.env.example b/.env.example index e2dce26..c31f1be 100644 --- a/.env.example +++ b/.env.example @@ -1,14 +1,6 @@ -# Questo file contiene le variabili d'ambiente per l'API di alcuni modelli di AI -# QUndo si cerca di far partire il progetto, bisogna copiare questo file in un file chiamato .env -# e mettere le proprie API keys (ottenibili registrandosi ai servizi) # Alcune API sono a pagamento, altre hanno un piano gratuito con limiti di utilizzo -# Non so se saranno tutte necessarie, ma visto i limiti di utilizzo è meglio averle tutte -# in modo da poterle usare a rotazione o metterne una per agenti diversi # Vedi https://docs.agno.com/examples/models per vedere tutti i modelli supportati GOOGLE_API_KEY= -ANTHROPIC_API_KEY= -DEEPSEEK_API_KEY= -OPENAI_API_KEY= # Dipende dal sistema operativo # windows: C:\Users\\.ollama # mac: /Users//.ollama diff --git a/src/app.py b/src/app.py index e3dab64..a20536b 100644 --- a/src/app.py +++ b/src/app.py @@ -1,29 +1,8 @@ -import os import gradio as gr from dotenv import load_dotenv from app.tool import ToolAgent - -def available_keys(): - """ - Controlla quali provider di modelli LLM hanno le loro API keys disponibili - come variabili d'ambiente e ritorna una lista di provider disponibili. - Se nessuna API key è disponibile, ritorna solo 'mock' come opzione. - """ - availables = [] - if os.getenv("GOOGLE_API_KEY"): - availables.append("google") - if os.getenv("OPENAI_API_KEY"): - availables.append("openai") - if os.getenv("ANTHROPIC_API_KEY"): - availables.append("anthropic") - if os.getenv("DEEPSEEK_API_KEY"): - availables.append("deepseek") - if os.getenv("OLLAMA_MODELS_PATH"): - availables.append("ollama") - - return ['mock', *availables] - +from app.models import Models ######################################## # MAIN APP & GRADIO INTERFACE @@ -37,16 +16,16 @@ if __name__ == "__main__": load_dotenv() ###################################### + list_models = Models.available() tool_agent = ToolAgent() with gr.Blocks() as demo: gr.Markdown("# 🤖 Agente di Analisi e Consulenza Crypto") with gr.Row(): - list_choices = available_keys() provider = gr.Dropdown( - choices=list_choices, - value=list_choices[0], + choices=list_models, + value=list_models[0], label="Modello da usare" ) style = gr.Dropdown( diff --git a/src/app/agents/market_agent.py b/src/app/agents/market_agent.py index e92a05c..c0347b5 100644 --- a/src/app/agents/market_agent.py +++ b/src/app/agents/market_agent.py @@ -2,11 +2,9 @@ from typing import Dict, List, Optional, Any import requests import logging import os -from dotenv import load_dotenv from app.signers.market_signers.coinbase_signer import CoinbaseCDPSigner from app.signers.market_signers.cryptocompare_signer import CryptoCompareSigner -load_dotenv() logger = logging.getLogger(__name__) diff --git a/src/app/agents/predictor_agent.py b/src/app/agents/predictor_agent.py index a27573c..55d3160 100644 --- a/src/app/agents/predictor_agent.py +++ b/src/app/agents/predictor_agent.py @@ -4,12 +4,9 @@ from typing import Any import anthropic import requests -from dotenv import load_dotenv from google import genai from openai import OpenAI -load_dotenv() - class PredictorAgent: def __init__(self): # Ollama via HTTP locale diff --git a/src/app/models.py b/src/app/models.py new file mode 100644 index 0000000..10cda8c --- /dev/null +++ b/src/app/models.py @@ -0,0 +1,78 @@ +import os +from enum import Enum +from agno.agent import Agent +from agno.models.base import BaseModel +from agno.models.google import Gemini +from agno.models.ollama import Ollama + +class Models(Enum): + """ + Enum per i modelli supportati. + Aggiungere nuovi modelli qui se necessario. + Per quanto riguarda Ollama, i modelli dovranno essere scaricati e installati + localmente seguendo le istruzioni di https://ollama.com/docs/guide/install-models + """ + GEMINI = "gemini-2.0-flash" # API online + GEMINI_PRO = "gemini-2.0-pro" # API online, più costoso ma migliore + OLLAMA = "llama3.1" # little and fast (7b) but not so good + OLLAMA_GPT = "gpt-oss" # a bit big (13b) but very good (almost like gemini API) + OLLAMA_QWEN = "qwen3:8b" # good + MOCK = "mock" + + def available() -> list[str]: + """ + Controlla quali provider di modelli LLM hanno le loro API keys disponibili + come variabili d'ambiente e ritorna una lista di provider disponibili. + Se nessuna API key è disponibile, ritorna solo 'mock' come opzione. + L'ordine di preferenza è: + 1. Gemini (Google) + 2. Ollama (locale) + """ + availables = [] + if os.getenv("GOOGLE_API_KEY"): + availables.append(Models.GEMINI) + availables.append(Models.GEMINI_PRO) + if os.getenv("OLLAMA_MODELS_PATH"): + availables.append(Models.OLLAMA) + availables.append(Models.OLLAMA_GPT) + availables.append(Models.OLLAMA_QWEN) + + return [Models.MOCK, *availables] + + def __str__(self) -> str: + # Per semplificare la visualizzazione del modello come stringa. + return self.name + + def get_model(self, instructions:str) -> BaseModel: + """ + Restituisce un'istanza del modello specificato. + instructions: istruzioni da passare al modello (system prompt). + Ritorna un'istanza di BaseModel o una sua sottoclasse. + Raise ValueError se il modello non è supportato. + """ + name = self.value + if self in {Models.GEMINI}: + return Gemini(name, instructions=instructions) + elif self in {Models.OLLAMA, Models.OLLAMA_GPT, Models.OLLAMA_QWEN}: + return Ollama(name, instructions=instructions) + elif self in {Models.MOCK}: + from agno.models.base import Model + return Model(name, instructions=instructions) + + raise ValueError(f"Modello non supportato: {self}") + + def get_agent(self, instructions: str) -> Agent: + """ + Costruisce un agente con il modello e le istruzioni specificate. + instructions: istruzioni da passare al modello (system prompt). + Ritorna un'istanza di Agent. + """ + return Agent( + model=self.get_model(instructions=instructions), + instructions=instructions, + # TODO Eventuali altri parametri da mettere all'agente + # anche se si possono comunque assegnare dopo la creazione + # Esempio: + # retries=2, + # retry_delay=1, + ) diff --git a/src/app/tool.py b/src/app/tool.py index bf47d9d..e2b448a 100644 --- a/src/app/tool.py +++ b/src/app/tool.py @@ -1,17 +1,25 @@ -from .agents.market_agent import MarketAgent -from .agents.news_agent import NewsAgent -from .agents.social_agent import SocialAgent -from .agents.predictor_agent import PredictorAgent +from app.agents.market_agent import MarketAgent +from app.agents.news_agent import NewsAgent +from app.agents.social_agent import SocialAgent +from app.agents.predictor_agent import PredictorAgent +from app.models import Models class ToolAgent: - def __init__(self): + def __init__(self, available_models: list[Models]): self.market_agent = MarketAgent() self.news_agent = NewsAgent() self.social_agent = SocialAgent() self.predictor_agent = PredictorAgent() - def interact(self, query, provider="mock", style="conservative"): + def interact(self, query: str, provider: str, style: str): + """ + Funzione principale che coordina gli agenti per rispondere alla richiesta dell'utente. + """ + # TODO Utilizzare AGNO per gestire i modelli... è molto più semplice e permette di cambiare modello facilmente + # TODO https://docs.agno.com/introduction + # Inoltre permette di creare dei team e workflow di agenti più facilmente + # Step 1: raccolta analisi market_data = self.market_agent.analyze(query) news_sentiment = self.news_agent.analyze(query)