Fnguyen
Fnguyen

Reputation: 1177

How to process user messages after bot action in telegram?

I have written a simple telegram bot in python with the python-telegram-bot library that rolls a n-sided die and returns the result to the user.

My code for this:

# Let's make a dice bot
import random
import time
from telegram.ext import Updater,CommandHandler,MessageHandler, Filters
from telegram import Update

updater = Updater(token='MY-TOKEN', use_context=True)
dispatcher = updater.dispatcher

# relevant function here:
def dice_roll(sides):
    roll = random.randint(1,sides)
    return roll

def dice(update, context):
    result = dice_roll(int(context.args[0]))
    lucky_dice = "You rolled a "+str(result)
    context.bot.send_message(chat_id=update.message.chat_id, text=lucky_dice)
dice_handler = CommandHandler('rollDice', dice)
dispatcher.add_handler(dice_handler)

# Polling function here:
updater.start_polling(clean=True)

What I'd like to improve

I do not really like the way users interact with the bot at the moment. To roll a die, the user has to define the number of sides of the die in the command argument, like this:

$user: /rollDice 6
$bot: You rolled a 5

This isn't really user-friendly, and it's also prone to errors if users add anything else to the argument or simply forget.

Instead, I'd like the bot to ask the user for the input explicitly, like this:

$user: /rollDice
$bot: Please enter the number of sides, the die should have
$user: 6
$bot: You rolled a 5

I looked into force_reply, but my main issue is that I do not know how to access a new update/message within a handler function.

If I try something like this:

def dice(update, context):
    context.bot.send_message(chat_id=update.message.chat_id, text="Please enter the number of sides, the die should have") # new line
    result = dice_roll(int(context.args[0]))
    lucky_dice = "You rolled a "+str(result)
    context.bot.send_message(chat_id=update.message.chat_id, text=lucky_dice)
dice_handler = CommandHandler('rollDice', dice)
dispatcher.add_handler(dice_handler)

it does not really work, because a) the bot does not really give the user time to reply (adding a sleepstatement here seems very wrong) and b) it refers back to the original "command message" and not any new message sent in the meantime.

Any help is appreciated.

Upvotes: 2

Views: 3094

Answers (1)

Waqas
Waqas

Reputation: 6802

You can use ConversationHandler to achieve this, I am using similar code for my bot which asks user the bus number and replies with timetable. Most of the code is borrowed from: https://codeclimate.com/github/leandrotoledo/python-telegram-bot/examples/conversationbot.py/source

from telegram.ext import (Updater, CommandHandler, RegexHandler, ConversationHandler)
import random

# states
ROLLDICE = range(1)

def start(bot, update):
    update.message.reply_text('Please enter the number of sides, the die should have')

    return ROLLDICE

def cancel(bot, update):
    update.message.reply_text('Bye! I hope we can talk again some day.')
    return ConversationHandler.END

def rolldice(bot, update):
    roll = random.randint(1, int(update.message.text))
    update.message.reply_text('You rolled: ' + str(roll))
    return ConversationHandler.END

def main():
    updater = Updater(TOKEN)
    dp = updater.dispatcher

    conv_handler = ConversationHandler(
        entry_points=[CommandHandler('start', start)],
        states={ROLLDICE: [RegexHandler('^[0-9]+$', rolldice)]},
        fallbacks=[CommandHandler('cancel', cancel)]
    )

    dp.add_handler(conv_handler)
    updater.start_polling()

    updater.idle()

if __name__ == '__main__':
    main()

Output:

/start
Please enter the number of sides, the die should have
6
You rolled: 2

Upvotes: 2

Related Questions