Python Telegram Bot, как дождаться ответа пользователя на вопрос и вернуть его - PullRequest
4 голосов
/ 16 марта 2020

Контекст:

Я использую PyTelegramBotAPi или Python Telegram Bot

У меня есть код I я запускаю, когда пользователь начинает разговор.

Когда пользователь начинает разговор, мне нужно отправить ему первое изображение и вопрос, видел ли он что-то на рисунке, функция должна ждать ввода пользователя и верните, видел ли он это или нет.

После этого мне нужно будет продолжать посылать картинку в al oop, ждать ответа и запускать алгоритм деления пополам на нем.

Что я пробовал до сих пор:

Я пытался использовать разметку ответа, которая ждет ответа, или встроенную клавиатуру с обработчиками, но я застрял, потому что мой код выполняется без ожидания ввода пользователя. .

Код:

@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)

Алгоритм, который я запускаю для пользовательского ввода, выглядит примерно так:

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)

Надеюсь Я четко объяснил проблему, не стесняйтесь спрашивать любые разъяснения. Если вы знаете что-то, что может направить меня в правильном направлении для решения этой проблемы, дайте мне знать.

Я пробовал подобный вопрос, но не получаю ответы.

Ответы [ 2 ]

6 голосов
/ 18 марта 2020

Вы должны сохранить ваши данные пользователя в базе данных. Поля Basi c будут:

(id, first_name, last_name, username, menu)

Что такое меню?

Меню сохраняет текущее состояние пользователя. Когда пользователь отправляет сообщение вашему боту, вы проверяете базу данных, чтобы узнать текущее состояние пользователя.

Поэтому, если пользователь не существует, вы добавляете его в свою таблицу пользователей с menu, установленным в MainMenu или WelcomeMenu или в вашем случае PictureMenu.

Теперь у вас будет прослушиватель для функции обновления, давайте представим каждому из них меню.

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

поэтому, когда пользователь отправляет start, вы собираетесь проверить поле меню пользователя внутри функции.

@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")   
    ...

Надеюсь, вы его получили.

0 голосов
/ 23 марта 2020

Я нашел ответ:

  • хитрость заключалась в том, чтобы использовать next_step_handler и message_handler_function для обработки команд, начинающихся с start и help

  • Затем, как предложил @ALi в своем ответе, я сохраню ответ пользователя, а также идентификатор вопроса, на который он ответил, в словаре, где ключи - это вопросы, а идентификатор - это ответ.

  • После того, как пользователь ответил на все вопросы, я могу запустить алгоритмы для его ответа

Вот как это выглядит в код:

user_dict = {}


# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
    # initialise the the bisector and 
    bisector = LandsatBisector(LON, LAT)
    indice = 0
    message = send_current_candidate(bot, message, bisector, indice)
    bot.register_next_step_handler(
        message, partial(
            process_step, indice, bisector))


def process_step(indice, bisector, message):
    # this run a while loop and will that send picture and will stop when the count is reached
    response = message.text
    user = User.create_get_user(message, bisector=bisector)
    if indice < bisector.count - 1:
        indice += 1
        try:
            # get or create
            user.responses[bisector.date] = response # save the response
            message = send_current_candidate(bot, message, bisector, indice)
            bot.register_next_step_handler(
                message, partial(
                    process_step, indice, bisector))
        except Exception as e:
            print(e)
            bot.reply_to(message, 'oooops')
    else:
        culprit = bisect(bisector.count,
                         lambda x: x,
                         partial(
                             tester_function,
                             responses=list(user.responses.values())))
        bisector.index = culprit
        bot.reply_to(message, f"Found! First apparition = {bisector.date}")
...