Simplify live streaming model thinking indicator to cloud emoji and model name
This commit is contained in:
+102
-23
@@ -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 <شماره یا شناسه></code>\n"
|
||||
f"• تغییر موضوع: <code>/settopic <عنوان جدید></code>\n"
|
||||
f"• حذف: <code>/delconv <شماره یا شناسه></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 <number or ID></code>\n"
|
||||
f"• Rename: <code>/settopic <new title></code>\n"
|
||||
f"• Delete: <code>/delconv <number or ID></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 <عنوان یا موضوع جدید></code>\n"
|
||||
"یا برای گفتگوی خاص:\n"
|
||||
"<code>/settopic <شماره یا شناسه گفتگو> <عنوان جدید></code>"
|
||||
if is_fa else
|
||||
"💡 <b>Set Conversation Topic:</b>\n\n"
|
||||
"<code>/settopic <New Title></code>\n"
|
||||
"Or for a specific conversation:\n"
|
||||
"<code>/settopic <number or ID> <New Title></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))
|
||||
|
||||
Reference in New Issue
Block a user