Refactor and update structure #20

Merged
Berack96 merged 22 commits from 16-refactoring-e-sanity-check into main 2025-10-08 16:21:10 +02:00
26 changed files with 41 additions and 59 deletions
Showing only changes of commit f0193b94bb - Show all commits

View File

@@ -1,4 +0,0 @@
from app.chat_manager import ChatManager
from app.pipeline import Pipeline
__all__ = ["ChatManager", "Pipeline"]

View File

@@ -1,19 +1,23 @@
import gradio as gr
from agno.utils.log import log_info #type: ignore
from dotenv import load_dotenv
from app import ChatManager
from agno.utils.log import log_info #type: ignore
from app.utils import ChatManager
from app.agents import Pipeline
if __name__ == "__main__":
# Inizializzazioni
load_dotenv()
pipeline = Pipeline()
chat = ChatManager()
########################################
# Funzioni Gradio
########################################
def respond(message: str, history: list[dict[str, str]]) -> tuple[list[dict[str, str]], list[dict[str, str]], str]:
response = chat.send_message(message)
chat.send_message(message)
response = pipeline.interact(message)
chat.receive_message(response)
history.append({"role": "user", "content": message})
history.append({"role": "assistant", "content": response})
return history, history, ""
@@ -42,18 +46,18 @@ if __name__ == "__main__":
# Dropdown provider e stile
with gr.Row():
provider = gr.Dropdown(
choices=chat.list_providers(),
choices=pipeline.list_providers(),
type="index",
label="Modello da usare"
)
provider.change(fn=chat.choose_provider, inputs=provider, outputs=None)
provider.change(fn=pipeline.choose_predictor, inputs=provider, outputs=None)
style = gr.Dropdown(
choices=chat.list_styles(),
choices=pipeline.list_styles(),
type="index",
label="Stile di investimento"
)
style.change(fn=chat.choose_style, inputs=style, outputs=None)
style.change(fn=pipeline.choose_style, inputs=style, outputs=None)
chatbot = gr.Chatbot(label="Conversazione", height=500, type="messages")
msg = gr.Textbox(label="Scrivi la tua richiesta", placeholder="Es: Quali sono le crypto interessanti oggi?")

View File

@@ -1,5 +1,6 @@
from app.agents.models import AppModels
from app.agents.predictor import PredictorInput, PredictorOutput, PredictorStyle, PREDICTOR_INSTRUCTIONS
from app.agents.team import create_team_with
from app.agents.pipeline import Pipeline
__all__ = ["AppModels", "PredictorInput", "PredictorOutput", "PredictorStyle", "PREDICTOR_INSTRUCTIONS", "create_team_with"]
__all__ = ["AppModels", "PredictorInput", "PredictorOutput", "PredictorStyle", "PREDICTOR_INSTRUCTIONS", "create_team_with", "Pipeline"]

View File

@@ -1,8 +1,8 @@
from agno.run.agent import RunOutput
from app.agents import AppModels
from app.agents.models import AppModels
from app.agents.team import create_team_with
from app.agents.predictor import PREDICTOR_INSTRUCTIONS, PredictorInput, PredictorOutput, PredictorStyle
from app.markets.base import ProductInfo
from app.base.markets import ProductInfo
class Pipeline:

View File

@@ -1,6 +1,6 @@
from enum import Enum
from pydantic import BaseModel, Field
from app.markets.base import ProductInfo
from app.base.markets import ProductInfo
class PredictorStyle(Enum):

0
src/app/base/__init__.py Normal file
View File

View File

@@ -1,5 +1,5 @@
from agno.tools import Toolkit
from app.markets.base import MarketWrapper, Price, ProductInfo
from app.base.markets import MarketWrapper, Price, ProductInfo
from app.markets.binance import BinanceWrapper
from app.markets.coinbase import CoinBaseWrapper
from app.markets.cryptocompare import CryptoCompareWrapper

View File

@@ -1,7 +1,7 @@
import os
copilot-pull-request-reviewer[bot] commented 2025-10-05 22:06:00 +02:00 (Migrated from github.com)
Review

The docstring states the default currency is 'USD' but then mentions it gets changed to 'USDT'. This is confusing - the documentation should clearly explain that USD gets automatically converted to USDT for Binance compatibility.

        Inizializza il wrapper di Binance con le credenziali API e la valuta di riferimento.
        Se viene fornita una valuta fiat come "USD", questa viene automaticamente convertita in una stablecoin Tether ("USDT") per compatibilità con Binance,
        poiché Binance non supporta direttamente le valute fiat per il trading di criptovalute.
        Tutti i prezzi e volumi restituiti saranno quindi denominati nella stablecoin (ad esempio, "USDT") e non nella valuta fiat originale.
        Args:
            currency (str): Valuta in cui restituire i prezzi. Se "USD" viene fornito, verrà utilizzato "USDT". Default è "USD".
The docstring states the default currency is 'USD' but then mentions it gets changed to 'USDT'. This is confusing - the documentation should clearly explain that USD gets automatically converted to USDT for Binance compatibility. ```suggestion Inizializza il wrapper di Binance con le credenziali API e la valuta di riferimento. Se viene fornita una valuta fiat come "USD", questa viene automaticamente convertita in una stablecoin Tether ("USDT") per compatibilità con Binance, poiché Binance non supporta direttamente le valute fiat per il trading di criptovalute. Tutti i prezzi e volumi restituiti saranno quindi denominati nella stablecoin (ad esempio, "USDT") e non nella valuta fiat originale. Args: currency (str): Valuta in cui restituire i prezzi. Se "USD" viene fornito, verrà utilizzato "USDT". Default è "USD". ```
from typing import Any
from binance.client import Client # type: ignore
from app.markets.base import ProductInfo, MarketWrapper, Price
from app.base.markets import ProductInfo, MarketWrapper, Price
def extract_product(currency: str, ticker_data: dict[str, Any]) -> ProductInfo:

View File

@@ -3,7 +3,7 @@ from enum import Enum
from datetime import datetime, timedelta
from coinbase.rest import RESTClient # type: ignore
from coinbase.rest.types.product_types import Candle, GetProductResponse, Product # type: ignore
from app.markets.base import ProductInfo, MarketWrapper, Price
from app.base.markets import ProductInfo, MarketWrapper, Price
def extract_product(product_data: GetProductResponse | Product) -> ProductInfo:

View File

@@ -1,7 +1,7 @@
import os
from typing import Any
import requests
from app.markets.base import ProductInfo, MarketWrapper, Price
from app.base.markets import ProductInfo, MarketWrapper, Price
def extract_product(asset_data: dict[str, Any]) -> ProductInfo:

View File

@@ -1,6 +1,6 @@
import json
from agno.tools.yfinance import YFinanceTools
from app.markets.base import MarketWrapper, ProductInfo, Price
from app.base.markets import MarketWrapper, ProductInfo, Price
def extract_product(stock_data: dict[str, str]) -> ProductInfo:

View File

@@ -1,6 +1,6 @@
from agno.tools import Toolkit
from app.utils import WrapperHandler
from app.news.base import NewsWrapper, Article
from app.base.news import NewsWrapper, Article
from app.news.news_api import NewsApiWrapper
from app.news.googlenews import GoogleNewsWrapper
from app.news.cryptopanic_api import CryptoPanicWrapper

View File

@@ -2,7 +2,7 @@ import os
from typing import Any
import requests
from enum import Enum
from app.news.base import NewsWrapper, Article
from app.base.news import NewsWrapper, Article
class CryptoPanicFilter(Enum):

View File

@@ -1,7 +1,7 @@
import json
from typing import Any
from agno.tools.duckduckgo import DuckDuckGoTools
from app.news.base import Article, NewsWrapper
from app.base.news import Article, NewsWrapper
def extract_article(result: dict[str, Any]) -> Article:

View File

@@ -1,6 +1,6 @@
from typing import Any
from gnews import GNews # type: ignore
from app.news.base import Article, NewsWrapper
from app.base.news import Article, NewsWrapper
def extract_article(result: dict[str, Any]) -> Article:

View File

@@ -1,7 +1,7 @@
import os
from typing import Any
import newsapi # type: ignore
from app.news.base import Article, NewsWrapper
from app.base.news import Article, NewsWrapper
def extract_article(result: dict[str, Any]) -> Article:

View File

@@ -1,6 +1,6 @@
from agno.tools import Toolkit
from app.utils import WrapperHandler
from app.social.base import SocialPost, SocialWrapper
from app.base.social import SocialPost, SocialWrapper
from app.social.reddit import RedditWrapper
__all__ = ["SocialAPIsTool", "RedditWrapper", "SocialPost"]

View File

@@ -1,7 +1,7 @@
import os
from praw import Reddit # type: ignore
from praw.models import Submission, MoreComments # type: ignore
from app.social.base import SocialWrapper, SocialPost, SocialComment
from app.base.social import SocialWrapper, SocialPost, SocialComment
MAX_COMMENTS = 5

View File

@@ -1,4 +1,5 @@
from app.utils.market_aggregation import aggregate_history_prices, aggregate_product_info
from app.utils.wrapper_handler import WrapperHandler
from app.utils.chat_manager import ChatManager
__all__ = ["aggregate_history_prices", "aggregate_product_info", "WrapperHandler"]
__all__ = ["aggregate_history_prices", "aggregate_product_info", "WrapperHandler", "ChatManager"]

View File

@@ -1,10 +1,5 @@
import json
import os
from app import Pipeline
SAVE_DIR = os.path.join(os.path.dirname(__file__), "..", "saves")
os.makedirs(SAVE_DIR, exist_ok=True)
class ChatManager:
"""
@@ -15,19 +10,19 @@ class ChatManager:
"""
def __init__(self):
self.pipeline = Pipeline()
self.history: list[dict[str, str]] = [] # [{"role": "user"/"assistant", "content": "..."}]
def send_message(self, message: str) -> str:
def send_message(self, message: str) -> None:
"""
Aggiunge un messaggio utente, chiama la Pipeline e salva la risposta nello storico.
"""
# Aggiungi messaggio utente allo storico
self.history.append({"role": "user", "content": message})
# Pipeline elabora la query
response = self.pipeline.interact(message)
def receive_message(self, response: str) -> str:
"""
Riceve un messaggio dalla pipeline e lo aggiunge allo storico.
"""
# Aggiungi risposta assistente allo storico
self.history.append({"role": "assistant", "content": response})
@@ -37,19 +32,17 @@ class ChatManager:
"""
Salva la chat corrente in src/saves/<filename>.
"""
path = os.path.join(SAVE_DIR, filename)
with open(path, "w", encoding="utf-8") as f:
with open(filename, "w", encoding="utf-8") as f:
json.dump(self.history, f, ensure_ascii=False, indent=2)
def load_chat(self, filename: str = "chat.json") -> None:
"""
Carica una chat salvata da src/saves/<filename>.
"""
path = os.path.join(SAVE_DIR, filename)
if not os.path.exists(path):
if not os.path.exists(filename):
self.history = []
return
with open(path, "r", encoding="utf-8") as f:
with open(filename, "r", encoding="utf-8") as f:
self.history = json.load(f)
def reset_chat(self) -> None:
@@ -63,16 +56,3 @@ class ChatManager:
Restituisce lo storico completo della chat.
"""
return self.history
# Facciamo pass-through di provider e style, così Gradio può usarli
def choose_provider(self, index: int):
self.pipeline.choose_predictor(index)
def choose_style(self, index: int):
self.pipeline.choose_style(index)
def list_providers(self) -> list[str]:
return self.pipeline.list_providers()
def list_styles(self) -> list[str]:
return self.pipeline.list_styles()

View File

@@ -1,5 +1,5 @@
import statistics
from app.markets.base import ProductInfo, Price
from app.base.markets import ProductInfo, Price
def aggregate_history_prices(prices: dict[str, list[Price]]) -> list[Price]:

View File

@@ -1,7 +1,7 @@
import pytest
from app.agents import AppModels
from app.agents.predictor import PREDICTOR_INSTRUCTIONS, PredictorInput, PredictorOutput, PredictorStyle
from app.markets.base import ProductInfo
from app.base.markets import ProductInfo
def unified_checks(model: AppModels, input):
llm = model.get_agent(PREDICTOR_INSTRUCTIONS, output=PredictorOutput) # type: ignore[arg-type]

View File

@@ -1,5 +1,5 @@
import pytest
from app.markets.base import ProductInfo, Price
from app.base.markets import ProductInfo, Price
from app.utils.market_aggregation import aggregate_history_prices, aggregate_product_info