web-dev-qa-db-ja.com

Python Telegram Botユーザーが質問に答えるのを待って返す方法

コンテキスト:

PyTelegramBotAPi または Python 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)

問題を明確に説明できていれば幸いです。ご不明な点がございましたらお気軽にお問い合わせください。この問題を解決するために私を正しい方向に向けることができる何かを知っているなら、私に知らせてください。

同様の質問をしましたが、回答が得られません。

4

私は答えを見つけました:

  • トリックは next_step_handler を使用し、message_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}")
0