Refactor team management #26

Merged
Berack96 merged 14 commits from 21-team-monitoring into main 2025-10-15 14:00:39 +02:00
7 changed files with 198 additions and 165 deletions
Showing only changes of commit 544e179305 - Show all commits

View File

@@ -3,22 +3,21 @@ import logging
from dotenv import load_dotenv from dotenv import load_dotenv
from app.configs import AppConfig from app.configs import AppConfig
from app.interface import * from app.interface import *
from app.agents import Pipeline
if __name__ == "__main__": if __name__ == "__main__":
# =====================
load_dotenv() load_dotenv()
configs = AppConfig.load() configs = AppConfig.load()
pipeline = Pipeline(configs) # =====================
chat = ChatManager(pipeline) chat = ChatManager()
gradio = chat.gradio_build_interface() gradio = chat.gradio_build_interface()
_app, local_url, share_url = gradio.launch(server_name="0.0.0.0", server_port=configs.port, quiet=True, prevent_thread_lock=True, share=configs.gradio_share) _app, local_url, share_url = gradio.launch(server_name="0.0.0.0", server_port=configs.port, quiet=True, prevent_thread_lock=True, share=configs.gradio_share)
logging.info(f"UPO AppAI Chat is running on {share_url or local_url}") logging.info(f"UPO AppAI Chat is running on {share_url or local_url}")
try: try:
telegram = TelegramApp(pipeline) telegram = TelegramApp()
telegram.add_miniapp_url(share_url) telegram.add_miniapp_url(share_url)
telegram.run() telegram.run()
except AssertionError as e: except AssertionError as e:

View File

@@ -1,5 +1,4 @@
from app.agents.predictor import PredictorInput, PredictorOutput from app.agents.predictor import PredictorInput, PredictorOutput
from app.agents.pipeline import Pipeline from app.agents.pipeline import Pipeline, PipelineInputs, PipelineEvent
from app.agents.team import AppTeam
__all__ = ["PredictorInput", "PredictorOutput", "Pipeline", "AppTeam"] __all__ = ["PredictorInput", "PredictorOutput", "Pipeline", "PipelineInputs", "PipelineEvent"]

View File

@@ -1,31 +1,57 @@
import asyncio
copilot-pull-request-reviewer[bot] commented 2025-10-15 13:45:47 +02:00 (Migrated from github.com)
Review

The docstring incorrectly describes this method as choosing the model for the Team, but it actually chooses the team leader model.

        Sceglie il modello LLM da usare per il Team Leader.
The docstring incorrectly describes this method as choosing the model for the Team, but it actually chooses the team leader model. ```suggestion Sceglie il modello LLM da usare per il Team Leader. ```
from enum import Enum
import logging import logging
from typing import Callable import random
from typing import Any, Callable
from agno.agent import RunEvent
from agno.team import Team, TeamRunEvent
from agno.tools.reasoning import ReasoningTools
from agno.run.workflow import WorkflowRunEvent
from agno.workflow.step import Step
from agno.workflow.workflow import Workflow
from app.api.tools import *
from app.agents.prompts import * from app.agents.prompts import *
from app.agents.team import AppTeam, AppEvent, TeamRunEvent, RunEvent
from app.configs import AppConfig from app.configs import AppConfig
logging = logging.getLogger("pipeline") logging = logging.getLogger("pipeline")
class Pipeline: class PipelineEvent(str, Enum):
PLANNER = "Planner"
INFO_RECOVERY = "Info Recovery"
REPORT_GENERATION = "Report Generation"
REPORT_TRANSLATION = "Report Translation"
TOOL_USED = RunEvent.tool_call_completed
def check_event(self, event: str, step_name: str) -> bool:
return event == self.value or (WorkflowRunEvent.step_completed and step_name == self.value)
class PipelineInputs:
""" """
Coordina gli agenti di servizio (Market, News, Social) e il Predictor finale. Classe necessaria per passare gli input alla Pipeline.
Il Team è orchestrato da qwen3:latest (Ollama), mentre il Predictor è dinamico Serve per raggruppare i parametri e semplificare l'inizializzazione.
e scelto dall'utente tramite i dropdown dell'interfaccia grafica.
""" """
def __init__(self, configs: AppConfig): def __init__(self, configs: AppConfig | None = None) -> None:
self.configs = configs """
Inputs per la Pipeline di agenti.
Setta i valori di default se non specificati.
"""
self.configs = configs if configs else AppConfig()
# Stato iniziale agents = self.configs.agents
self.leader_model = self.configs.get_model_by_name(self.configs.agents.team_leader_model) self.team_model = self.configs.get_model_by_name(agents.team_model)
self.team_model = self.configs.get_model_by_name(self.configs.agents.team_model) self.team_leader_model = self.configs.get_model_by_name(agents.team_leader_model)
self.strategy = self.configs.get_strategy_by_name(self.configs.agents.strategy) self.predictor_model = self.configs.get_model_by_name(agents.predictor_model)
self.strategy = self.configs.get_strategy_by_name(agents.strategy)
self.user_query = ""
# ====================== # ======================
# Dropdown handlers # Dropdown handlers
# ====================== # ======================
def choose_leader(self, index: int): def choose_team_leader(self, index: int):
""" """
Sceglie il modello LLM da usare per il Team. Sceglie il modello LLM da usare per il Team.
""" """
@@ -46,47 +72,132 @@ class Pipeline:
# ====================== # ======================
# Helpers # Helpers
# ====================== # ======================
def list_providers(self) -> list[str]: def list_models_names(self) -> list[str]:
""" """
Restituisce la lista dei nomi dei modelli disponibili. Restituisce la lista dei nomi dei modelli disponibili.
""" """
return [model.label for model in self.configs.models.all_models] return [model.label for model in self.configs.models.all_models]
def list_styles(self) -> list[str]: def list_strategies_names(self) -> list[str]:
""" """
Restituisce la lista degli stili di previsione disponibili. Restituisce la lista delle strategie disponibili.
""" """
return [strat.label for strat in self.configs.strategies] return [strat.label for strat in self.configs.strategies]
class Pipeline:
"""
Coordina gli agenti di servizio (Market, News, Social) e il Predictor finale.
Il Team è orchestrato da qwen3:latest (Ollama), mentre il Predictor è dinamico
e scelto dall'utente tramite i dropdown dell'interfaccia grafica.
"""
def __init__(self, inputs: PipelineInputs):
self.inputs = inputs
# ====================== # ======================
# Core interaction # Core interaction
# ====================== # ======================
def interact(self, query: str, listeners: dict[RunEvent | TeamRunEvent, Callable[[AppEvent], None]] = {}) -> str: def interact(self, listeners: dict[RunEvent | TeamRunEvent, Callable[[PipelineEvent], None]] = {}) -> str:
""" """
Esegue la pipeline di agenti per rispondere alla query dell'utente. Esegue la pipeline di agenti per rispondere alla query dell'utente.
1. Crea il Team di agenti.
2. Aggiunge listener per eventi di logging.
3. Esegue il Team con la query dell'utente.
4. Recupera e restituisce l'output generato dagli agenti.
Args: Args:
query (str): La query dell'utente. listeners: dizionario di callback per eventi specifici (opzionale)
Returns: Returns:
str: La risposta generata dagli agenti. La risposta generata dalla pipeline.
""" """
logging.info(f"Pipeline received query: {query}") return asyncio.run(self.interact_async(listeners))
# Step 1: Creazione Team async def interact_async(self, listeners: dict[RunEvent | TeamRunEvent, Callable[[PipelineEvent], None]] = {}) -> str:
team = AppTeam(self.configs, self.team_model, self.leader_model) """
Versione asincrona che esegue la pipeline di agenti per rispondere alla query dell'utente.
Args:
listeners: dizionario di callback per eventi specifici (opzionale)
Returns:
La risposta generata dalla pipeline.
"""
run_id = random.randint(1000, 9999) # Per tracciare i log
logging.info(f"[{run_id}] Pipeline query: {self.inputs.user_query}")
# Step 2: Aggiunti listener per eventi # Step 1: Crea gli agenti e il team
for event_name, listener in listeners.items(): market_tool, news_tool, social_tool = self.get_tools()
team.add_listener(event_name, listener) market_agent = self.inputs.team_model.get_agent(instructions=MARKET_INSTRUCTIONS, name="MarketAgent", tools=[market_tool])
news_agent = self.inputs.team_model.get_agent(instructions=NEWS_INSTRUCTIONS, name="NewsAgent", tools=[news_tool])
social_agent = self.inputs.team_model.get_agent(instructions=SOCIAL_INSTRUCTIONS, name="SocialAgent", tools=[social_tool])
# Step 3: Esecuzione Team team = Team(
# TODO migliorare prompt (?) model=self.inputs.team_leader_model.get_model(COORDINATOR_INSTRUCTIONS),
query = f"The user query is: {query}\n\n They requested a {self.strategy.label} investment strategy." name="CryptoAnalysisTeam",
result = team.run_team(query) tools=[ReasoningTools()],
members=[market_agent, news_agent, social_agent],
)
# Step 4: Recupero output # Step 3: Crea il workflow
logging.info(f"Team finished") #query_planner = Step(name=PipelineEvent.PLANNER, agent=Agent())
info_recovery = Step(name=PipelineEvent.INFO_RECOVERY, team=team)
#report_generation = Step(name=PipelineEvent.REPORT_GENERATION, agent=Agent())
#report_translate = Step(name=AppEvent.REPORT_TRANSLATION, agent=Agent())
workflow = Workflow(
name="App Workflow",
steps=[
#query_planner,
info_recovery,
#report_generation,
#report_translate
]
)
# Step 4: Fai partire il workflow e prendi l'output
query = f"The user query is: {self.inputs.user_query}\n\n They requested a {self.inputs.strategy.label} investment strategy."
result = await self.run(workflow, query, events={})
logging.info(f"[{run_id}] Run finished")
return result return result
# ======================
# Helpers
# =====================
def get_tools(self) -> tuple[MarketAPIsTool, NewsAPIsTool, SocialAPIsTool]:
"""
Restituisce la lista di tools disponibili per gli agenti.
"""
api = self.inputs.configs.api
market_tool = MarketAPIsTool(currency=api.currency)
market_tool.handler.set_retries(api.retry_attempts, api.retry_delay_seconds)
news_tool = NewsAPIsTool()
news_tool.handler.set_retries(api.retry_attempts, api.retry_delay_seconds)
social_tool = SocialAPIsTool()
social_tool.handler.set_retries(api.retry_attempts, api.retry_delay_seconds)
return (market_tool, news_tool, social_tool)
@classmethod
async def run(cls, workflow: Workflow, query: str, events: dict[PipelineEvent, Callable[[Any], None]]) -> str:
"""
Esegue il workflow e gestisce gli eventi tramite le callback fornite.
Args:
workflow: istanza di Workflow da eseguire
query: query dell'utente da passare al workflow
events: dizionario di callback per eventi specifici (opzionale)
Returns:
La risposta generata dal workflow.
"""
iterator = await workflow.arun(query, stream=True, stream_intermediate_steps=True)
content = None
async for event in iterator:
step_name = getattr(event, 'step_name', '')
for app_event, listener in events.items():
if app_event.check_event(event.event, step_name):
listener(event)
if event.event == WorkflowRunEvent.workflow_completed:
content = getattr(event, 'content', '')
if isinstance(content, str):
think_str = "</think>"
think = content.rfind(think_str)
content = content[(think + len(think_str)):] if think != -1 else content
return content if content else "No output from workflow, something went wrong."

View File

@@ -1,64 +0,0 @@
import asyncio
from typing import Callable
from agno.agent import RunEvent, RunOutputEvent
from agno.team import Team, TeamRunEvent, TeamRunOutputEvent
from agno.tools.reasoning import ReasoningTools
from app.agents.prompts import *
from app.configs import AppConfig, AppModel
from app.api.tools import *
# Define a unified event type for team and agent events
AppEvent = TeamRunOutputEvent | RunOutputEvent
class AppTeam:
def __init__(self, configs: AppConfig, team_models: AppModel, team_leader: AppModel | None = None):
self.configs = configs
self.team_models = team_models
self.team_leader = team_leader or team_models
self.listeners: dict[str, Callable[[AppEvent], None]] = {}
def add_listener(self, event: RunEvent | TeamRunEvent, listener: Callable[[AppEvent], None]) -> None:
self.listeners[event.value] = listener
def run_team(self, query: str) -> str:
return asyncio.run(self.run_team_async(query))
async def run_team_async(self, query: str) -> str:
team = AppTeam.create_team_with(self.configs, self.team_models, self.team_leader)
result = "No output from team"
async for run_event in team.arun(query, stream=True, stream_intermediate_steps=True): # type: ignore
if run_event.event in self.listeners:
self.listeners[run_event.event](run_event)
if run_event.event in [TeamRunEvent.run_completed]:
if isinstance(run_event.content, str):
result = run_event.content
thinking = result.rfind("</think>")
if thinking != -1: result = result[thinking:]
return result
@classmethod
def create_team_with(cls, configs: AppConfig, team_model: AppModel, team_leader: AppModel | None = None) -> Team:
market_tool = MarketAPIsTool(currency=configs.api.currency)
market_tool.handler.set_retries(configs.api.retry_attempts, configs.api.retry_delay_seconds)
news_tool = NewsAPIsTool()
news_tool.handler.set_retries(configs.api.retry_attempts, configs.api.retry_delay_seconds)
social_tool = SocialAPIsTool()
social_tool.handler.set_retries(configs.api.retry_attempts, configs.api.retry_delay_seconds)
market_agent = team_model.get_agent(instructions=MARKET_INSTRUCTIONS, name="MarketAgent", tools=[market_tool])
news_agent = team_model.get_agent(instructions=NEWS_INSTRUCTIONS, name="NewsAgent", tools=[news_tool])
social_agent = team_model.get_agent(instructions=SOCIAL_INSTRUCTIONS, name="SocialAgent", tools=[social_tool])
team_leader = team_leader or team_model
return Team(
model=team_leader.get_model(COORDINATOR_INSTRUCTIONS),
name="CryptoAnalysisTeam",
tools=[ReasoningTools()],
members=[market_agent, news_agent, social_agent],
)

View File

@@ -104,8 +104,6 @@ class AppConfig(BaseModel):
data = yaml.safe_load(f) data = yaml.safe_load(f)
configs = cls(**data) configs = cls(**data)
configs.set_logging_level()
configs.validate_models()
log.info(f"Loaded configuration from {file_path}") log.info(f"Loaded configuration from {file_path}")
return configs return configs
@@ -115,6 +113,15 @@ class AppConfig(BaseModel):
cls.instance = super(AppConfig, cls).__new__(cls) cls.instance = super(AppConfig, cls).__new__(cls)
return cls.instance return cls.instance
def __init__(self, *args: Any, **kwargs: Any) -> None:
if hasattr(self, '_initialized'):
return
super().__init__(*args, **kwargs)
self.set_logging_level()
self.validate_models()
self._initialized = True
def get_model_by_name(self, name: str) -> AppModel: def get_model_by_name(self, name: str) -> AppModel:
""" """
Retrieve a model configuration by its name. Retrieve a model configuration by its name.
@@ -145,17 +152,6 @@ class AppConfig(BaseModel):
return strat return strat
raise ValueError(f"Strategy with name '{name}' not found.") raise ValueError(f"Strategy with name '{name}' not found.")
def get_defaults(self) -> tuple[AppModel, AppModel, Strategy]:
"""
Retrieve the default team model, leader model, and strategy.
Returns:
A tuple containing the default team model (AppModel), leader model (AppModel), and strategy (Strategy).
"""
team_model = self.get_model_by_name(self.agents.team_model)
leader_model = self.get_model_by_name(self.agents.team_leader_model)
strategy = self.get_strategy_by_name(self.agents.strategy)
return team_model, leader_model, strategy
def set_logging_level(self) -> None: def set_logging_level(self) -> None:
""" """
Set the logging level based on the configuration. Set the logging level based on the configuration.

View File

@@ -1,7 +1,7 @@
import os import os
import json import json
import gradio as gr import gradio as gr
from app.agents.pipeline import Pipeline from app.agents.pipeline import Pipeline, PipelineInputs
class ChatManager: class ChatManager:
@@ -12,9 +12,9 @@ class ChatManager:
- salva e ricarica le chat - salva e ricarica le chat
""" """
def __init__(self, pipeline: Pipeline): def __init__(self):
self.history: list[dict[str, str]] = [] # [{"role": "user"/"assistant", "content": "..."}] self.history: list[dict[str, str]] = [] # [{"role": "user"/"assistant", "content": "..."}]
self.pipeline = pipeline self.inputs = PipelineInputs()
def send_message(self, message: str) -> None: def send_message(self, message: str) -> None:
""" """
@@ -67,7 +67,11 @@ class ChatManager:
######################################## ########################################
def gradio_respond(self, message: str, history: list[dict[str, str]]) -> tuple[list[dict[str, str]], list[dict[str, str]], str]: def gradio_respond(self, message: str, history: list[dict[str, str]]) -> tuple[list[dict[str, str]], list[dict[str, str]], str]:
self.send_message(message) self.send_message(message)
response = self.pipeline.interact(message)
self.inputs.user_query = message
pipeline = Pipeline(self.inputs)
response = pipeline.interact()
self.receive_message(response) self.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})
@@ -95,18 +99,18 @@ class ChatManager:
# Dropdown provider e stile # Dropdown provider e stile
with gr.Row(): with gr.Row():
provider = gr.Dropdown( provider = gr.Dropdown(
choices=self.pipeline.list_providers(), choices=self.inputs.list_models_names(),
type="index", type="index",
label="Modello da usare" label="Modello da usare"
) )
provider.change(fn=self.pipeline.choose_leader, inputs=provider, outputs=None) provider.change(fn=self.inputs.choose_team_leader, inputs=provider, outputs=None)
style = gr.Dropdown( style = gr.Dropdown(
choices=self.pipeline.list_styles(), choices=self.inputs.list_strategies_names(),
type="index", type="index",
label="Stile di investimento" label="Stile di investimento"
) )
style.change(fn=self.pipeline.choose_strategy, inputs=style, outputs=None) style.change(fn=self.inputs.choose_strategy, 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?")

View File

@@ -9,8 +9,7 @@ from markdown_pdf import MarkdownPdf, Section
from telegram import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message, Update, User from telegram import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message, Update, User
from telegram.constants import ChatAction from telegram.constants import ChatAction
from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes, ConversationHandler, MessageHandler, filters from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes, ConversationHandler, MessageHandler, filters
from app.agents.pipeline import Pipeline from app.agents.pipeline import Pipeline, PipelineInputs
from app.configs import AppConfig
# per per_message di ConversationHandler che rompe sempre qualunque input tu metta # per per_message di ConversationHandler che rompe sempre qualunque input tu metta
warnings.filterwarnings("ignore") warnings.filterwarnings("ignore")
@@ -40,22 +39,12 @@ class ConfigsChat(Enum):
MODEL_OUTPUT = "Output Model" MODEL_OUTPUT = "Output Model"
STRATEGY = "Strategy" STRATEGY = "Strategy"
class ConfigsRun:
def __init__(self, configs: AppConfig):
team, leader, strategy = configs.get_defaults()
self.team_model = team
self.leader_model = leader
self.strategy = strategy
self.user_query = ""
class TelegramApp: class TelegramApp:
def __init__(self, pipeline: Pipeline): def __init__(self):
token = os.getenv("TELEGRAM_BOT_TOKEN") token = os.getenv("TELEGRAM_BOT_TOKEN")
assert token, "TELEGRAM_BOT_TOKEN environment variable not set" assert token, "TELEGRAM_BOT_TOKEN environment variable not set"
self.user_requests: dict[User, ConfigsRun] = {} self.user_requests: dict[User, PipelineInputs] = {}
self.pipeline = pipeline
self.token = token self.token = token
self.create_bot() self.create_bot()
@@ -104,10 +93,10 @@ class TelegramApp:
# Funzioni di utilità # Funzioni di utilità
######################################## ########################################
async def start_message(self, user: User, query: CallbackQuery | Message) -> None: async def start_message(self, user: User, query: CallbackQuery | Message) -> None:
confs = self.user_requests.setdefault(user, ConfigsRun(self.pipeline.configs)) confs = self.user_requests.setdefault(user, PipelineInputs())
str_model_team = f"{ConfigsChat.MODEL_TEAM.value}: {confs.team_model.label}" str_model_team = f"{ConfigsChat.MODEL_TEAM.value}: {confs.team_model.label}"
str_model_output = f"{ConfigsChat.MODEL_OUTPUT.value}: {confs.leader_model.label}" str_model_output = f"{ConfigsChat.MODEL_OUTPUT.value}: {confs.team_leader_model.label}"
str_strategy = f"{ConfigsChat.STRATEGY.value}: {confs.strategy.label}" str_strategy = f"{ConfigsChat.STRATEGY.value}: {confs.strategy.label}"
msg, keyboard = ( msg, keyboard = (
@@ -135,8 +124,8 @@ class TelegramApp:
assert update.message and update.message.from_user, "Update message or user is None" assert update.message and update.message.from_user, "Update message or user is None"
return update.message, update.message.from_user return update.message, update.message.from_user
def callback_data(self, strings: list[str]) -> str: def build_callback_data(self, callback: str, config: ConfigsChat, labels: list[str]) -> list[tuple[str, str]]:
return QUERY_SEP.join(strings) return [(label, QUERY_SEP.join((callback, config.value, str(i)))) for i, label in enumerate(labels)]
async def __error_handler(self, update: object, context: ContextTypes.DEFAULT_TYPE) -> None: async def __error_handler(self, update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
try: try:
@@ -168,18 +157,20 @@ class TelegramApp:
return await self._model_select(update, ConfigsChat.MODEL_OUTPUT) return await self._model_select(update, ConfigsChat.MODEL_OUTPUT)
async def _model_select(self, update: Update, state: ConfigsChat, msg: str | None = None) -> int: async def _model_select(self, update: Update, state: ConfigsChat, msg: str | None = None) -> int:
query, _ = await self.handle_callbackquery(update) query, user = await self.handle_callbackquery(update)
models = [(m.label, self.callback_data([f"__select_config", str(state), m.name])) for m in self.pipeline.configs.models.all_models] req = self.user_requests[user]
models = self.build_callback_data("__select_config", state, req.list_models_names())
inline_btns = [[InlineKeyboardButton(name, callback_data=callback_data)] for name, callback_data in models] inline_btns = [[InlineKeyboardButton(name, callback_data=callback_data)] for name, callback_data in models]
await query.edit_message_text(msg or state.value, reply_markup=InlineKeyboardMarkup(inline_btns)) await query.edit_message_text(msg or state.value, reply_markup=InlineKeyboardMarkup(inline_btns))
return SELECT_CONFIG return SELECT_CONFIG
async def __strategy(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: async def __strategy(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
query, _ = await self.handle_callbackquery(update) query, user = await self.handle_callbackquery(update)
strategies = [(s.label, self.callback_data([f"__select_config", str(ConfigsChat.STRATEGY), s.name])) for s in self.pipeline.configs.strategies] req = self.user_requests[user]
strategies = self.build_callback_data("__select_config", ConfigsChat.STRATEGY, req.list_strategies_names())
inline_btns = [[InlineKeyboardButton(name, callback_data=callback_data)] for name, callback_data in strategies] inline_btns = [[InlineKeyboardButton(name, callback_data=callback_data)] for name, callback_data in strategies]
await query.edit_message_text("Select a strategy", reply_markup=InlineKeyboardMarkup(inline_btns)) await query.edit_message_text("Select a strategy", reply_markup=InlineKeyboardMarkup(inline_btns))
@@ -190,13 +181,13 @@ class TelegramApp:
logging.debug(f"@{user.username} --> {query.data}") logging.debug(f"@{user.username} --> {query.data}")
req = self.user_requests[user] req = self.user_requests[user]
_, state, model_name = str(query.data).split(QUERY_SEP) _, state, index = str(query.data).split(QUERY_SEP)
if state == str(ConfigsChat.MODEL_TEAM): if state == str(ConfigsChat.MODEL_TEAM):
req.team_model = self.pipeline.configs.get_model_by_name(model_name) req.choose_team(int(index))
if state == str(ConfigsChat.MODEL_OUTPUT): if state == str(ConfigsChat.MODEL_OUTPUT):
req.leader_model = self.pipeline.configs.get_model_by_name(model_name) req.choose_team_leader(int(index))
if state == str(ConfigsChat.STRATEGY): if state == str(ConfigsChat.STRATEGY):
req.strategy = self.pipeline.configs.get_strategy_by_name(model_name) req.choose_strategy(int(index))
await self.start_message(user, query) await self.start_message(user, query)
return CONFIGS return CONFIGS
@@ -207,7 +198,7 @@ class TelegramApp:
confs = self.user_requests[user] confs = self.user_requests[user]
confs.user_query = message.text or "" confs.user_query = message.text or ""
logging.info(f"@{user.username} started the team with [{confs.team_model.label}, {confs.leader_model.label}, {confs.strategy.label}]") logging.info(f"@{user.username} started the team with [{confs.team_model.label}, {confs.team_leader_model.label}, {confs.strategy.label}]")
await self.__run_team(update, confs) await self.__run_team(update, confs)
logging.info(f"@{user.username} team finished.") logging.info(f"@{user.username} team finished.")
@@ -221,7 +212,7 @@ class TelegramApp:
await query.edit_message_text("Conversation canceled. Use /start to begin again.") await query.edit_message_text("Conversation canceled. Use /start to begin again.")
return ConversationHandler.END return ConversationHandler.END
async def __run_team(self, update: Update, confs: ConfigsRun) -> None: async def __run_team(self, update: Update, inputs: PipelineInputs) -> None:
if not update.message: return if not update.message: return
bot = update.get_bot() bot = update.get_bot()
@@ -230,10 +221,10 @@ class TelegramApp:
configs_str = [ configs_str = [
'Running with configurations: ', 'Running with configurations: ',
f'Team: {confs.team_model.label}', f'Team: {inputs.team_model.label}',
f'Output: {confs.leader_model.label}', f'Output: {inputs.team_leader_model.label}',
f'Strategy: {confs.strategy.label}', f'Strategy: {inputs.strategy.label}',
f'Query: "{confs.user_query}"' f'Query: "{inputs.user_query}"'
] ]
full_message = f"""```\n{'\n'.join(configs_str)}\n```\n\n""" full_message = f"""```\n{'\n'.join(configs_str)}\n```\n\n"""
first_message = full_message + "Generating report, please wait" first_message = full_message + "Generating report, please wait"
@@ -243,13 +234,10 @@ class TelegramApp:
# Remove user query and bot message # Remove user query and bot message
await bot.delete_message(chat_id=chat_id, message_id=update.message.id) await bot.delete_message(chat_id=chat_id, message_id=update.message.id)
self.pipeline.leader_model = confs.leader_model
self.pipeline.team_model = confs.team_model
self.pipeline.strategy = confs.strategy
# TODO migliorare messaggi di attesa # TODO migliorare messaggi di attesa
await bot.send_chat_action(chat_id=chat_id, action=ChatAction.TYPING) await bot.send_chat_action(chat_id=chat_id, action=ChatAction.TYPING)
report_content = self.pipeline.interact(confs.user_query) pipeline = Pipeline(inputs)
report_content = await pipeline.interact_async()
await msg.delete() await msg.delete()
# attach report file to the message # attach report file to the message