Can't seem to find a way to make my Telegram Bot wait for user input

1.2k Views Asked by At

I'm trying to make a telegram bot that gets lyrics from the genius API. When the bot asks for the artist, it sends the question for the song title right after, but I'm trying to make the bot work like the input() command in python.

I know I could make the user split the string with a comma between the artist and the song title, but that would be a last resort option.

Here's the code I'm talking about.

def lyrics(update: Update, context: CallbackContext) -> None:
    update.message.reply_text("Enter artist")
    artist_name = update.message.text
    artist = genius.search_artist(artist_name, max_songs=0)
    update.message.reply_text("Enter song title")
    song_name = update.message.text
    song = artist.song(song_name)
    update.message.reply_text(song.lyrics)

And an example without the lyrics thing

update.message.reply_text("Reply something")
reply = update.message.text
update.message.reply_text("2nd answer")
reply2 = update.message.text
1

There are 1 best solutions below

0
On BEST ANSWER

You might be looking for ConversationHandler, which can handle conversations.

Prepration

To start, we need to import the following modules and define Dispatcher, which takes all the handlers for your bot.

from telegram import Update
from telegram.ext import (
    Updater,
    Filters,
    CommandHandler,
    MessageHandler,
    ConversationHandler,
    CallbackContext
)

updater = Updater('your token here', use_context=True)

dispatcher = updater.dispatcher

ConversationHandler

Then, we attach the conversation handler to the dispatcher with dispatcher.add_handler. You can specify states like the following and define a conversation handler.

Note that states must be int, for readability, we define constants ARTIST and TITLE for different states.

For more information about Filters, check out the documentation here. We only need Filters.text here as we only take texts as input for MessageHandler.

ARTIST, TITLE = 0, 1
dispatcher.add_handler(ConversationHandler(
    entry_points=[CommandHandler('start', intro)],
    states={
        ARTIST: [MessageHandler(Filters.text, callback=artist)],
        TITLE: [MessageHandler(Filters.text, callback=title)]
    },
    fallbacks=[CommandHandler('quit', quit)]
))

Handlers for the ConversationHandler

The conversation is started with entry_points and proceeded with different states. Each of these requires a handler. For example, we define a CommandHandler called intro for entry_points, which is called when the user inputs the command /start.

def intro(update: Update, context: CallbackContext) -> int:
    update.message.reply_text('Enter artist')
    # Specify the succeeding state to enter
    return ARTIST

The other handlers like artist and title are straightforward as well. For example:

def artist(update: Update, context: CallbackContext) -> int:
    artist_name = update.message.text
    # This variable needs to be stored globally to be retrieved in the next state
    artist = genius.search_artist(artist_name, max_songs=0)
    update.message.reply_text('Enter song title')
    # Let the conversation proceed to the next state
    return TITLE
def title(update: Update, context: CallbackContext) -> int:
    song_name = update.message.text
    song = artist.song(song_name)
    update.message.reply_text(song.lyrics)
    # return ConversationHandler.END to end the conversation
    return ConversationHandler.END

Also, the conversation needs a fallback handler. In the code example, we define a simple quit function to end the conversation when the user types in the command /quit.

def quit(update: Update, context: CallbackContext):
    return ConversationHandler.END

Sidenotes

An advantage of using ConversationHandler is that you can add any new states at any time to ask more questions. ConversationHandler also makes filtering messages easier.

You can also take a look at an example of a conversation bot here which utilizes ConversationHandler.