Aggiunto il supporto per la gestione del bot Telegram e aggiornata la configurazione del pipeline

This commit is contained in:
2025-10-09 01:28:51 +02:00
parent e6e40f96f0
commit 52e9cb2996
3 changed files with 54 additions and 28 deletions

View File

@@ -3,12 +3,17 @@ from dotenv import load_dotenv
from agno.utils.log import log_info #type: ignore
from app.utils import ChatManager
from app.agents import Pipeline
from app.utils.telegram_app import BotFunctions
if __name__ == "__main__":
# Inizializzazioni
load_dotenv()
pipeline = Pipeline()
# Disabilita TUTTI i log di livello inferiore a WARNING
# La maggior parte arrivano da httpx
import logging
logging.getLogger().setLevel(logging.WARNING)
def gradio_app(pipeline: Pipeline, server: str = "0.0.0.0", port: int = 8000) -> str:
chat = ChatManager()
########################################
@@ -73,7 +78,18 @@ if __name__ == "__main__":
save_btn.click(save_current_chat, inputs=None, outputs=None)
load_btn.click(load_previous_chat, inputs=None, outputs=[chatbot, chatbot])
server, port = ("0.0.0.0", 8000) # 0.0.0.0 per accesso esterno (Docker)
server_log = "localhost" if server == "0.0.0.0" else server
log_info(f"Starting UPO AppAI Chat on http://{server_log}:{port}") # noqa
demo.launch(server_name=server, server_port=port, quiet=True)
_app, local, share = demo.launch(server_name=server, server_port=port, quiet=True, prevent_thread_lock=True)
log_info(f"UPO AppAI Chat is running on {local} and {share}")
return share
if __name__ == "__main__":
load_dotenv() # Carica le variabili d'ambiente dal file .env
pipeline = Pipeline()
url = gradio_app(pipeline)
telegram = BotFunctions.create_bot(pipeline, url)
telegram.run_polling()

View File

@@ -1,5 +1,6 @@
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
from app.utils.telegram_app import BotFunctions
__all__ = ["aggregate_history_prices", "aggregate_product_info", "WrapperHandler", "ChatManager"]
__all__ = ["aggregate_history_prices", "aggregate_product_info", "WrapperHandler", "ChatManager", "BotFunctions"]

View File

@@ -1,4 +1,6 @@
import os
import json
import httpx
from enum import Enum
from typing import Any
from agno.utils.log import log_info # type: ignore
@@ -6,6 +8,7 @@ from telegram import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup,
from telegram.constants import ChatAction
from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes, ConversationHandler, ExtBot, JobQueue, MessageHandler, filters
from app.agents import AppModels, PredictorStyle
from app.agents.pipeline import Pipeline
# Lo stato cambia in base al valore di ritorno delle funzioni async
# END state è già definito in telegram.ext.ConversationHandler
@@ -29,9 +32,9 @@ class ConfigsChat(Enum):
class ConfigsRun:
def __init__(self):
self.model_team = BotFunctions.app_models[0]
self.model_output = BotFunctions.app_models[0]
self.strategy = PredictorStyle.CONSERVATIVE
self.model_team = BotFunctions.pipeline.available_models[0]
self.model_output = BotFunctions.pipeline.available_models[0]
self.strategy = BotFunctions.pipeline.all_styles[0]
self.user_query = ""
@@ -39,13 +42,12 @@ class ConfigsRun:
class BotFunctions:
# In theory this is already thread-safe if run with CPython
users_req: dict[User, ConfigsRun] = {}
app_models: list[AppModels] = AppModels.availables()
strategies: list[PredictorStyle] = list(PredictorStyle)
users_req: dict[User, ConfigsRun]
pipeline: Pipeline
# che incubo di typing
@staticmethod
def create_bot() -> Application[ExtBot[None], ContextTypes.DEFAULT_TYPE, dict[str, Any], dict[str, Any], dict[str, Any], JobQueue[ContextTypes.DEFAULT_TYPE]]:
def create_bot(pipeline: Pipeline, miniapp_url: str | None = None) -> Application[ExtBot[None], ContextTypes.DEFAULT_TYPE, dict[str, Any], dict[str, Any], dict[str, Any], JobQueue[ContextTypes.DEFAULT_TYPE]]:
"""
Create a Telegram bot application instance.
Assumes the TELEGRAM_BOT_TOKEN environment variable is set.
@@ -54,10 +56,13 @@ class BotFunctions:
Raises:
AssertionError: If the TELEGRAM_BOT_TOKEN environment variable is not set.
"""
BotFunctions.users_req = {}
BotFunctions.pipeline = pipeline
token = os.getenv("TELEGRAM_BOT_TOKEN", '')
assert token, "TELEGRAM_BOT_TOKEN environment variable not set"
if miniapp_url: BotFunctions.update_miniapp_url(miniapp_url, token)
app = Application.builder().token(token).build()
conv_handler = ConversationHandler(
@@ -113,7 +118,7 @@ class BotFunctions:
async def handle_configs(update: Update, state: ConfigsChat, msg: str | None = None) -> int:
query, _ = await BotFunctions.handle_callbackquery(update)
models = [(m.name, f"__select_config:{state}:{m.name}") for m in BotFunctions.app_models]
models = [(m.name, f"__select_config:{state}:{m.name}") for m in BotFunctions.pipeline.available_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))
@@ -131,6 +136,20 @@ class BotFunctions:
assert update.message and update.message.from_user, "Update message or user is None"
return update.message, update.message.from_user
@staticmethod
def update_miniapp_url(url: str, token: str) -> None:
try:
endpoint = f"https://api.telegram.org/bot{token}/setChatMenuButton"
payload = {"menu_button": json.dumps({
"type": "web_app",
"text": "Apri Mini App", # Il testo che appare sul pulsante
"web_app": {
"url": url
}
})}
httpx.post(endpoint, data=payload)
except httpx.HTTPError as e:
log_info(f"Failed to update mini app URL: {e}")
#########################################
# Funzioni async per i comandi e messaggi
@@ -154,7 +173,7 @@ class BotFunctions:
async def __strategy(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
query, _ = await BotFunctions.handle_callbackquery(update)
strategies = [(s.name, f"__select_config:{ConfigsChat.STRATEGY}:{s.name}") for s in BotFunctions.strategies]
strategies = [(s.name, f"__select_config:{ConfigsChat.STRATEGY}:{s.name}") for s in BotFunctions.pipeline.all_styles]
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))
@@ -238,13 +257,3 @@ class BotFunctions:
document = io.BytesIO(report_content.encode('utf-8'))
await bot.send_document(chat_id=chat_id, document=document, filename="report.md", parse_mode='MarkdownV2', caption=full_message)
if __name__ == "__main__":
from dotenv import load_dotenv
load_dotenv()
bot_app = BotFunctions.create_bot()
bot_app.run_polling()