【问题标题】:Python Telegram Bot how to wait for user answer to a question And Return ItPython Telegram Bot 如何等待用户回答问题并返回
【发布时间】:2020-06-27 11:32:01
【问题描述】:

上下文:

我正在使用PyTelegramBotAPiPython Telegram Bot

当用户开始对话时,我正在运行一个代码。

当用户开始对话时,我需要向他发送第一张图片和一个问题,如果他看到图片中的东西,该函数需要等待用户输入并返回他是否看到。

之后,我将需要继续循环发送图片并等待答案并对其运行二分算法。

到目前为止我所做的尝试:

我尝试使用等待响应的回复标记或带有处理程序的内联键盘,但我被卡住了,因为我的代码正在运行而无需等待用户输入。

代码:

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

我希望我清楚地解释了问题,请随时提出任何澄清。 如果您知道一些可以为我指明正确方向以解决此问题的信息,请告诉我。

我尝试过类似的问题,但没有得到答案。

【问题讨论】:

    标签: python telegram telegram-bot python-telegram-bot


    【解决方案1】:

    我找到了答案:

    • 诀窍是使用next_step_handlermessage_handler_function 来处理以starthelp 开头的命令

    • 然后按照@ALi 在他的回答中的建议,我将把用户输入的答案以及他回答的问题 ID 保存在字典中,其中键是问题,ID 是答案。

    • 一旦用户回答了所有问题,我就可以根据他的答案运行算法

    这是代码中的样子:

    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}")
    

    【讨论】:

      【解决方案2】:

      您应该将您的用户信息保存在数据库中。基本字段是:

      (id, first_name, last_name, username, menu)

      什么是菜单?

      菜单保持用户的当前状态。当用户向您的机器人发送消息时,您检查数据库以了解用户的当前状态。

      因此,如果用户不存在,您可以将其添加到您的用户表中,并将 menu 设置为 MainMenuWelcomeMenu 或在您的情况下为 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")   
          ...
      

      我希望你明白了。

      【讨论】:

      • 但问题是,我是发送图片给用户而不是他的人
      • @EspoirMurhabazi 然后不要发送:Please send a photo,您应该自己发送照片并要求用户发送详细信息。您应该对所有类型的更新使用全局更新处理程序,然后手动检查用户是否发送了文本并且他们的菜单是 Picture1Menu。你调用相关函数,比如说:picture_details_handler
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-01
      • 2018-01-20
      • 1970-01-01
      • 2019-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多