pythontelegramgenius-api

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


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

Solution

  • 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.