Refactor market system and improve app configuration

- Refactor market system from singleton function to class-based architecture with MarketAPIs
- Add automatic API key detection for Coinbase and CryptoCompare wrappers
- Improve error handling and logging with agno.utils.log throughout the application
- Split Models class into separate methods for online and local model availability
- Add proper JSON response extraction with thinking pattern support
- Enhance ToolAgent with better state management for provider and style selection
- Update Gradio app with proper server configuration and logging
This commit is contained in:
2025-09-27 17:49:32 +02:00
parent a51ec67ac1
commit 03d8523a5a
8 changed files with 143 additions and 73 deletions

View File

@@ -1,38 +1,57 @@
import os
from app.markets.base import BaseWrapper
from app.markets.coinbase import CoinBaseWrapper
from app.markets.cryptocompare import CryptoCompareWrapper
# TODO Dare la priorità in base alla qualità del servizio
# TODO Aggiungere altri wrapper se necessario
def get_first_available_market_api(currency:str = "USD") -> BaseWrapper:
"""
Restituisce il primo wrapper disponibile in base alle configurazioni del file .env e alle chiavi API presenti.
La priorità è data a Coinbase, poi a CryptoCompare.
Se non sono presenti chiavi API, restituisce una eccezione.
:param currency: Valuta di riferimento (default "USD")
:return: Lista di istanze di wrapper
"""
return get_list_available_market_apis(currency=currency)[0]
from agno.utils.log import log_warning
def get_list_available_market_apis(currency:str = "USD") -> list[BaseWrapper]:
class MarketAPIs(BaseWrapper):
"""
Restituisce la lista di wrapper disponibili in base alle configurazioni del file .env e alle chiavi API presenti.
La priorità è data a Coinbase, poi a CryptoCompare.
Se non sono presenti chiavi API, restituisce una eccezione.
:param currency: Valuta di riferimento (default "USD")
:return: Lista di istanze di wrapper
Classe per gestire le API di mercato disponibili.
Permette di ottenere un'istanza della prima API disponibile in base alla priorità specificata.
"""
wrappers = []
api_key = os.getenv("COINBASE_API_KEY")
api_secret = os.getenv("COINBASE_API_SECRET")
if api_key and api_secret:
wrappers.append(CoinBaseWrapper(api_key=api_key, api_private_key=api_secret, currency=currency))
@staticmethod
def get_list_available_market_apis(currency: str = "USD") -> list[BaseWrapper]:
"""
Restituisce una lista di istanze delle API di mercato disponibili.
La priorità è data dall'ordine delle API nella lista wrappers.
1. CoinBase
2. CryptoCompare
api_key = os.getenv("CRYPTOCOMPARE_API_KEY")
if api_key:
wrappers.append(CryptoCompareWrapper(api_key=api_key, currency=currency))
:param currency: Valuta di riferimento (default "USD")
:return: Lista di istanze delle API di mercato disponibili
"""
wrapper_builders = [
CoinBaseWrapper,
CryptoCompareWrapper,
]
assert wrappers, "No valid API keys set in environment variables."
return wrappers
result = []
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?")
assert result, "No market API keys set in environment variables."
return result
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")
"""
self.currency = currency
self.wrappers = MarketAPIs.get_list_available_market_apis(currency=currency)
# Metodi che semplicemente chiamano il metodo corrispondente del primo wrapper disponibile
# TODO magari fare in modo che se il primo fallisce, prova con il secondo, ecc.
# oppure fare un round-robin tra i vari wrapper oppure usarli tutti e fare una media dei risultati
def get_product(self, asset_id):
return self.wrappers[0].get_product(asset_id)
def get_products(self, asset_ids: list):
return self.wrappers[0].get_products(asset_ids)
def get_all_products(self):
return self.wrappers[0].get_all_products()
def get_historical_prices(self, asset_id = "BTC"):
return self.wrappers[0].get_historical_prices(asset_id)