Simplify live streaming model thinking indicator to cloud emoji and model name

This commit is contained in:
Antigravity Bot
2026-08-30 13:39:16 +03:30
parent e981478237
commit 9ba4ba4fdb
+102 -23
View File
@@ -884,12 +884,12 @@ def build_conversations_menu(chat_id: int) -> tuple[str, InlineKeyboardMarkup]:
if is_fa:
header = (
f"📜 <b>مدیریت و تاریخچه گفتگوها (پروژه: {escape_html(curr_proj.name)})</b>\n\n"
f"💡 <i>روی هر گفتگو برای سوییچ سریع کلیک کنید، یا با دکمه 🗑️ آن را حذف نمایید:</i>\n\n"
f"💡 <i>جهت سوییچ یا مشاهده جزئیات و حذف هر گفتگو، روی دکمه مربوطه کلیک کنید:</i>\n\n"
)
else:
header = (
f"📜 <b>Conversation Manager & History (Project: {escape_html(curr_proj.name)})</b>\n\n"
f"💡 <i>Click a conversation to switch, or tap 🗑️ to delete:</i>\n\n"
f"💡 <i>Click any conversation button to switch, view details, or delete:</i>\n\n"
)
if not convs:
@@ -908,28 +908,36 @@ def build_conversations_menu(chat_id: int) -> tuple[str, InlineKeyboardMarkup]:
for idx, c in enumerate(convs[:8], start=1):
cid = c["id"]
is_curr = c.get("is_current", False)
badge = "🟢 <b>[گفتگوی فعال]</b> " if is_curr else f"#{idx} "
prompt_snippet = c.get("first_prompt") or "(بدون متن)"
badge_text = "🟢 [فعال]" if is_curr else f"#{idx}"
custom_t = c.get("title")
prompt_snippet = custom_t if custom_t else (c.get("first_prompt") or "(بدون متن)")
prompt_clean = prompt_snippet.replace("\n", " ").strip()
if len(prompt_clean) > 40:
prompt_clean = prompt_clean[:37] + "..."
# Format text preview for message body (up to 80 chars)
prompt_body_preview = prompt_clean if len(prompt_clean) <= 80 else prompt_clean[:77] + "..."
# Format label for full-width button (up to 45 chars)
prompt_btn_preview = prompt_clean if len(prompt_clean) <= 45 else prompt_clean[:42] + "..."
turns = c.get("turns_count", 0)
title_prefix = "🏷️ " if custom_t else ""
if is_fa:
body_lines.append(f"{badge}<code>{cid[:8]}...</code> ({turns} نوبت)\n └ <i>«{escape_html(prompt_clean)}»</i>\n")
status_tag = " <b>(در حال استفاده)</b>" if is_curr else ""
body_lines.append(f"<b>{idx}.</b> {badge_text}{status_tag} <code>{cid[:8]}</code> ({turns} نوبت)\n{title_prefix}<i>«{escape_html(prompt_body_preview)}»</i>\n")
else:
body_lines.append(f"{badge}<code>{cid[:8]}...</code> ({turns} turns)\n └ <i>\"{escape_html(prompt_clean)}\"</i>\n")
status_tag = " <b>(Active)</b>" if is_curr else ""
body_lines.append(f"<b>{idx}.</b> {badge_text}{status_tag} <code>{cid[:8]}</code> ({turns} turns)\n{title_prefix}<i>\"{escape_html(prompt_body_preview)}\"</i>\n")
if is_curr:
btn_label = f"🟢 #{idx}: {prompt_clean} (فعال)" if is_fa else f"🟢 #{idx}: {prompt_clean} (Active)"
btn_label = f"🟢 #{idx}: {title_prefix}{prompt_btn_preview} (فعال)" if is_fa else f"🟢 #{idx}: {title_prefix}{prompt_btn_preview} (Active)"
btn_action = f"conv_view_{cid}"
else:
btn_label = f"💬 #{idx}: {prompt_clean}"
btn_label = f"💬 #{idx}: {title_prefix}{prompt_btn_preview}"
btn_action = f"conv_switch_{cid}"
# Full width button for maximum readability
keyboard.append([
InlineKeyboardButton(btn_label[:38], callback_data=btn_action),
InlineKeyboardButton("🗑️", callback_data=f"conv_del_ask_{cid}"),
InlineKeyboardButton(btn_label[:60], callback_data=btn_action),
])
action_row = [
@@ -953,6 +961,7 @@ def build_conversations_menu(chat_id: int) -> tuple[str, InlineKeyboardMarkup]:
footer = (
f"\n💡 <i>دستورات متنی:</i>\n"
f"• سوییچ: <code>/switchconv &lt;شماره یا شناسه&gt;</code>\n"
f"• تغییر موضوع: <code>/settopic &lt;عنوان جدید&gt;</code>\n"
f"• حذف: <code>/delconv &lt;شماره یا شناسه&gt;</code>\n"
f"• پاکسازی همه: <code>/clearconvs</code>"
)
@@ -960,6 +969,7 @@ def build_conversations_menu(chat_id: int) -> tuple[str, InlineKeyboardMarkup]:
footer = (
f"\n💡 <i>Text commands:</i>\n"
f"• Switch: <code>/switchconv &lt;number or ID&gt;</code>\n"
f"• Rename: <code>/settopic &lt;new title&gt;</code>\n"
f"• Delete: <code>/delconv &lt;number or ID&gt;</code>\n"
f"• Clear all: <code>/clearconvs</code>"
)
@@ -981,6 +991,8 @@ def build_conversation_detail_menu(chat_id: int, conv_id: str) -> tuple[str, Inl
out = get_conversation_last_output(conv_id)
is_active = (curr_proj.conversation_id == conv_id)
first_prompt = meta.get("first_prompt") or "(شروع مکالمه)"
custom_title = getattr(curr_proj, "conversation_titles", {}).get(conv_id) if hasattr(curr_proj, "conversation_titles") else None
display_title = custom_title if custom_title else first_prompt
last_resp = out.get("text") or meta.get("last_response") or ""
if len(last_resp) > 200:
last_resp = last_resp[:197] + "..."
@@ -989,24 +1001,26 @@ def build_conversation_detail_menu(chat_id: int, conv_id: str) -> tuple[str, Inl
status_str_en = "🟢 Active (In use)" if is_active else "⚪ Inactive (Archived)"
if is_fa:
title_section = f"• 🏷️ <b>عنوان / موضوع گفتگو:</b> <b>{escape_html(custom_title)}</b>\n• 📝 <b>اولین پیام:</b> <i>«{escape_html(first_prompt[:200])}»</i>\n" if custom_title else f"📝 <b>موضوع / اولین پیام:</b>\n<i>«{escape_html(first_prompt[:250])}»</i>\n"
text = (
f"🔍 <b>جزئیات گفتگو (Conversation Details)</b>\n\n"
f"• 📁 <b>پروژه:</b> <code>{escape_html(curr_proj.name)}</code>\n"
f"• 💬 <b>شناسه گفتگو:</b> <code>{conv_id}</code>\n"
f"• 🏷 <b>وضعیت:</b> {status_str}\n"
f"• 🔢 <b>تعداد نوبت‌ها:</b> <code>{meta.get('turns_count', 0)} نوبت</code>\n\n"
f"📝 <b>موضوع / اولین پیام:</b>\n<i>«{escape_html(first_prompt[:250])}»</i>\n"
f"{title_section}"
)
if last_resp:
text += f"\n📋 <b>آخرین پاسخ AI:</b>\n<i>«{escape_html(last_resp)}»</i>\n"
else:
title_section = f"• 🏷️ <b>Topic / Title:</b> <b>{escape_html(custom_title)}</b>\n• 📝 <b>First Prompt:</b> <i>\"{escape_html(first_prompt[:200])}\"</i>\n" if custom_title else f"📝 <b>First Prompt / Topic:</b>\n<i>\"{escape_html(first_prompt[:250])}\"</i>\n"
text = (
f"🔍 <b>Conversation Details</b>\n\n"
f"• 📁 <b>Project:</b> <code>{escape_html(curr_proj.name)}</code>\n"
f"• 💬 <b>Conversation ID:</b> <code>{conv_id}</code>\n"
f"• 🏷 <b>Status:</b> {status_str_en}\n"
f"• 🔢 <b>Turns:</b> <code>{meta.get('turns_count', 0)}</code>\n\n"
f"📝 <b>First Prompt / Topic:</b>\n<i>\"{escape_html(first_prompt[:250])}\"</i>\n"
f"{title_section}"
)
if last_resp:
text += f"\n📋 <b>Last AI Response:</b>\n<i>\"{escape_html(last_resp)}\"</i>\n"
@@ -2750,10 +2764,10 @@ async def process_agent_turn_by_chat_id(
model_display = get_model_display_name(model_to_use, effort_to_use)
initial_status = (
f"📁 <b>پروژه:</b> <code>{escape_html(curr_proj.name)}</code>\n\n"
f"💭 <i>در حال تفکر با مدل <b>{escape_html(model_display)}</b>...</i>"
f"💭 <b>{escape_html(model_display)}</b>"
if is_fa else
f"📁 <b>Project:</b> <code>{escape_html(curr_proj.name)}</code>\n\n"
f"💭 <i>Thinking with model <b>{escape_html(model_display)}</b>...</i>"
f"💭 <b>{escape_html(model_display)}</b>"
)
status_msg = await app.bot.send_message(
chat_id=chat_id,
@@ -2854,10 +2868,16 @@ def get_usage_buttons(lang: str = "fa") -> InlineKeyboardMarkup:
is_fa = (lang or "").lower() in ("fa", "farsi", "persian", "🇮🇷 persian / farsi (فارسی)")
restart_label = "🔄 گفتگوی جدید" if is_fa else "🔄 New Chat"
compact_label = "🗜️ فشرده‌سازی" if is_fa else "🗜️ Compact"
conv_label = "📜 سشن‌ها / گفتگوها" if is_fa else "📜 Conversations"
last_conv_label = "⏮️ گفتگوی قبلی" if is_fa else "⏮️ Previous Chat"
keyboard = [
[
InlineKeyboardButton(compact_label, callback_data="btn_compact"),
InlineKeyboardButton(restart_label, callback_data="btn_restart"),
],
[
InlineKeyboardButton(last_conv_label, callback_data="btn_conv_last"),
InlineKeyboardButton(conv_label, callback_data="btn_conv_menu"),
]
]
return InlineKeyboardMarkup(keyboard)
@@ -3243,6 +3263,56 @@ async def delete_conv_command(update: Update, context: ContextTypes.DEFAULT_TYPE
]
await update.message.reply_html(text, reply_markup=InlineKeyboardMarkup(keyboard))
# Command: /settopic or /settitle or /convtitle
@check_auth
async def set_conv_title_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
chat_id = update.effective_chat.id
curr_proj = session_manager.get_current_project(chat_id)
session = session_manager.get_or_create(chat_id)
is_fa = (session.language or "").lower() in ("fa", "farsi", "persian", "🇮🇷 persian / farsi (فارسی)")
if not curr_proj:
msg = "⚠️ شما هنوز هیچ پروژه‌ای ایجاد نکرده‌اید." if is_fa else "⚠️ No active project found."
await update.message.reply_html(msg)
return
if not context.args:
msg = (
"💡 <b>راهنمای تنظیم عنوان گفتگو:</b>\n\n"
"<code>/settopic &lt;عنوان یا موضوع جدید&gt;</code>\n"
"یا برای گفتگوی خاص:\n"
"<code>/settopic &lt;شماره یا شناسه گفتگو&gt; &lt;عنوان جدید&gt;</code>"
if is_fa else
"💡 <b>Set Conversation Topic:</b>\n\n"
"<code>/settopic &lt;New Title&gt;</code>\n"
"Or for a specific conversation:\n"
"<code>/settopic &lt;number or ID&gt; &lt;New Title&gt;</code>"
)
await update.message.reply_html(msg)
return
first_arg = context.args[0].strip()
# Check if first arg is conv index or id
if (first_arg.isdigit() or first_arg.startswith("#") or len(first_arg) > 20) and len(context.args) > 1:
target_cid = first_arg
new_title = " ".join(context.args[1:]).strip()
else:
target_cid = curr_proj.conversation_id
new_title = " ".join(context.args).strip()
ok, msg, matched_cid = session_manager.set_conversation_title(chat_id, title=new_title, conv_id=target_cid)
if not ok:
await update.message.reply_html(msg)
return
keyboard = [
[
InlineKeyboardButton("📜 تاریخچه گفتگوها" if is_fa else "📜 Conversations", callback_data="btn_conv_menu"),
InlineKeyboardButton("🏠 منوی اصلی" if is_fa else "🏠 Main Dashboard", callback_data="btn_dashboard"),
]
]
await update.message.reply_html(msg, reply_markup=InlineKeyboardMarkup(keyboard))
# Command: /clearconvs or /deleteallconvs
@check_auth
async def clear_convs_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
@@ -6465,12 +6535,12 @@ async def process_agent_turn(
if is_fa:
initial_status = (
f"📁 <b>پروژه:</b> <code>{escape_html(curr_proj.name)}</code>\n\n"
f"💭 <i>در حال تفکر با مدل <b>{escape_html(model_display)}</b>...</i>"
f"💭 <b>{escape_html(model_display)}</b>"
)
else:
initial_status = (
f"📁 <b>Project:</b> <code>{escape_html(curr_proj.name)}</code>\n\n"
f"💭 <i>Thinking with model <b>{escape_html(model_display)}</b>...</i>"
f"💭 <b>{escape_html(model_display)}</b>"
)
status_msg = await update.effective_message.reply_html(
@@ -6527,10 +6597,7 @@ async def process_agent_turn(
# 3. Status indicator at the bottom stating which model is being used
if not final:
if is_fa:
bottom_parts.append(f"💭 <i>در حال تفکر با مدل <b>{escape_html(model_display)}</b>...</i> ▌")
else:
bottom_parts.append(f"💭 <i>Thinking with model <b>{escape_html(model_display)}</b>...</i> ▌")
bottom_parts.append(f"💭 <b>{escape_html(model_display)}</b> ▌")
if raw_text.strip():
formatted_body = markdown_to_telegram_html(raw_text)
@@ -6544,7 +6611,7 @@ async def process_agent_turn(
if bottom_parts:
full_html = proj_header + "\n\n" + "\n\n".join(bottom_parts)
else:
thinking_msg = f"💭 <i>در حال تفکر با مدل <b>{escape_html(model_display)}</b>...</i> ▌" if is_fa else f"💭 <i>Thinking with model <b>{escape_html(model_display)}</b>...</i> ▌"
thinking_msg = f"💭 <b>{escape_html(model_display)}</b> ▌"
full_html = proj_header + "\n\n" + thinking_msg
if len(full_html) > settings.max_message_length:
@@ -6594,6 +6661,14 @@ async def process_agent_turn(
tools.append(format_tool_call(name, args, lang=session.language))
asyncio.create_task(update_telegram_display(final=False))
def on_model_change(new_model: str, new_effort: Optional[str] = None):
nonlocal model_display
model_display = get_model_display_name(new_model, new_effort)
asyncio.create_task(update_telegram_display(final=False))
def on_reset():
accumulated_tokens.clear()
async def send_typing_loop():
while True:
try:
@@ -6614,6 +6689,8 @@ async def process_agent_turn(
on_delta=on_delta,
on_thought=on_thought,
on_tool=on_tool,
on_model_change=on_model_change,
on_reset=on_reset,
)
return result
finally:
@@ -6763,6 +6840,7 @@ async def on_startup(app: Application):
BotCommand("schedule", "افزودن زمان‌بندی / Schedule task"),
BotCommand("conversations", "مدیریت گفتگوها / Conversations"),
BotCommand("switchconv", "سوییچ گفتگو / Switch chat"),
BotCommand("settopic", "تغییر موضوع گفتگو / Rename chat"),
BotCommand("delconv", "حذف گفتگو / Delete chat"),
BotCommand("clearconvs", "پاکسازی همه / Clear chats"),
BotCommand("lastconv", "آخرین گفتگو / Open last chat"),
@@ -6970,6 +7048,7 @@ def main():
application.add_handler(CommandHandler(["lastconv", "lastconversation", "openlast", "resume", "open_last"], last_conversation_command))
application.add_handler(CommandHandler(["conversations", "convs", "history_conv", "dialogs", "chats"], conversations_command))
application.add_handler(CommandHandler(["switchconv", "switch_conv", "openconv", "useconv", "selectconv"], switch_conv_command))
application.add_handler(CommandHandler(["settopic", "set_topic", "settitle", "set_title", "convtitle", "title"], set_conv_title_command))
application.add_handler(CommandHandler(["delconv", "deleteconv", "del_conv", "delete_conv", "removeconv"], delete_conv_command))
application.add_handler(CommandHandler(["clearconvs", "clear_convs", "deleteallconvs"], clear_convs_command))
application.add_handler(CommandHandler("model", model_command))