From 27444d6fa1d38bcafb54441a846ef0a8ec2268ca Mon Sep 17 00:00:00 2001 From: Yi Zhao Date: Fri, 29 Mar 2024 22:45:58 +0800 Subject: [PATCH 1/9] reply immediately and make users feel bots little resposible --- handlers/__init__.py | 27 +++++++++++++++++++-------- handlers/claude.py | 17 +++++++++++++---- handlers/gemini.py | 14 +++++++++++--- handlers/yi.py | 11 +++++++++-- 4 files changed, 52 insertions(+), 17 deletions(-) diff --git a/handlers/__init__.py b/handlers/__init__.py index 237d6e6..383e79d 100644 --- a/handlers/__init__.py +++ b/handlers/__init__.py @@ -21,32 +21,43 @@ T = TypeVar("T", bound=Callable) BOT_MESSAGE_LENGTH = 4000 -def bot_reply_markdown(message: Message, hint: str, text: str, bot: TeleBot) -> None: +def bot_reply_markdown(reply_id: Message, who: str, text: str, bot: TeleBot) -> None: """ reply the Markdown by take care of the message length. it will fallback to plain text in case of any failure """ try: if len(text.encode("utf-8")) <= BOT_MESSAGE_LENGTH: - bot.reply_to( - message, - f"**{hint}**:\n{telegramify_markdown.convert(text)}", - parse_mode="MarkdownV2", + bot.edit_message_text( + f"**{who}**:\n{telegramify_markdown.convert(text)}", + chat_id=reply_id.chat.id, + message_id=reply_id.message_id, + parse_mode="MarkdownV2" ) return # Need a split of message msgs = smart_split(text, BOT_MESSAGE_LENGTH) - for i in range(len(msgs)): + bot.edit_message_text( + f"**{who}** \[1/{len(msgs)}\]:\n{telegramify_markdown.convert(msgs[0])}", + chat_id=reply_id.chat.id, + message_id=reply_id.message_id, + parse_mode="MarkdownV2" + ) + for i in range(1, len(msgs)): bot.reply_to( - message, + reply_id.reply_to_message, f"**{hint}** \[{i+1}/{len(msgs)}\]:\n{telegramify_markdown.convert(msgs[i])}", parse_mode="MarkdownV2", ) except Exception as e: print(traceback.format_exc()) # print(f"wrong markdown format: {text}") - bot.reply_to(message, f"{hint}:\n{text}") + bot.edit_message_text( + f"**{who}**:\n{text}", + chat_id=reply_id.chat.id, + message_id=reply_id.message_id, + ) def extract_prompt(message: str, bot_name: str) -> str: diff --git a/handlers/claude.py b/handlers/claude.py index 315caa6..89b283d 100644 --- a/handlers/claude.py +++ b/handlers/claude.py @@ -37,7 +37,9 @@ def claude_handler(message: Message, bot: TeleBot) -> None: ) else: player_message = claude_player_dict[str(message.from_user.id)] - if m.strip() == "clear": + + q = m.strip() + if q == "clear" or len(q) == 0: bot.reply_to( message, "just clear you claude messages history", @@ -45,6 +47,12 @@ def claude_handler(message: Message, bot: TeleBot) -> None: player_message.clear() return + # show something, make it more responsible + reply_id = bot.reply_to(message, + "**Claude** is __thinking__...", + parse_mode="MarkdownV2" + ) + player_message.append({"role": "user", "content": m}) # keep the last 5, every has two ask and answer. if len(player_message) > 10: @@ -57,7 +65,7 @@ def claude_handler(message: Message, bot: TeleBot) -> None: # tricky player_message.pop() r = client.messages.create( - max_tokens=1024, messages=player_message, model=ANTHROPIC_MODEL + max_tokens=4096, messages=player_message, model=ANTHROPIC_MODEL ) if not r.content: claude_reply_text = "Claude did not answer." @@ -81,7 +89,7 @@ def claude_handler(message: Message, bot: TeleBot) -> None: player_message.clear() return - bot_reply_markdown(message, "Claude answer", claude_reply_text, bot) + bot_reply_markdown(reply_id, "Claude", claude_reply_text, bot) def claude_pro_handler(message: Message, bot: TeleBot) -> None: @@ -94,7 +102,8 @@ def claude_pro_handler(message: Message, bot: TeleBot) -> None: ) else: player_message = claude_pro_player_dict[str(message.from_user.id)] - if m.strip() == "clear": + q = m.strip() + if q == "clear" or len(q) == 0: bot.reply_to( message, "just clear you claude opus messages history", diff --git a/handlers/gemini.py b/handlers/gemini.py index 84dc99c..9c2f03d 100644 --- a/handlers/gemini.py +++ b/handlers/gemini.py @@ -49,13 +49,21 @@ def gemini_handler(message: Message, bot: TeleBot) -> None: gemini_player_dict[str(message.from_user.id)] = player else: player = gemini_player_dict[str(message.from_user.id)] - if m.strip() == "clear": + q = m.strip() + if q == "clear" or len(q) == 0: bot.reply_to( message, "just clear you gemini messages history", ) player.history.clear() return + + # show something, make it more responsible + reply_id = bot.reply_to(message, + "**Gemini** is __thinking__...", + parse_mode="MarkdownV2" + ) + # keep the last 5, every has two ask and answer. if len(player.history) > 10: player.history = player.history[2:] @@ -64,7 +72,7 @@ def gemini_handler(message: Message, bot: TeleBot) -> None: player.send_message(m) gemini_reply_text = player.last.text.strip() # Gemini is often using ':' in **Title** which not work in Telegram Markdown - gemini_reply_text = gemini_reply_text.replace(": **", "**\: ") + gemini_reply_text = gemini_reply_text.replace(":**", "\:**") except StopCandidateException as e: match = re.search(r'content\s*{\s*parts\s*{\s*text:\s*"([^"]+)"', str(e)) if match: @@ -79,7 +87,7 @@ def gemini_handler(message: Message, bot: TeleBot) -> None: return # By default markdown - bot_reply_markdown(message, "Gemini answer", gemini_reply_text, bot) + bot_reply_markdown(reply_id, "Gemini", gemini_reply_text, bot) def gemini_photo_handler(message: Message, bot: TeleBot) -> None: diff --git a/handlers/yi.py b/handlers/yi.py index 6de7164..ccd194c 100644 --- a/handlers/yi.py +++ b/handlers/yi.py @@ -35,7 +35,8 @@ def yi_handler(message: Message, bot: TeleBot) -> None: ) else: player_message = yi_player_dict[str(message.from_user.id)] - if m.strip() == "clear": + q = m.strip() + if q == "clear" or len(q) == 0: bot.reply_to( message, "just clear your yi messages history", @@ -43,6 +44,12 @@ def yi_handler(message: Message, bot: TeleBot) -> None: player_message.clear() return + # show something, make it more responsible + reply_id = bot.reply_to(message, + "**Yi** is __thinking__...", + parse_mode="MarkdownV2" + ) + player_message.append({"role": "user", "content": m}) # keep the last 5, every has two ask and answer. if len(player_message) > 10: @@ -81,7 +88,7 @@ def yi_handler(message: Message, bot: TeleBot) -> None: return # reply back as Markdown and fallback to plain text if failed. - bot_reply_markdown(message, "yi answer", yi_reply_text, bot) + bot_reply_markdown(replay_id, "Yi", yi_reply_text, bot) def _image_to_data_uri(file_path): From 98909312f252c8523b728e6cac7558403e8a83fc Mon Sep 17 00:00:00 2001 From: Yi Zhao Date: Fri, 29 Mar 2024 23:01:34 +0800 Subject: [PATCH 2/9] Update the MarkdownV2 message --- handlers/__init__.py | 8 +++++++- handlers/claude.py | 7 ++----- handlers/gemini.py | 7 ++----- handlers/yi.py | 7 ++----- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/handlers/__init__.py b/handlers/__init__.py index 383e79d..43f0c04 100644 --- a/handlers/__init__.py +++ b/handlers/__init__.py @@ -20,6 +20,12 @@ T = TypeVar("T", bound=Callable) BOT_MESSAGE_LENGTH = 4000 +def bot_reply_first(message: Message, who: str, bot: TeleBot) -> Message: + """ Create the first reply message which make user feel the bot is working. """ + return bot.reply_to(message, + f"**{who}** is __thinking__ \.\.\.", + parse_mode="MarkdownV2" + ) def bot_reply_markdown(reply_id: Message, who: str, text: str, bot: TeleBot) -> None: """ @@ -144,4 +150,4 @@ def list_available_commands() -> list[str]: # `import *` will give you these -__all__ = ["bot_reply_markdown", "extract_prompt"] +__all__ = ["bot_reply_first", "bot_reply_markdown", "extract_prompt"] diff --git a/handlers/claude.py b/handlers/claude.py index 89b283d..85e6e5d 100644 --- a/handlers/claude.py +++ b/handlers/claude.py @@ -6,7 +6,7 @@ from anthropic import Anthropic, APITimeoutError from telebot import TeleBot from telebot.types import Message -from . import bot_reply_markdown +from . import * from telegramify_markdown import convert from telegramify_markdown.customize import markdown_symbol @@ -48,10 +48,7 @@ def claude_handler(message: Message, bot: TeleBot) -> None: return # show something, make it more responsible - reply_id = bot.reply_to(message, - "**Claude** is __thinking__...", - parse_mode="MarkdownV2" - ) + reply_id = bot_reply_first(message, "Claude", bot) player_message.append({"role": "user", "content": m}) # keep the last 5, every has two ask and answer. diff --git a/handlers/gemini.py b/handlers/gemini.py index 9c2f03d..0f1c2ba 100644 --- a/handlers/gemini.py +++ b/handlers/gemini.py @@ -6,7 +6,7 @@ from google.generativeai.types.generation_types import StopCandidateException from telebot import TeleBot from telebot.types import Message -from . import bot_reply_markdown +from . import * GOOGLE_GEMINI_KEY = environ.get("GOOGLE_GEMINI_KEY") @@ -59,10 +59,7 @@ def gemini_handler(message: Message, bot: TeleBot) -> None: return # show something, make it more responsible - reply_id = bot.reply_to(message, - "**Gemini** is __thinking__...", - parse_mode="MarkdownV2" - ) + reply_id = bot_reply_first(message, "Gemini", bot) # keep the last 5, every has two ask and answer. if len(player.history) > 10: diff --git a/handlers/yi.py b/handlers/yi.py index ccd194c..3f3230b 100644 --- a/handlers/yi.py +++ b/handlers/yi.py @@ -7,7 +7,7 @@ import requests from telebot import TeleBot from telebot.types import Message -from . import bot_reply_markdown +from . import * YI_BASE_URL = environ.get("YI_BASE_URL") YI_API_KEY = environ.get("YI_API_KEY") @@ -45,10 +45,7 @@ def yi_handler(message: Message, bot: TeleBot) -> None: return # show something, make it more responsible - reply_id = bot.reply_to(message, - "**Yi** is __thinking__...", - parse_mode="MarkdownV2" - ) + reply_id = bot_reply_first(message, "Yi", bot) player_message.append({"role": "user", "content": m}) # keep the last 5, every has two ask and answer. From 35d6368779fc371ca8c0e52c112ce9372e435c96 Mon Sep 17 00:00:00 2001 From: Yi Zhao Date: Fri, 29 Mar 2024 23:09:28 +0800 Subject: [PATCH 3/9] enlarge context to 8K --- handlers/claude.py | 5 ++--- handlers/gemini.py | 5 ++--- handlers/yi.py | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/handlers/claude.py b/handlers/claude.py index 85e6e5d..ffae8e3 100644 --- a/handlers/claude.py +++ b/handlers/claude.py @@ -38,8 +38,7 @@ def claude_handler(message: Message, bot: TeleBot) -> None: else: player_message = claude_player_dict[str(message.from_user.id)] - q = m.strip() - if q == "clear" or len(q) == 0: + if m.strip() == "clear": bot.reply_to( message, "just clear you claude messages history", @@ -119,7 +118,7 @@ def claude_pro_handler(message: Message, bot: TeleBot) -> None: # tricky player_message.pop() r = client.messages.create( - max_tokens=4096, + max_tokens=8192, messages=player_message, model=ANTHROPIC_PRO_MODEL, stream=True, diff --git a/handlers/gemini.py b/handlers/gemini.py index 0f1c2ba..8a89f2f 100644 --- a/handlers/gemini.py +++ b/handlers/gemini.py @@ -15,7 +15,7 @@ generation_config = { "temperature": 0.7, "top_p": 1, "top_k": 1, - "max_output_tokens": 4096, + "max_output_tokens": 8192, } safety_settings = [ @@ -49,8 +49,7 @@ def gemini_handler(message: Message, bot: TeleBot) -> None: gemini_player_dict[str(message.from_user.id)] = player else: player = gemini_player_dict[str(message.from_user.id)] - q = m.strip() - if q == "clear" or len(q) == 0: + if m.strip() == "clear": bot.reply_to( message, "just clear you gemini messages history", diff --git a/handlers/yi.py b/handlers/yi.py index 3f3230b..b22b570 100644 --- a/handlers/yi.py +++ b/handlers/yi.py @@ -35,8 +35,7 @@ def yi_handler(message: Message, bot: TeleBot) -> None: ) else: player_message = yi_player_dict[str(message.from_user.id)] - q = m.strip() - if q == "clear" or len(q) == 0: + if m.strip() == "clear": bot.reply_to( message, "just clear your yi messages history", From 790bd5551746ca57f183e975f77c147b2492adf9 Mon Sep 17 00:00:00 2001 From: Yi Zhao Date: Fri, 29 Mar 2024 23:24:44 +0800 Subject: [PATCH 4/9] Correct typo --- handlers/__init__.py | 4 ++-- handlers/gemini.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/handlers/__init__.py b/handlers/__init__.py index 43f0c04..df5732d 100644 --- a/handlers/__init__.py +++ b/handlers/__init__.py @@ -23,7 +23,7 @@ BOT_MESSAGE_LENGTH = 4000 def bot_reply_first(message: Message, who: str, bot: TeleBot) -> Message: """ Create the first reply message which make user feel the bot is working. """ return bot.reply_to(message, - f"**{who}** is __thinking__ \.\.\.", + f"**{who}** is *thinking* \.\.\.", parse_mode="MarkdownV2" ) @@ -53,7 +53,7 @@ def bot_reply_markdown(reply_id: Message, who: str, text: str, bot: TeleBot) -> for i in range(1, len(msgs)): bot.reply_to( reply_id.reply_to_message, - f"**{hint}** \[{i+1}/{len(msgs)}\]:\n{telegramify_markdown.convert(msgs[i])}", + f"**{who}** \[{i+1}/{len(msgs)}\]:\n{telegramify_markdown.convert(msgs[i])}", parse_mode="MarkdownV2", ) except Exception as e: diff --git a/handlers/gemini.py b/handlers/gemini.py index 8a89f2f..fd8b722 100644 --- a/handlers/gemini.py +++ b/handlers/gemini.py @@ -69,6 +69,7 @@ def gemini_handler(message: Message, bot: TeleBot) -> None: gemini_reply_text = player.last.text.strip() # Gemini is often using ':' in **Title** which not work in Telegram Markdown gemini_reply_text = gemini_reply_text.replace(":**", "\:**") + gemini_reply_text = gemini_reply_text.replace(": **", "\:** ") except StopCandidateException as e: match = re.search(r'content\s*{\s*parts\s*{\s*text:\s*"([^"]+)"', str(e)) if match: From f68f19e35939d3005ecb58373ff788119562d2eb Mon Sep 17 00:00:00 2001 From: Yi Zhao Date: Fri, 29 Mar 2024 23:28:39 +0800 Subject: [PATCH 5/9] Update the MarketdownV2 message --- handlers/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/handlers/__init__.py b/handlers/__init__.py index df5732d..297ff5c 100644 --- a/handlers/__init__.py +++ b/handlers/__init__.py @@ -23,7 +23,7 @@ BOT_MESSAGE_LENGTH = 4000 def bot_reply_first(message: Message, who: str, bot: TeleBot) -> Message: """ Create the first reply message which make user feel the bot is working. """ return bot.reply_to(message, - f"**{who}** is *thinking* \.\.\.", + f"*{who}* is _thinking_ \.\.\.", parse_mode="MarkdownV2" ) @@ -35,7 +35,7 @@ def bot_reply_markdown(reply_id: Message, who: str, text: str, bot: TeleBot) -> try: if len(text.encode("utf-8")) <= BOT_MESSAGE_LENGTH: bot.edit_message_text( - f"**{who}**:\n{telegramify_markdown.convert(text)}", + f"*{who}*:\n{telegramify_markdown.convert(text)}", chat_id=reply_id.chat.id, message_id=reply_id.message_id, parse_mode="MarkdownV2" @@ -45,7 +45,7 @@ def bot_reply_markdown(reply_id: Message, who: str, text: str, bot: TeleBot) -> # Need a split of message msgs = smart_split(text, BOT_MESSAGE_LENGTH) bot.edit_message_text( - f"**{who}** \[1/{len(msgs)}\]:\n{telegramify_markdown.convert(msgs[0])}", + f"*{who}* \[1/{len(msgs)}\]:\n{telegramify_markdown.convert(msgs[0])}", chat_id=reply_id.chat.id, message_id=reply_id.message_id, parse_mode="MarkdownV2" @@ -53,14 +53,14 @@ def bot_reply_markdown(reply_id: Message, who: str, text: str, bot: TeleBot) -> for i in range(1, len(msgs)): bot.reply_to( reply_id.reply_to_message, - f"**{who}** \[{i+1}/{len(msgs)}\]:\n{telegramify_markdown.convert(msgs[i])}", + f"*{who}* \[{i+1}/{len(msgs)}\]:\n{telegramify_markdown.convert(msgs[i])}", parse_mode="MarkdownV2", ) except Exception as e: print(traceback.format_exc()) # print(f"wrong markdown format: {text}") bot.edit_message_text( - f"**{who}**:\n{text}", + f"*{who}*:\n{text}", chat_id=reply_id.chat.id, message_id=reply_id.message_id, ) @@ -150,4 +150,4 @@ def list_available_commands() -> list[str]: # `import *` will give you these -__all__ = ["bot_reply_first", "bot_reply_markdown", "extract_prompt"] +__all__ = ["bot_reply_first", "bot_reply_markdown"] From ffccd1d116838c3e0b72cdd0b43de6bef304bf68 Mon Sep 17 00:00:00 2001 From: Yi Zhao Date: Fri, 29 Mar 2024 23:33:41 +0800 Subject: [PATCH 6/9] Update the full-angle character --- handlers/gemini.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/gemini.py b/handlers/gemini.py index fd8b722..888a896 100644 --- a/handlers/gemini.py +++ b/handlers/gemini.py @@ -69,7 +69,7 @@ def gemini_handler(message: Message, bot: TeleBot) -> None: gemini_reply_text = player.last.text.strip() # Gemini is often using ':' in **Title** which not work in Telegram Markdown gemini_reply_text = gemini_reply_text.replace(":**", "\:**") - gemini_reply_text = gemini_reply_text.replace(": **", "\:** ") + gemini_reply_text = gemini_reply_text.replace(":**", "\:**") except StopCandidateException as e: match = re.search(r'content\s*{\s*parts\s*{\s*text:\s*"([^"]+)"', str(e)) if match: From da079d795dbd849c6a40a7b1422385e2f066e389 Mon Sep 17 00:00:00 2001 From: Yi Zhao Date: Fri, 29 Mar 2024 23:36:01 +0800 Subject: [PATCH 7/9] hack the Gemini markdown formst --- handlers/gemini.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/gemini.py b/handlers/gemini.py index 888a896..d985b3e 100644 --- a/handlers/gemini.py +++ b/handlers/gemini.py @@ -69,7 +69,7 @@ def gemini_handler(message: Message, bot: TeleBot) -> None: gemini_reply_text = player.last.text.strip() # Gemini is often using ':' in **Title** which not work in Telegram Markdown gemini_reply_text = gemini_reply_text.replace(":**", "\:**") - gemini_reply_text = gemini_reply_text.replace(":**", "\:**") + gemini_reply_text = gemini_reply_text.replace(":**", "**") except StopCandidateException as e: match = re.search(r'content\s*{\s*parts\s*{\s*text:\s*"([^"]+)"', str(e)) if match: From 4a40cf7695c64f0ef43ae695cb868ff461d4ffb7 Mon Sep 17 00:00:00 2001 From: Yi Zhao Date: Fri, 29 Mar 2024 23:42:54 +0800 Subject: [PATCH 8/9] hack the Gemini markdown formst 2 --- handlers/gemini.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/gemini.py b/handlers/gemini.py index d985b3e..ee1891c 100644 --- a/handlers/gemini.py +++ b/handlers/gemini.py @@ -69,7 +69,7 @@ def gemini_handler(message: Message, bot: TeleBot) -> None: gemini_reply_text = player.last.text.strip() # Gemini is often using ':' in **Title** which not work in Telegram Markdown gemini_reply_text = gemini_reply_text.replace(":**", "\:**") - gemini_reply_text = gemini_reply_text.replace(":**", "**") + gemini_reply_text = gemini_reply_text.replace(":**", "**\: ") except StopCandidateException as e: match = re.search(r'content\s*{\s*parts\s*{\s*text:\s*"([^"]+)"', str(e)) if match: From 14b075491e7a29b89cbc62f28e2276eb0d768c7d Mon Sep 17 00:00:00 2001 From: "Y1.Zhao" Date: Fri, 29 Mar 2024 11:57:33 -0400 Subject: [PATCH 9/9] use black to format the code --- handlers/__init__.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/handlers/__init__.py b/handlers/__init__.py index 297ff5c..7135bba 100644 --- a/handlers/__init__.py +++ b/handlers/__init__.py @@ -20,13 +20,14 @@ T = TypeVar("T", bound=Callable) BOT_MESSAGE_LENGTH = 4000 + def bot_reply_first(message: Message, who: str, bot: TeleBot) -> Message: - """ Create the first reply message which make user feel the bot is working. """ - return bot.reply_to(message, - f"*{who}* is _thinking_ \.\.\.", - parse_mode="MarkdownV2" + """Create the first reply message which make user feel the bot is working.""" + return bot.reply_to( + message, f"*{who}* is _thinking_ \.\.\.", parse_mode="MarkdownV2" ) + def bot_reply_markdown(reply_id: Message, who: str, text: str, bot: TeleBot) -> None: """ reply the Markdown by take care of the message length. @@ -38,7 +39,7 @@ def bot_reply_markdown(reply_id: Message, who: str, text: str, bot: TeleBot) -> f"*{who}*:\n{telegramify_markdown.convert(text)}", chat_id=reply_id.chat.id, message_id=reply_id.message_id, - parse_mode="MarkdownV2" + parse_mode="MarkdownV2", ) return @@ -48,7 +49,7 @@ def bot_reply_markdown(reply_id: Message, who: str, text: str, bot: TeleBot) -> f"*{who}* \[1/{len(msgs)}\]:\n{telegramify_markdown.convert(msgs[0])}", chat_id=reply_id.chat.id, message_id=reply_id.message_id, - parse_mode="MarkdownV2" + parse_mode="MarkdownV2", ) for i in range(1, len(msgs)): bot.reply_to(