Update telegram interface #44

Merged
Berack96 merged 6 commits from update-telegram-interaction into main 2025-10-27 12:42:14 +01:00
2 changed files with 56 additions and 20 deletions
Showing only changes of commit 49a3c84350 - Show all commits

View File

@@ -133,3 +133,41 @@ class PipelineInputs:
social_tool = SocialAPIsTool() social_tool = SocialAPIsTool()
copilot-pull-request-reviewer[bot] commented 2025-10-23 15:07:19 +02:00 (Migrated from github.com)
Review

Potential IndexError if self.current >= len(steps) after all steps complete. The update() method increments self.current beyond the list bounds when the last step finishes. Add bounds checking: if extra and self.current < len(steps):

        if extra and self.current < len(steps):
Potential IndexError if `self.current >= len(steps)` after all steps complete. The `update()` method increments `self.current` beyond the list bounds when the last step finishes. Add bounds checking: `if extra and self.current < len(steps):` ```suggestion if extra and self.current < len(steps): ```
social_tool.handler.set_retries(api.retry_attempts, api.retry_delay_seconds) social_tool.handler.set_retries(api.retry_attempts, api.retry_delay_seconds)
return market_tool, news_tool, social_tool return market_tool, news_tool, social_tool
def __str__(self) -> str:
return "\n".join([
f"Query Check: {self.query_analyzer_model.label}",
f"Team Leader: {self.team_leader_model.label}",
f"Team: {self.team_model.label}",
f"Report: {self.report_generation_model.label}",
f"Strategy: {self.strategy.label}",
f"User Query: \"{self.user_query}\"",
])
class RunMessage:
def __init__(self, inputs: PipelineInputs, prefix: str = "", suffix: str = ""):
self.base_message = f"Running configurations: \n{prefix}{inputs}{suffix}\n\n"
self.emojis = ['🔳', '➡️', '']
self.placeholder = '<<<>>>'
self.current = 0
self.steps_total = [
(f"{self.placeholder} Query Check", 1),
(f"{self.placeholder} Info Recovery", 0),
(f"{self.placeholder} Report Generation", 0),
]
def update(self) -> 'RunMessage':
text_curr, state_curr = self.steps_total[self.current]
self.steps_total[self.current] = (text_curr, state_curr + 1)
self.current += 1
if self.current < len(self.steps_total):
text_curr, state_curr = self.steps_total[self.current]
self.steps_total[self.current] = (text_curr, state_curr + 1)
return self
def get_latest(self, extra: str = "") -> str:
steps = [msg.replace(self.placeholder, self.emojis[state]) for msg, state in self.steps_total]
if extra:
steps[self.current] = f"{steps[self.current]}: {extra}"
return self.base_message + "\n".join(steps)

View File

@@ -1,3 +1,4 @@
import asyncio
import io import io
import os import os
import json import json
@@ -10,7 +11,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, PipelineInputs from app.agents.pipeline import Pipeline, PipelineEvent, PipelineInputs, RunMessage
# 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")
@@ -233,7 +234,7 @@ class TelegramApp:
async def __select_config(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: async def __select_config(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
query, user = await self.handle_callbackquery(update) query, user = await self.handle_callbackquery(update)
logging.info(f"@{user.username} --> {query.data}") logging.debug(f"@{user.username} --> {query.data}")
copilot-pull-request-reviewer[bot] commented 2025-10-23 15:07:19 +02:00 (Migrated from github.com)
Review

Creating async tasks with asyncio.create_task without awaiting or tracking them can lead to unhandled exceptions and race conditions. The task may fail silently if msg.edit_text raises an exception. Consider using await directly or implementing proper task tracking and error handling.

Creating async tasks with `asyncio.create_task` without awaiting or tracking them can lead to unhandled exceptions and race conditions. The task may fail silently if `msg.edit_text` raises an exception. Consider using `await` directly or implementing proper task tracking and error handling.
copilot-pull-request-reviewer[bot] commented 2025-10-23 15:07:19 +02:00 (Migrated from github.com)
Review

The f-string uses backticks for markdown code formatting, but wraps the entire expression. If e.agent_name or e.tool.tool_name contain special MarkdownV2 characters, they should be escaped. Consider adding proper markdown escaping for user-facing content.

The f-string uses backticks for markdown code formatting, but wraps the entire expression. If `e.agent_name` or `e.tool.tool_name` contain special MarkdownV2 characters, they should be escaped. Consider adding proper markdown escaping for user-facing content.
req = self.user_requests[user] req = self.user_requests[user]
_, state, index = str(query.data).split(QUERY_SEP) _, state, index = str(query.data).split(QUERY_SEP)
@@ -264,36 +265,33 @@ class TelegramApp:
msg_id = update.message.message_id - 1 msg_id = update.message.message_id - 1
chat_id = update.message.chat_id chat_id = update.message.chat_id
configs_str = [ run_message = RunMessage(inputs, prefix="```\n", suffix="\n```")
'Running with configurations: ', msg = await bot.edit_message_text(chat_id=chat_id, message_id=msg_id, text=run_message.get_latest(), parse_mode='MarkdownV2')
f'Check: {inputs.query_analyzer_model.label}',
f'Leader: {inputs.team_leader_model.label}',
f'Team: {inputs.team_model.label}',
f'Report: {inputs.report_generation_model.label}',
f'Strategy: {inputs.strategy.label}',
f'Query: "{inputs.user_query}"'
]
full_message = f"""```\n{'\n'.join(configs_str)}\n```\n\n"""
first_message = full_message + "Generating report, please wait"
msg = await bot.edit_message_text(chat_id=chat_id, message_id=msg_id, text=first_message, parse_mode='MarkdownV2')
if isinstance(msg, bool): return if isinstance(msg, bool): return
# 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)
# TODO migliorare messaggi di attesa def update_user(update: bool = True, extra: str = "") -> None:
if update: run_message.update()
message = run_message.get_latest(extra)
if msg.text != message:
asyncio.create_task(msg.edit_text(message, parse_mode='MarkdownV2'))
await bot.send_chat_action(chat_id=chat_id, action=ChatAction.TYPING) await bot.send_chat_action(chat_id=chat_id, action=ChatAction.TYPING)
pipeline = Pipeline(inputs) pipeline = Pipeline(inputs)
report_content = await pipeline.interact_async() report_content = await pipeline.interact_async(listeners=[
await msg.delete() (PipelineEvent.QUERY_CHECK, lambda _: update_user()),
(PipelineEvent.TOOL_USED, lambda e: update_user(False, f"`{e.agent_name} {e.tool.tool_name}`")),
(PipelineEvent.INFO_RECOVERY, lambda _: update_user()),
(PipelineEvent.REPORT_GENERATION, lambda _: update_user()),
])
# attach report file to the message # attach report file to the message
pdf = MarkdownPdf(toc_level=2, optimize=True) pdf = MarkdownPdf(toc_level=2, optimize=True)
pdf.add_section(Section(report_content, toc=False)) pdf.add_section(Section(report_content, toc=False))
# TODO vedere se ha senso dare il pdf o solo il messaggio
document = io.BytesIO() document = io.BytesIO()
pdf.save_bytes(document) pdf.save_bytes(document)
document.seek(0) document.seek(0)
await bot.send_document(chat_id=chat_id, document=document, filename="report.pdf", parse_mode='MarkdownV2', caption=full_message) await msg.reply_document(document=document, filename="report.pdf")