Telebot: how to retrieve InlineKeyboardButton callback data? - python

I am buidling a simple game with pytelegrambotapi.
According to the rules, the user is sent a definition and four buttons with words as text, of which one is correct.
The user then should press the right button. Another routine then compares the user's answer to the right answer.
How do I retrieve the value of the button that the user pressed?
import telebot
from telebot import types
TOKEN = 'XXXXXXXXXXXXXXXXX'
bot = telebot.TeleBot(TOKEN)
kb = types.InlineKeyboardMarkup(row_width=2)
words = {
'Meager' : 'Lacking in quantity',
'Asylum' : 'Shelter',
'Irk' : 'To annoy',
'Kudos' : 'Great glory'
}
def compare(message, word, definition):
if definition == words[word]:
bot.send_message(message.from_user.id, 'Correct!')
else:
bot.send_message(message.from_user.id, 'Wrong!')
for item in words.items():
kb.add(types.InlineKeyboardButton(item[0], callback_data = item[0]))
#bot.message_handler(commands=['start', 's'])
def post_random_article(message):
word = 'Meager'
bot.send_message(message.from_user.id, word, reply_markup = kb)
bot.polling()

Nevermind, I found an answer.
#bot.callback_query_handler(func=lambda call: True)
def handle_query(call):
if call.data.split('#')[0] == call.data.split('#')[1]:
bot.send_message(call.message.chat.id, '✅ Correct!')
else:
bot.send_message(call.message.chat.id, '❌ Wrong!\n♻️ The answer is: %s' % call.data.split('#')[1])
#bot.message_handler(commands=['game', 'g'])
def game(message):
list_of_words = load_my_dictionary(message.from_user.id)
random.shuffle(list_of_words)
while not len(list_of_words) < 4:
current = list_of_words.pop()
word = current[0]
definition = current[1]
all_answers = generate_answers(word, list_of_words)
keyboard = generate_keyboard(all_answers, word)
bot.send_message(message.from_user.id, definition, reply_markup = keyboard)
time.sleep(7)
bot.send_message(message.from_user.id, '📭 List is empty!')

Related

Telegram bot written using Telebot stucks when is used by 2+ people

I wrote a simple TicTacToe game: user sends cell's index and bot places character('X' or 'O') into that cell and plays back. It works fine as long as it's being used by one person. However, when a few are concurrently playing, bot refuses to process requests and sometimes sends the similar board(which I store in dict for each player individually)
I think that I messed up with async function 'MakeMove'. I haven't used python much and a bit of advise would be highly appreciated. Thank you!
import telebot
import asyncio
#Consists of objects of class Player
players = {}
class Player:
def __init__(self, userName):
self.userName = userName
self.winsAmount = 0
self.loses = 0
self.pickedChar = 'X'
self.isGameRunning = False
self.isTurn = True
self.currentBoard = Board(self.pickedChar)
...
#bot.message_handler(commands=['game'])
def StartGame(message):
chatId = message.chat.id
if chatId not in players:
players[chatId] = Player(message.from_user.username)
if not isGameRunning(chatId):
player = players[chatId]
player.isGameRunning = True
bot.send_message(chatId, f'Hello, *{player.userName}*!\nYour wins amount is _{player.winsAmount}_\nYou\'ve lost _{player.loses}_ times', parse_mode='Markdown')
keyboard = telebot.types.InlineKeyboardMarkup()
keyboard.row(telebot.types.InlineKeyboardButton('X', callback_data='charX'),
telebot.types.InlineKeyboardButton('O', callback_data='charO'))
bot.send_message(chatId, 'Choose your side: X | O', reply_markup=keyboard)
else:
keyboard = telebot.types.InlineKeyboardMarkup()
keyboard.row(telebot.types.InlineKeyboardButton('End the current game', callback_data='endGame'))
bot.send_message(chatId, 'The game is still running!', reply_markup=keyboard)
#bot.message_handler(content_types=['text'])
def HandleMoves(message):
player = players[message.chat.id]
board = player.currentBoard
for i in range(9):
if message.text == (str)(i + 1) and player.isGameRunning and player.isTurn:
if board.desk[i] == '_':
board.desk[i] = board.playerChar
player.isTurn = False
else:
bot.send_message(message.chat.id, 'The cell is already occupied')
.........................................................
# I suppouse these two functions cause the problem
async def CheckForTurn(chatId):
while True:
if not players[chatId].isTurn:
return
await asyncio.sleep(0.2)
async def MakeMove(chatId):
board = players[chatId].currentBoard
player = players[chatId]
while True:
DrawBoard(chatId)
if board.GetState() != States.IN_GAME:
EndGame(chatId, board.GetState())
break
if player.isTurn:
bot.send_message(chatId, 'Make a move (from 1 to 9)')
await CheckForTurn(chatId)
if not player.isTurn:
index = GetBestMove(board)
char = ' '
if player.pickedChar == 'O':
char = 'X'
else:
char = 'O'
board.desk[index] = char
player.isTurn = True

How to get message updates from the user after the bot message telegram bot

So I'm new at making a telegram bot, I want to have like the botfather:
user: create bot
bot: provide name for your bot
user: foo bot
then the user text is used in the future.
I have a simple sample bot which defines a word that the user provide
user:/define internet
bot: defines the term
but I want to recreate it to
user:/define
bot: please send the word you want to define
user: internet
bot: defines the term
user: ....
I'm using pyTelegramBotAPI
Here is my code
#bot.message_handler(commands=['define'])
def dictionary(message):
user_message = message.text
msg = user_message.split(' ')
if len(msg) != 1:
try:
word = msg[1]
botmsg = bot.send_message(message.chat.id, 'Finding the word in the dictionary')
resp = requests.get(DICT_URL + word)
respData = resp.json()
pof = respData[0]['meanings'][0]['partOfSpeech']
print(pof)
defi = respData[0]['meanings'][0]['definitions'][0]['definition']
print(defi)
bot.send_message(message.chat.id, text=f'*Word:* {word} \n\n *Part Of Speech: *{pof} \n\n *Definition: *{defi}', parse_mode='Markdown')
bot.delete_message(message.chat.id, botmsg.message_id)
except:
bot.send_message(message.chat.id, "Couldn't find in the dictionary.")
else:
bot.send_message(message.chat.id, 'Please input a word to define.')
I've found the answer thanks to #furas who helped with his comments
incase someone has the same problem with me here's the code.
#bot.message_handler(commands=['define'])
def send_welcome(message):
msg = bot.reply_to(message, "What word you want to define?")
bot.register_next_step_handler(msg, define)
def define(message):
chat_id = message.chat.id
word = message.text
bot.send_message(chat_id, f'the word you want to define is {word}')
bot.enable_save_next_step_handlers(delay=2)
bot.load_next_step_handlers()
bot.infinity_polling()

How to check if user press the reply keyboard button? telegram bot python

Easy task, but I can't figure out how to do it.
I'd like to check if user press the button 'Add variants' to add next messages from user to list variants. I tried to do it using if message.text == 'Add variants', but it just adds to the
list text 'Add variants' one time and that's it. Is there any way to check if user click the button and after that add next messages from user to list?
variants = []
#bot.message_handler(commands=['start', 'welcome'])
def start(message):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
item_1 = types.KeyboardButton('Random🎲')
item_2 = types.KeyboardButton('TradingView💸')
item_3 = types.KeyboardButton('Weather🌤')
item_4 = types.KeyboardButton('Other')
item_5 = types.KeyboardButton('Back🔙')
markup.add(item_1, item_2, item_3, item_4, item_5)
bot.send_message(message.chat.id, 'Choose', reply_markup = markup)
#bot.message_handler(content_types=['text'])
def bot_message(message):
if message.chat.type == 'private':
if message.text == 'Random🎲':
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
item_1 = types.KeyboardButton('Add variants')
item_2 = types.KeyboardButton('Back🔙')
markup.add(item_1, item_2)
bot.send_message(message.chat.id, 'Choose', reply_markup = markup)
In this part of code you dont add anything to 'variants'. But as I understood: after user clicks 'Add variants' button you want to handle new message from user and add this message to a 'variants'. If so you need to register next_step_handler after you handeled 'Add variants' message.
Like that:
variants = []
#bot.message_handler(content_types=['text'])
def bot_message(message):
if message.chat.type == 'private':
if message.text == 'Add variants':
msg = bot.send_message(message.chat.id, "Send me variant")
bot.register_next_step_handler(msg, handling_variant)
def handling_variant(message):
variants.append(message.text)
here is example of using next_step_handler

Repeat action on button click in telebot module

I'm implementing a simple function in Python, but it doesn't work
Function:
# Рандомное число с кнопкой
#bot.message_handler(content_types=['text'], commands=['get_number'])
def get_number(message):
number = random.randint(0, 1000)
markup = types.InlineKeyboardMarkup()
item_yes = types.InlineKeyboardButton('Да', callback_data='yes')
item_no = types.InlineKeyboardButton('Нет', callback_data='no')
markup.row(item_yes, item_no)
bot.send_message(message.chat.id, f"<i><b>Ваше число:</b></i>\n{number}\n\nЗагадать еще раз?", reply_markup=markup,
parse_mode='html')
# Реакция на нажатие кнопки
#bot.callback_query_handler(func=lambda call: True)
def answer(call, message):
if call.data == 'yes':
pass
elif call.data == 'no':
pass
Tell me how to make it so that when you click the "Yes" button, the function is executed when you click it again, when you click "No", it stops accordingly.
I believe you can change your method:
def answer(call, message):
for
def handle_query(call):

telegram bot conversation handler state not reached

def final_or_make_changes_to_bill(bot, update):
user_choice_make_changes = update.message.text
if user_choice_make_changes == "Yes":
reply_keyboard = [["Add","Delete"]]
message = "Do you want to add or delete?"
bot.send_message(chat_id=update.message.chat_id, text=message, reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
return ADD_OR_DELETE
return STOP
For some reason the state STOP in my code is never reached. I tried other states and none of them are reached. I tried replacing the return statement in the if condition to STOP to check if there was a problem with the state. But it seems to work fine and the state is reached through the if statement block.
This is the function for the STOP state.
def stop(bot, update):
print("ht")
bot.send_message(chat_id=update.message.chat_id,text="dsfdsfsadf")
return ConversationHandler.END
Here's the entire code.
import os
import logging
from DBHelper import DBHelper
from telegram.ext import Updater,CommandHandler,MessageHandler,ConversationHandler,Filters
from telegram import ReplyKeyboardMarkup
from random import randint
TOKEN = ""
db = DBHelper()
ADD_ITEMS, FINAL_OR_MAKE_CHANGES, ADD_OR_DELETE, DELETE, STOP = range(5)
bill_items = []
ID = None
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
def start(bot, update):
message = "Welcome to the Bill Splitter Bot. An easy way to split bills among friends. The following are a list of"
+ "commands you can use."
bot.send_message(chat_id=update.message.chat_id, text=message)
message = ""
message += "/help - To get a list of commands\n"
message += "/create - To create a new bill\n"
message += "/add - To add items spent on for a particular bill"
message += "/get - To get the amount owed"
def create(bot, update):
global ID
message = "Hey! Looks like you're trying to create a new bill! One moment, while I create a new ID for you!"
bot.send_message(chat_id=update.message.chat_id, text=message)
id_for_bill = randint(1000,9999)
# Check if bill id does not exist in database
message = "Here's the ID for your bill: " + str(id_for_bill)
ID = id_for_bill
print(ID)
bot.send_message(chat_id=update.message.chat_id, text=message)
message = "Can you enter the items followed by the price for the bill? A simple format would look as follows. Type "
message += "Done when you're done adding items to the bill\n"
bot.send_message(chat_id=update.message.chat_id, text=message)
message = " <pre>Pizza - 150\n"
message += "Pasta - 150\n"
message += "Garlic Bread - 230</pre> "
reply_keyboard = [["Done"]]
bot.send_message(chat_id=update.message.chat_id, text=message,parse_mode="html")
return ADD_ITEMS
def add_items_to_bill(bot, update):
user_input_bill_items = update.message.text
# Use regex
if user_input_bill_items == "Done":
message = "Looks like you're done! Here's your bill for re-confirmation: "
item_count=0
for item in bill_items:
item_count += 1
message += "<pre>" + str(item_count) + ". " + str(item) + "\n</pre>"
bot.send_message(chat_id=update.message.chat_id, text=message, parse_mode="html")
message = "Do you want to make any changes to the bill?"
reply_keyboard = [["Yes","No"]]
bot.send_message(chat_id=update.message.chat_id, text=message, reply_markup=ReplyKeyboardMarkup(reply_keyboard,one_time_keyboard=True))
return FINAL_OR_MAKE_CHANGES
bill_items.append(user_input_bill_items)
return ADD_ITEMS
def final_or_make_changes_to_bill(bot, update):
user_choice_make_changes = update.message.text
if user_choice_make_changes == "Yes":
reply_keyboard = [["Add","Delete"]]
message = "Do you want to add or delete?"
bot.send_message(chat_id=update.message.chat_id, text=message, reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
return ADD_OR_DELETE
return STOP
def add_or_delete(bot, update):
user_choice_add_or_delete = update.message.text
if user_choice_add_or_delete == "Add":
message = "Enter items you want to add."
bot.send_message(chat_id=update.message.chat_id, text=message)
return ADD_ITEMS
message = "Enter the list number of the item you want to delete. Type Done when you're done."
bot.send_message(chat_id= update.message.chat_id, text=message)
return DELETE
def delete_item_from_bill(bot, update):
number_to_delete = update.message.text
print(number_to_delete)
# SQL command to delete from table
print("to be filled")
return STOP
def stop(bot, update):
print("ht")
bot.send_message(chat_id=update.message.chat_id,text="dsfdsfsadf")
return ConversationHandler.END
# def done(bot, update):
# global ID
# bot.send_message(chat_id=update.message.chat_id, text="done")
# print("done")
# message = "Great! Share this ID with the other participants of the bill: "
# bot.send_message(chat_id=update.message.chat_id, text=message)
# return ConversationHandler.END
def cancel(bot,update):
print("cancel")
return ConversationHandler.END
def add_bought_items(bot, update):
message = "Add the list of items conforming to this example. Bill followed by ID\nEg: 4632 1,2,3"
bot.send_message(chat_id=update.message.chat_id, text=message)
def error(bot, update, error):
"""Log Errors caused by Updates."""
logger.warning('Update "%s" caused error "%s"', update, update.error)
def main():
updater = Updater(TOKEN)
db.setup()
PORT = int(os.environ.get('PORT','8443'))
dp = updater.dispatcher
dp.add_handler(CommandHandler("help",start))
create_conversation_handler = ConversationHandler(
entry_points = [CommandHandler('create',create)],
states = {
# GET_BILL_DETAILS: [MessageHandler(Filters.text,get_bill_details)],
ADD_ITEMS: [MessageHandler(Filters.text, add_items_to_bill)],
FINAL_OR_MAKE_CHANGES: [MessageHandler(Filters.text, final_or_make_changes_to_bill)],
ADD_OR_DELETE: [MessageHandler(Filters.text, add_or_delete)],
DELETE: [MessageHandler(Filters.text, delete_item_from_bill)],
STOP: [MessageHandler(Filters.text, stop)]
},
fallbacks = [CommandHandler('cancel',cancel)]
)
dp.add_handler(create_conversation_handler)
dp.add_error_handler(error)
dp.add_handler(CommandHandler("add",add_bought_items))
# dp.add_handler(CommandHandler("add",add))
updater.start_polling()
if __name__ == "__main__":
main()

Categories