Refactoring architetturale e spostamento classi base
- Eliminazione del file __init__.py obsoleto che importava ChatManager e Pipeline - Spostamento della classe Pipeline in agents/pipeline.py - Spostamento della classe ChatManager in utils/chat_manager.py - Aggiornamento di __main__.py per importare da app.utils e app.agents, e modifica della logica per utilizzare Pipeline invece di chat per la selezione di provider e stile - Creazione della cartella base con classi base comuni: markets.py (ProductInfo, Price, MarketWrapper), news.py (Article, NewsWrapper), social.py (SocialPost, SocialComment, SocialWrapper) - Aggiornamento di tutti gli import nel progetto (markets/, news/, social/, utils/, tests/) per utilizzare la nuova struttura base/
This commit is contained in:
@@ -1,4 +0,0 @@
|
|||||||
from app.chat_manager import ChatManager
|
|
||||||
from app.pipeline import Pipeline
|
|
||||||
|
|
||||||
__all__ = ["ChatManager", "Pipeline"]
|
|
||||||
@@ -1,19 +1,23 @@
|
|||||||
import gradio as gr
|
import gradio as gr
|
||||||
from agno.utils.log import log_info #type: ignore
|
|
||||||
from dotenv import load_dotenv
|
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__":
|
if __name__ == "__main__":
|
||||||
# Inizializzazioni
|
# Inizializzazioni
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
pipeline = Pipeline()
|
||||||
chat = ChatManager()
|
chat = ChatManager()
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# Funzioni Gradio
|
# Funzioni Gradio
|
||||||
########################################
|
########################################
|
||||||
def respond(message: str, history: list[dict[str, str]]) -> tuple[list[dict[str, str]], list[dict[str, str]], str]:
|
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": "user", "content": message})
|
||||||
history.append({"role": "assistant", "content": response})
|
history.append({"role": "assistant", "content": response})
|
||||||
return history, history, ""
|
return history, history, ""
|
||||||
@@ -42,18 +46,18 @@ if __name__ == "__main__":
|
|||||||
# Dropdown provider e stile
|
# Dropdown provider e stile
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
provider = gr.Dropdown(
|
provider = gr.Dropdown(
|
||||||
choices=chat.list_providers(),
|
choices=pipeline.list_providers(),
|
||||||
type="index",
|
type="index",
|
||||||
label="Modello da usare"
|
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(
|
style = gr.Dropdown(
|
||||||
choices=chat.list_styles(),
|
choices=pipeline.list_styles(),
|
||||||
type="index",
|
type="index",
|
||||||
label="Stile di investimento"
|
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")
|
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?")
|
msg = gr.Textbox(label="Scrivi la tua richiesta", placeholder="Es: Quali sono le crypto interessanti oggi?")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from app.agents.models import AppModels
|
from app.agents.models import AppModels
|
||||||
from app.agents.predictor import PredictorInput, PredictorOutput, PredictorStyle, PREDICTOR_INSTRUCTIONS
|
from app.agents.predictor import PredictorInput, PredictorOutput, PredictorStyle, PREDICTOR_INSTRUCTIONS
|
||||||
from app.agents.team import create_team_with
|
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"]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from agno.run.agent import RunOutput
|
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.team import create_team_with
|
||||||
from app.agents.predictor import PREDICTOR_INSTRUCTIONS, PredictorInput, PredictorOutput, PredictorStyle
|
from app.agents.predictor import PREDICTOR_INSTRUCTIONS, PredictorInput, PredictorOutput, PredictorStyle
|
||||||
from app.markets.base import ProductInfo
|
from app.base.markets import ProductInfo
|
||||||
|
|
||||||
|
|
||||||
class Pipeline:
|
class Pipeline:
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from app.markets.base import ProductInfo
|
from app.base.markets import ProductInfo
|
||||||
|
|
||||||
|
|
||||||
class PredictorStyle(Enum):
|
class PredictorStyle(Enum):
|
||||||
|
|||||||
0
src/app/base/__init__.py
Normal file
0
src/app/base/__init__.py
Normal file
@@ -1,5 +1,5 @@
|
|||||||
from agno.tools import Toolkit
|
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.binance import BinanceWrapper
|
||||||
from app.markets.coinbase import CoinBaseWrapper
|
from app.markets.coinbase import CoinBaseWrapper
|
||||||
from app.markets.cryptocompare import CryptoCompareWrapper
|
from app.markets.cryptocompare import CryptoCompareWrapper
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from binance.client import Client # type: ignore
|
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:
|
def extract_product(currency: str, ticker_data: dict[str, Any]) -> ProductInfo:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from enum import Enum
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from coinbase.rest import RESTClient # type: ignore
|
from coinbase.rest import RESTClient # type: ignore
|
||||||
from coinbase.rest.types.product_types import Candle, GetProductResponse, Product # 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:
|
def extract_product(product_data: GetProductResponse | Product) -> ProductInfo:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
from typing import Any
|
from typing import Any
|
||||||
import requests
|
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:
|
def extract_product(asset_data: dict[str, Any]) -> ProductInfo:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
from agno.tools.yfinance import YFinanceTools
|
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:
|
def extract_product(stock_data: dict[str, str]) -> ProductInfo:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from agno.tools import Toolkit
|
from agno.tools import Toolkit
|
||||||
from app.utils import WrapperHandler
|
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.news_api import NewsApiWrapper
|
||||||
from app.news.googlenews import GoogleNewsWrapper
|
from app.news.googlenews import GoogleNewsWrapper
|
||||||
from app.news.cryptopanic_api import CryptoPanicWrapper
|
from app.news.cryptopanic_api import CryptoPanicWrapper
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import os
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
import requests
|
import requests
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from app.news.base import NewsWrapper, Article
|
from app.base.news import NewsWrapper, Article
|
||||||
|
|
||||||
|
|
||||||
class CryptoPanicFilter(Enum):
|
class CryptoPanicFilter(Enum):
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from agno.tools.duckduckgo import DuckDuckGoTools
|
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:
|
def extract_article(result: dict[str, Any]) -> Article:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from gnews import GNews # type: ignore
|
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:
|
def extract_article(result: dict[str, Any]) -> Article:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
from typing import Any
|
from typing import Any
|
||||||
import newsapi # type: ignore
|
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:
|
def extract_article(result: dict[str, Any]) -> Article:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from agno.tools import Toolkit
|
from agno.tools import Toolkit
|
||||||
from app.utils import WrapperHandler
|
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
|
from app.social.reddit import RedditWrapper
|
||||||
|
|
||||||
__all__ = ["SocialAPIsTool", "RedditWrapper", "SocialPost"]
|
__all__ = ["SocialAPIsTool", "RedditWrapper", "SocialPost"]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
from praw import Reddit # type: ignore
|
from praw import Reddit # type: ignore
|
||||||
from praw.models import Submission, MoreComments # 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
|
MAX_COMMENTS = 5
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from app.utils.market_aggregation import aggregate_history_prices, aggregate_product_info
|
from app.utils.market_aggregation import aggregate_history_prices, aggregate_product_info
|
||||||
from app.utils.wrapper_handler import WrapperHandler
|
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"]
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
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:
|
class ChatManager:
|
||||||
"""
|
"""
|
||||||
@@ -15,19 +10,19 @@ class ChatManager:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.pipeline = Pipeline()
|
|
||||||
self.history: list[dict[str, str]] = [] # [{"role": "user"/"assistant", "content": "..."}]
|
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.
|
Aggiunge un messaggio utente, chiama la Pipeline e salva la risposta nello storico.
|
||||||
"""
|
"""
|
||||||
# Aggiungi messaggio utente allo storico
|
# Aggiungi messaggio utente allo storico
|
||||||
self.history.append({"role": "user", "content": message})
|
self.history.append({"role": "user", "content": message})
|
||||||
|
|
||||||
# Pipeline elabora la query
|
def receive_message(self, response: str) -> str:
|
||||||
response = self.pipeline.interact(message)
|
"""
|
||||||
|
Riceve un messaggio dalla pipeline e lo aggiunge allo storico.
|
||||||
|
"""
|
||||||
# Aggiungi risposta assistente allo storico
|
# Aggiungi risposta assistente allo storico
|
||||||
self.history.append({"role": "assistant", "content": response})
|
self.history.append({"role": "assistant", "content": response})
|
||||||
|
|
||||||
@@ -37,19 +32,17 @@ class ChatManager:
|
|||||||
"""
|
"""
|
||||||
Salva la chat corrente in src/saves/<filename>.
|
Salva la chat corrente in src/saves/<filename>.
|
||||||
"""
|
"""
|
||||||
path = os.path.join(SAVE_DIR, filename)
|
with open(filename, "w", encoding="utf-8") as f:
|
||||||
with open(path, "w", encoding="utf-8") as f:
|
|
||||||
json.dump(self.history, f, ensure_ascii=False, indent=2)
|
json.dump(self.history, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
def load_chat(self, filename: str = "chat.json") -> None:
|
def load_chat(self, filename: str = "chat.json") -> None:
|
||||||
"""
|
"""
|
||||||
Carica una chat salvata da src/saves/<filename>.
|
Carica una chat salvata da src/saves/<filename>.
|
||||||
"""
|
"""
|
||||||
path = os.path.join(SAVE_DIR, filename)
|
if not os.path.exists(filename):
|
||||||
if not os.path.exists(path):
|
|
||||||
self.history = []
|
self.history = []
|
||||||
return
|
return
|
||||||
with open(path, "r", encoding="utf-8") as f:
|
with open(filename, "r", encoding="utf-8") as f:
|
||||||
self.history = json.load(f)
|
self.history = json.load(f)
|
||||||
|
|
||||||
def reset_chat(self) -> None:
|
def reset_chat(self) -> None:
|
||||||
@@ -63,16 +56,3 @@ class ChatManager:
|
|||||||
Restituisce lo storico completo della chat.
|
Restituisce lo storico completo della chat.
|
||||||
"""
|
"""
|
||||||
return self.history
|
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()
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import statistics
|
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]:
|
def aggregate_history_prices(prices: dict[str, list[Price]]) -> list[Price]:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from app.agents import AppModels
|
from app.agents import AppModels
|
||||||
from app.agents.predictor import PREDICTOR_INSTRUCTIONS, PredictorInput, PredictorOutput, PredictorStyle
|
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):
|
def unified_checks(model: AppModels, input):
|
||||||
llm = model.get_agent(PREDICTOR_INSTRUCTIONS, output=PredictorOutput) # type: ignore[arg-type]
|
llm = model.get_agent(PREDICTOR_INSTRUCTIONS, output=PredictorOutput) # type: ignore[arg-type]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import pytest
|
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
|
from app.utils.market_aggregation import aggregate_history_prices, aggregate_product_info
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user