Skip to content

Commit c41abc8

Browse files
committed
chore: add examples for telegram plugin
1 parent 7fd3c83 commit c41abc8

File tree

2 files changed

+221
-0
lines changed

2 files changed

+221
-0
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import os
2+
from typing import TypedDict
3+
import logging
4+
5+
from telegram import Update
6+
from telegram.ext import ContextTypes, filters, MessageHandler
7+
8+
from game_sdk.game.chat_agent import Chat, ChatAgent
9+
from telegram_plugin_gamesdk.telegram_plugin import TelegramPlugin
10+
from test_telegram_game_functions import send_message_fn, send_media_fn, create_poll_fn, pin_message_fn, unpin_message_fn, delete_message_fn
11+
12+
game_api_key = os.environ.get("GAME_API_KEY")
13+
telegram_bot_token = os.environ.get("TELEGRAM_BOT_TOKEN")
14+
15+
logging.basicConfig(
16+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
17+
level=logging.INFO,
18+
)
19+
20+
logger = logging.getLogger(__name__)
21+
22+
class ActiveUser(TypedDict):
23+
chat_id: int
24+
name: str
25+
26+
chat_agent = ChatAgent(
27+
prompt="You are a helpful assistant.",
28+
api_key=game_api_key,
29+
)
30+
31+
active_users: list[ActiveUser] = []
32+
active_chats: dict[int, Chat] = {}
33+
34+
if __name__ == "__main__":
35+
tg_plugin = TelegramPlugin(bot_token=telegram_bot_token)
36+
37+
agent_action_space = [
38+
send_message_fn(tg_plugin),
39+
send_media_fn(tg_plugin),
40+
create_poll_fn(tg_plugin),
41+
pin_message_fn(tg_plugin),
42+
unpin_message_fn(tg_plugin),
43+
delete_message_fn(tg_plugin),
44+
]
45+
46+
async def default_message_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
47+
"""Handles incoming messages but ignores messages from the bot itself unless it's mentioned in a group chat."""
48+
49+
# Ignore messages from the bot itself
50+
if update.message.from_user.id == tg_plugin.bot.id:
51+
logger.info("Ignoring bot's own message.")
52+
return
53+
54+
user = update.message.from_user
55+
chat_id = update.message.chat.id
56+
chat_type = update.message.chat.type # "private", "group", "supergroup", or "channel"
57+
bot_username = f"@{tg_plugin.bot.username}"
58+
59+
logger.info(f"Update received: {update}")
60+
logger.info(f"Message received: {update.message.text}")
61+
62+
name = f"{user.first_name} (Telegram's chat_id: {chat_id}, this is not part of the partner's name but important for the telegram's function arguments)"
63+
64+
# Ignore group/supergroup messages unless the bot is mentioned
65+
if chat_type in ["group", "supergroup"] and bot_username not in update.message.text:
66+
logger.info(f"Ignoring group message not mentioning the bot: {update.message.text}")
67+
return
68+
69+
if not any(u["chat_id"] == chat_id for u in active_users):
70+
active_users.append({"chat_id": chat_id, "name": name})
71+
logger.info(f"Active user added: {name}")
72+
logger.info(f"Active users: {active_users}")
73+
chat = chat_agent.create_chat(
74+
partner_id=str(chat_id),
75+
partner_name=name,
76+
action_space=agent_action_space,
77+
)
78+
active_chats[chat_id] = chat
79+
80+
response = active_chats[chat_id].next(update.message.text.replace(bot_username, "").strip()) # Remove bot mention
81+
logger.info(f"Response: {response}")
82+
83+
if response.message:
84+
await update.message.reply_text(response.message)
85+
86+
if response.is_finished:
87+
active_chats.pop(chat_id)
88+
active_users.remove({"chat_id": chat_id, "name": name})
89+
logger.info(f"Chat with {name} ended.")
90+
logger.info(f"Active users: {active_users}")
91+
92+
tg_plugin.add_handler(MessageHandler(filters.ALL, default_message_handler))
93+
94+
# Start polling
95+
tg_plugin.start_polling()
96+
97+
# Example of executing a function from Telegram Plugin to a chat without polling
98+
#tg_plugin.send_message(chat_id=829856292, text="Hello! I am a helpful assistant. How can I assist you today?")
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import os
2+
import sys
3+
from typing import Tuple
4+
5+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))
6+
sys.path.append(project_root)
7+
8+
from plugins.telegram.telegram_plugin_gamesdk.telegram_plugin import TelegramPlugin
9+
from src.game_sdk.game.custom_types import Function, FunctionResultStatus, Argument
10+
11+
12+
def send_message_executable(tg_plugin: TelegramPlugin, chat_id: str, text: str) -> Tuple[FunctionResultStatus, str, dict]:
13+
try:
14+
tg_plugin.send_message(chat_id=chat_id, text=text)
15+
return FunctionResultStatus.DONE, "Message sent successfully", {}
16+
except Exception as e:
17+
return FunctionResultStatus.FAILED, str(e), {}
18+
19+
def send_message_fn(bot: TelegramPlugin) -> Function:
20+
return Function(
21+
fn_name="send_message",
22+
fn_description="Send a text message to a Telegram chat",
23+
args=[
24+
Argument(name="chat_id", description="ID of the chat to send the message to", type="str"),
25+
Argument(name="text", description="Text message to send", type="str"),
26+
],
27+
executable=lambda chat_id, text: send_message_executable(bot, chat_id, text),
28+
)
29+
30+
def send_media_executable(tg_plugin: TelegramPlugin, chat_id: str, media_type: str, media: str, caption: str = None) -> Tuple[FunctionResultStatus, str, dict]:
31+
try:
32+
tg_plugin.send_media(chat_id=chat_id, media_type=media_type, media=media, caption=caption)
33+
return FunctionResultStatus.DONE, "Media sent successfully", {}
34+
except Exception as e:
35+
return FunctionResultStatus.FAILED, str(e), {}
36+
37+
def send_media_fn(bot: TelegramPlugin) -> Function:
38+
return Function(
39+
fn_name="send_media",
40+
fn_description="Send a media message to a Telegram chat",
41+
args=[
42+
Argument(name="chat_id", description="ID of the chat to send the message to", type="str"),
43+
Argument(name="media_type", description="Type of media to send (photo, document, video, audio)", type="str"),
44+
Argument(name="media", description="Media URL or file path to send", type="str"),
45+
Argument(name="caption", description="Optional caption for the media", type="str", optional=True),
46+
],
47+
executable=lambda chat_id, media_type, media, caption=None: send_media_executable(bot, chat_id, media_type, media, caption),
48+
)
49+
50+
def create_poll_executable(tg_plugin: TelegramPlugin, chat_id: str, question: str, options: list[str], is_anonymous: bool = True, allows_multiple_answers: bool = False) -> Tuple[FunctionResultStatus, str, dict]:
51+
try:
52+
tg_plugin.create_poll(chat_id=chat_id, question=question, options=options, is_anonymous=is_anonymous, allows_multiple_answers=allows_multiple_answers)
53+
return FunctionResultStatus.DONE, "Poll created successfully", {}
54+
except Exception as e:
55+
return FunctionResultStatus.FAILED, str(e), {}
56+
57+
def create_poll_fn(bot: TelegramPlugin) -> Function:
58+
return Function(
59+
fn_name="create_poll",
60+
fn_description="Create a poll in a Telegram chat",
61+
args=[
62+
Argument(name="chat_id", description="ID of the chat to create the poll in", type="str"),
63+
Argument(name="question", description="Question to ask in the poll", type="str"),
64+
Argument(name="options", description="List of options for the poll", type="List[str]"),
65+
Argument(name="is_anonymous", description="Whether the poll is anonymous (default: True)", type="bool", optional=True),
66+
Argument(name="allows_multiple_answers", description="Whether multiple answers are allowed (default: False)", type="bool", optional=True),
67+
],
68+
executable=lambda chat_id, question, options, is_anonymous=False, allows_multiple_answers=False: create_poll_executable(bot, chat_id, question, options, is_anonymous, allows_multiple_answers),
69+
)
70+
71+
def pin_message_executable(tg_plugin: TelegramPlugin, chat_id: str, message_id: int) -> Tuple[FunctionResultStatus, str, dict]:
72+
try:
73+
tg_plugin.pin_message(chat_id=chat_id, message_id=message_id)
74+
return FunctionResultStatus.DONE, "Message pinned successfully", {}
75+
except Exception as e:
76+
return FunctionResultStatus.FAILED, str(e), {}
77+
78+
def pin_message_fn(bot: TelegramPlugin) -> Function:
79+
return Function(
80+
fn_name="pin_message",
81+
fn_description="Pin a message in a Telegram chat",
82+
args=[
83+
Argument(name="chat_id", description="ID of the chat to pin the message in", type="str"),
84+
Argument(name="message_id", description="ID of the message to pin", type="int"),
85+
],
86+
executable=lambda chat_id, message_id: pin_message_executable(bot, chat_id, message_id),
87+
)
88+
89+
def unpin_message_executable(tg_plugin: TelegramPlugin, chat_id: str, message_id: int) -> Tuple[FunctionResultStatus, str, dict]:
90+
try:
91+
tg_plugin.unpin_message(chat_id=chat_id, message_id=message_id)
92+
return FunctionResultStatus.DONE, "Message unpinned successfully", {}
93+
except Exception as e:
94+
return FunctionResultStatus.FAILED, str(e), {}
95+
96+
def unpin_message_fn(bot: TelegramPlugin) -> Function:
97+
return Function(
98+
fn_name="unpin_message",
99+
fn_description="Unpin a message in a Telegram chat",
100+
args=[
101+
Argument(name="chat_id", description="ID of the chat to unpin the message in", type="str"),
102+
Argument(name="message_id", description="ID of the message to unpin", type="int"),
103+
],
104+
executable=lambda chat_id, message_id: unpin_message_executable(bot, chat_id, message_id),
105+
)
106+
107+
def delete_message_executable(tg_plugin: TelegramPlugin, chat_id: str, message_id: int) -> Tuple[FunctionResultStatus, str, dict]:
108+
try:
109+
tg_plugin.delete_message(chat_id=chat_id, message_id=message_id)
110+
return FunctionResultStatus.DONE, "Message deleted successfully", {}
111+
except Exception as e:
112+
return FunctionResultStatus.FAILED, str(e), {}
113+
114+
def delete_message_fn(bot: TelegramPlugin) -> Function:
115+
return Function(
116+
fn_name="delete_message",
117+
fn_description="Delete a message in a Telegram chat",
118+
args=[
119+
Argument(name="chat_id", description="ID of the chat to delete the message in", type="str"),
120+
Argument(name="message_id", description="ID of the message to delete", type="int"),
121+
],
122+
executable=lambda chat_id, message_id: delete_message_executable(bot, chat_id, message_id),
123+
)

0 commit comments

Comments
 (0)