Telegram: 3. Buttons with Callback#
This tutorial demonstrates, how to add an inline keyboard and utilize inline queries.
Here, TelegramMessage class is used to represent telegram message, TelegramUI and RemoveKeyboard classes are used for configuring additional telegram message features.
Different message classes are used for representing different common message features, like Attachment, Audio, Button, Image, etc.
[1]:
# installing dependencies
%pip install -q dff[telegram]
Note: you may need to restart the kernel to use updated packages.
[2]:
import os
import dff.script.conditions as cnd
from dff.script import TRANSITIONS, RESPONSE
from dff.pipeline import Pipeline
from dff.script.core.message import Button
from dff.messengers.telegram import (
PollingTelegramInterface,
TelegramUI,
TelegramMessage,
)
from dff.messengers.telegram.message import _ClickButton
from dff.utils.testing.common import is_interactive_mode
If you want to send an inline keyboard to your Telegram chat, set is_inline
field of the TelegramUI
instance to True
(note that it is inline by default, so you could also omit it).
Pushing a button of an inline keyboard results in a callback query being sent to your bot. The data of the query is stored in the callback_query
field of a user TelegramMessage
.
[3]:
script = {
"root": {
"start": {
TRANSITIONS: {
("general", "keyboard"): (
lambda ctx, _: ctx.last_request.text
in ("/start", "/restart")
),
},
},
"fallback": {
RESPONSE: TelegramMessage(
text="Finishing test, send /restart command to restart"
),
TRANSITIONS: {
("general", "keyboard"): (
lambda ctx, _: ctx.last_request.text
in ("/start", "/restart")
)
},
},
},
"general": {
"keyboard": {
RESPONSE: TelegramMessage(
**{
"text": "Starting test! What's 9 + 10?",
"ui": TelegramUI(
buttons=[
Button(text="19", payload="correct"),
Button(text="21", payload="wrong"),
],
is_inline=True,
),
}
),
TRANSITIONS: {
("general", "success"): cnd.exact_match(
TelegramMessage(callback_query="correct")
),
("general", "fail"): cnd.exact_match(
TelegramMessage(callback_query="wrong")
),
},
},
"success": {
RESPONSE: TelegramMessage(text="Success!"),
TRANSITIONS: {("root", "fallback"): cnd.true()},
},
"fail": {
RESPONSE: TelegramMessage(
text="Incorrect answer, type anything to try again"
),
TRANSITIONS: {("general", "keyboard"): cnd.true()},
},
},
}
# this variable is only for testing
happy_path = (
(
TelegramMessage(text="/start"),
TelegramMessage(
text="Starting test! What's 9 + 10?",
ui=TelegramUI(
buttons=[
Button(text="19", payload="correct"),
Button(text="21", payload="wrong"),
],
),
),
),
(
TelegramMessage(callback_query=_ClickButton(button_index=1)),
TelegramMessage(text="Incorrect answer, type anything to try again"),
),
(
TelegramMessage(text="try again"),
TelegramMessage(
text="Starting test! What's 9 + 10?",
ui=TelegramUI(
buttons=[
Button(text="19", payload="correct"),
Button(text="21", payload="wrong"),
],
),
),
),
(
TelegramMessage(callback_query=_ClickButton(button_index=0)),
TelegramMessage(text="Success!"),
),
(
TelegramMessage(text="Yay!"),
TelegramMessage(
text="Finishing test, send /restart command to restart"
),
),
(
TelegramMessage(text="/restart"),
TelegramMessage(
text="Starting test! What's 9 + 10?",
ui=TelegramUI(
buttons=[
Button(text="19", payload="correct"),
Button(text="21", payload="wrong"),
],
),
),
),
)
interface = PollingTelegramInterface(token=os.environ["TG_BOT_TOKEN"])
[4]:
pipeline = Pipeline.from_script(
script=script,
start_label=("root", "start"),
fallback_label=("root", "fallback"),
messenger_interface=interface,
)
def main():
pipeline.run()
if __name__ == "__main__" and is_interactive_mode():
# prevent run during doc building
main()