Creazione branch tool, refactor degli import e soppressione dei warning

This commit is contained in:
trojanhorse47
2025-09-29 12:22:02 +02:00
parent 4615ebe63e
commit c82f10b32c
11 changed files with 72 additions and 46 deletions

View File

@@ -1,5 +1,5 @@
from agno.tools import Toolkit
from app.markets import MarketAPIs
from src.app.markets import MarketAPIs
# TODO (?) in futuro fare in modo che la LLM faccia da sé per il mercato
# Non so se può essere utile, per ora lo lascio qui

View File

@@ -1,5 +1,5 @@
from enum import Enum
from app.markets.base import ProductInfo
from src.app.markets.base import ProductInfo
from pydantic import BaseModel, Field
class PredictorStyle(Enum):
@@ -23,7 +23,7 @@ class PredictorOutput(BaseModel):
PREDICTOR_INSTRUCTIONS = """
You are an **Allocation Algorithm (Crypto-Algo)** specialized in analyzing market data and sentiment to generate an investment strategy and a target portfolio.
Your sole objective is to process the input data and generate the strictly structured output as required by the response format. **You MUST NOT provide introductions, preambles, explanations, conclusions, or any additional comments that are not strictly required.**
Your sole objective is to process the user_input data and generate the strictly structured output as required by the response format. **You MUST NOT provide introductions, preambles, explanations, conclusions, or any additional comments that are not strictly required.**
## Processing Instructions (Absolute Rule)

View File

@@ -1,6 +1,6 @@
from app.markets.base import BaseWrapper
from app.markets.coinbase import CoinBaseWrapper
from app.markets.cryptocompare import CryptoCompareWrapper
from src.app.markets.base import BaseWrapper
from src.app.markets.coinbase import CoinBaseWrapper
from src.app.markets.cryptocompare import CryptoCompareWrapper
from agno.utils.log import log_warning
@@ -30,8 +30,8 @@ class MarketAPIs(BaseWrapper):
for wrapper in wrapper_builders:
try:
result.append(wrapper(currency=currency))
except Exception as _:
log_warning(f"{wrapper} cannot be initialized, maybe missing API key?")
except Exception as e:
log_warning(f"{wrapper} cannot be initialized: {e}")
assert result, "No market API keys set in environment variables."
return result
@@ -39,7 +39,9 @@ class MarketAPIs(BaseWrapper):
def __init__(self, currency: str = "USD"):
"""
Inizializza la classe con la valuta di riferimento e la priorità dei provider.
:param currency: Valuta di riferimento (default "USD")
Args:
currency: Valuta di riferimento (default "USD")
"""
self.currency = currency
self.wrappers = MarketAPIs.get_list_available_market_apis(currency=currency)

View File

@@ -1,6 +1,6 @@
import os
from coinbase.rest import RESTClient
from app.markets.base import ProductInfo, BaseWrapper, Price
from src.app.markets.base import ProductInfo, BaseWrapper, Price
class CoinBaseWrapper(BaseWrapper):
"""

View File

@@ -1,6 +1,6 @@
import os
import requests
from app.markets.base import ProductInfo, BaseWrapper, Price
from src.app.markets.base import ProductInfo, BaseWrapper, Price
BASE_URL = "https://min-api.cryptocompare.com"
@@ -8,7 +8,7 @@ class CryptoCompareWrapper(BaseWrapper):
"""
Wrapper per le API pubbliche di CryptoCompare.
La documentazione delle API è disponibile qui: https://developers.coindesk.com/documentation/legacy/Price/SingleSymbolPriceEndpoint
!!ATTENZIONE!! sembra essere una API legacy e potrebbe essere deprecata in futuro.
!ATTENZIONE! Sembra essere una API legacy e potrebbe essere deprecata in futuro.
"""
def __init__(self, api_key:str = None, currency:str='USD'):
if api_key is None:

View File

@@ -41,6 +41,7 @@ class AppModels(Enum):
availables.append(AppModels.OLLAMA_QWEN)
return availables
@staticmethod
def availables_online() -> list['AppModels']:
"""
Controlla quali provider di modelli LLM online hanno le loro API keys disponibili
@@ -49,9 +50,7 @@ class AppModels(Enum):
if not os.getenv("GOOGLE_API_KEY"):
log_warning("No GOOGLE_API_KEY set in environment variables.")
return []
availables = []
availables.append(AppModels.GEMINI)
availables.append(AppModels.GEMINI_PRO)
availables = [AppModels.GEMINI, AppModels.GEMINI_PRO]
return availables
@staticmethod
@@ -75,9 +74,13 @@ class AppModels(Enum):
def extract_json_str_from_response(response: str) -> str:
"""
Estrae il JSON dalla risposta del modello.
response: risposta del modello (stringa).
Ritorna la parte JSON della risposta come stringa.
Se non viene trovato nessun JSON, ritorna una stringa vuota.
Args:
response: risposta del modello (stringa).
Returns:
La parte JSON della risposta come stringa.
Se non viene trovato nessun JSON, ritorna una stringa vuota.
ATTENZIONE: questa funzione è molto semplice e potrebbe non funzionare
in tutti i casi. Si assume che il JSON sia ben formato e che inizi con
'{' e finisca con '}'. Quindi anche solo un json array farà fallire questa funzione.
@@ -98,9 +101,15 @@ class AppModels(Enum):
def get_model(self, instructions:str) -> Model:
"""
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.
Args:
instructions: istruzioni da passare al modello (system prompt).
Returns:
Un'istanza di BaseModel o una sua sottoclasse.
Raise:
ValueError se il modello non è supportato.
"""
name = self.value
if self in {AppModels.GEMINI, AppModels.GEMINI_PRO}:
@@ -113,8 +122,13 @@ class AppModels(Enum):
def get_agent(self, instructions: str, name: str = "", output: BaseModel | None = None) -> Agent:
"""
Costruisce un agente con il modello e le istruzioni specificate.
instructions: istruzioni da passare al modello (system prompt).
Ritorna un'istanza di Agent.
Args:
instructions: istruzioni da passare al modello (system prompt)
name: nome dell'agente (opzionale)
output: schema di output opzionale (Pydantic BaseModel)
Returns:
Un'istanza di Agent.
"""
return Agent(
model=self.get_model(instructions),

View File

@@ -1,8 +1,8 @@
from app.agents.news_agent import NewsAgent
from app.agents.social_agent import SocialAgent
from app.agents.predictor import PredictorStyle, PredictorInput, PredictorOutput, PREDICTOR_INSTRUCTIONS
from app.markets import MarketAPIs
from app.models import AppModels
from src.app.agents.news_agent import NewsAgent
from src.app.agents.social_agent import SocialAgent
from src.app.agents.predictor import PredictorStyle, PredictorInput, PredictorOutput, PREDICTOR_INSTRUCTIONS
from src.app.markets import MarketAPIs
from src.app.models import AppModels
from agno.utils.log import log_info
class ToolAgent:
@@ -14,6 +14,10 @@ class ToolAgent:
"""
Inizializza l'agente con i modelli disponibili, gli stili e l'API di mercato.
"""
self.social_agent = None
self.news_agent = None
self.predictor = None
self.chosen_model = None
self.available_models = AppModels.availables()
self.all_styles = list(PredictorStyle)
self.style = self.all_styles[0] # Default to the first style
@@ -24,7 +28,9 @@ class ToolAgent:
def choose_provider(self, index: int):
"""
Sceglie il modello LLM da utilizzare in base all'indice fornito.
index: indice del modello nella lista available_models.
Args:
index: indice del modello nella lista available_models.
"""
# TODO Utilizzare AGNO per gestire i modelli... è molto più semplice e permette di cambiare modello facilmente
# TODO https://docs.agno.com/introduction
@@ -37,15 +43,18 @@ class ToolAgent:
def choose_style(self, index: int):
"""
Sceglie lo stile di previsione da utilizzare in base all'indice fornito.
index: indice dello stile nella lista all_styles.
Args:
index: indice dello stile nella lista all_styles.
"""
self.style = self.all_styles[index]
def interact(self, query: str) -> str:
"""
Funzione principale che coordina gli agenti per rispondere alla richiesta dell'utente.
query: richiesta dell'utente (es. "Qual è la previsione per Bitcoin?")
style_index: indice dello stile di previsione nella lista all_styles.
Args:
query: richiesta dell'utente (es. "Qual è la previsione per Bitcoin?")
"""
log_info(f"[model={self.chosen_model.name}] [style={self.style.name}] [query=\"{query.replace('"', "'")}\"]")

View File

@@ -1,5 +1,5 @@
import statistics
from typing import Dict, List, Any
from typing import Dict, Any
class MarketAggregator:
"""
@@ -65,6 +65,7 @@ class MarketAggregator:
return float(v[:-1]) * 1_000
try:
return float(v)
except Exception:
except Exception as e:
print(f"Errore nel parsing del volume: {e}")
return 0.0
return 0.0