Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Telegram Bot how to wait for user answer to a question And Return It

Context:

I am using PyTelegramBotAPi or Python Telegram Bot

I have a code I am running when a user starts the conversation.

When the user starts the conversation I need to send him the first picture and a question if He saw something in the picture, the function needs to wait for the user input and return whether he saw it or not.

After that, I will need to keep sending the picture in a loop and wait for the answer and run a bisection algorithm on it.

What I have tried so far:

I tried to use reply markup that waits for a response or an inline keyboard with handlers but I am stuck because my code is running without waiting for the user input.

The code:

@bot.message_handler(func=lambda msg: msg in ['Yes', 'No'])
@bot.message_handler(commands=['start', 'help'])
def main(message):
    """
    This is my main function
    """
    chat_id = message.chat.id
    try:
        reply_answer = message.reply_to_message.text
    except AttributeError:
        reply_answer = '0'
    # TODO : should wait for the answer asynchnonossly
    def tester(n, reply_answer):
        """
        Displays the current candidate to the user and asks them to
        check if they see wildfire damages.
        """
        print('call......')
        bisector.index = n
        bot.send_photo(
            chat_id=chat_id,
            photo=bisector.image.save_image(),
            caption=f"Did you see it Yes or No {bisector.date}",
            reply_markup=types.ForceReply(selective=True))
        # I SHOUL WAIT FOR THE INPUT HERE AND RETURN THE USER INPUT
        return eval(reply_answer)
    culprit = bisect(bisector.count, lambda x: x, partial(tester, reply_answer=reply_answer) )
    bisector.index = culprit
    bot.send_message(chat_id, f"Found! First apparition = {bisector.date}")


bot.polling(none_stop=True)

The algorithm I am running on the user input is something like this :

def bisect(n, mapper, tester):
    """
    Runs a bisection.

    - `n` is the number of elements to be bisected
    - `mapper` is a callable that will transform an integer from "0" to "n"
      into a value that can be tested
    - `tester` returns true if the value is within the "right" range
    """

    if n < 1:
        raise ValueError('Cannot bissect an empty array')

    left = 0
    right = n - 1

    while left + 1 < right:
        mid = int((left + right) / 2)

        val = mapper(mid)
        tester_values = tester(val) # Here is where I am using the ouput from Telegram bot
        if tester_values:
            right = mid
        else:
            left = mid

    return mapper(right)

I hope I was clear explaining the problem, feel free to ask any clarification. If you know something that can point me in the right direction in order to solve this problem, let me know.

I have tried a similar question but I am not getting answers.

like image 402
Espoir Murhabazi Avatar asked Mar 16 '20 10:03

Espoir Murhabazi


People also ask

Can a telegram bot start a conversation?

Telegram Bots can't initiate a conversation with a user. Only an user can initiate it by clicking on the start button.

How can I make Telegram bot run forever?

If you want to make sure your bot will run always, you have to daemonize it. There is a lot of solutions. You could transform your script to be a daemon, so when you launch it, it go directly to the background and continue to run until the server is shut down (or the program crash).

How many messages can a telegram bot send?

Also note that your bot will not be able to send more than 20 messages per minute to the same group.


Video Answer


1 Answers

You should save your user info in a database. Basic fields would be:

(id, first_name, last_name, username, menu)

What is menu?

Menu keeps user's current state. When a user sends a message to your bot, you check the database to find out about user's current sate.

So if the user doesn't exist, you add them to your users table with menu set to MainMenu or WelcomeMenu or in your case PictureMenu.

Now you're going to have a listener for update function, let's assume each of these a menu.

@bot.message_handler(commands=['start', 'help'])

so when the user sends start you're going to check user's menu field inside the function.

@bot.message_handler(commands=['start', 'help'])
def main(message):
    user = fetch_user_from_db(chat_id)
    if user.menu == "PictureMenu":
        if message.photo is Not None:
            photo = message.photo[0].file_id
            photo_file = download_photo_from_telegram(photo)
            do_other_things()
            user.menu = "Picture2Menu";
            user.save();
        else:
            send_message("Please send a photo")
    if user.menu == "Picture2Menu":
        if message.photo is Not None:
            photo = message.photo[0].file_id
            photo_file = download_photo_from_telegram(photo)
            do_other_things()
            user.menu = "Picture3Menu";
            user.save();
        else:
            send_message("Please send a photo")   
    ...

I hope you got it.

like image 79
Ali Padida Avatar answered Sep 28 '22 19:09

Ali Padida