尝试使用ConversationHandler

时间:2019-08-25 23:15:51

标签: python-3.x telegram telegram-bot python-telegram-bot

我试图同时处理InlineKeyboardButton callback_data和自由文本数据。这是我的情况:

提示带有多个按钮的InlineKeyboard,用户单击一个按钮,然后要求输入一些自由文本以供BE使用。

我试图将CallbackQueryHandler(回调函数中的几个InlineKeyboardMarkup)用作ConversationHandler的入口点,然后触发MessageHandler,但没有成功。 我需要捕获自由文本更新(基本上等待用户输入)。


def start(update, context):
    keyboard = [[InlineKeyboardButton("bal bla", callback_data='1'),
                 InlineKeyboardButton("bla bla", callback_data='2')],
                [InlineKeyboardButton("bla bla)", callback_data='3'),
                InlineKeyboardButton("bla bla", callback_data= '4')],
                [InlineKeyboardButton("bla bla", callback_data='5')]]

    reply_markup = InlineKeyboardMarkup(keyboard)
    update.message.reply_text('Please choose:', reply_markup=reply_markup)


reply_text = {'text': ''}


def reply_message(update, context):
    message = update.message.text
    reply_text['text'] = message
    return reply_text['text']


def button(update, context, user_data):
    query = update.callback_query
    query.edit_message_text(text="Loading....\n \r")

    if query.data == '1':
        pass
    elif query.data == '2':
        pass
    elif query.data == '3':

        keyboard = [[InlineKeyboardButton('BBB', callback_data='21'),
                     InlineKeyboardButton('GGG', callback_data='22')],
                    [InlineKeyboardButton('PPP', callback_data='23')]]

        reply_markup1 = InlineKeyboardMarkup(keyboard)
        query.edit_message_text('Please select:', reply_markup=reply_markup1)

    elif query.data == '21':

        query.edit_message_text('input customer name ')
        return 1

    if : #no idea which condition to give here
        print(reply_text['text'], '\n ^ new free text message here ^')


def main():

    conv_handler= ConversationHandler(
        entry_points=[
            CallbackQueryHandler(button)
        ],
        states={
            1 : [MessageHandler(Filters.text, reply_message)],
        },
        fallbacks= []
    )

    try:
        updater = Updater(bot_token, use_context=True)
        updater.dispatcher.add_handler(CommandHandler('start', start))
        updater.dispatcher.add_handler(CallbackQueryHandler(button))
        updater.dispatcher.add_handler(conv_handler)
        updater.start_polling()
        updater.idle()
    except Exception as e:
        print(e)

1 个答案:

答案 0 :(得分:0)

嘿,我通过提供一个函数来解析用户输入并使用上下文的user_data方法记住输入来解决了这个问题。

def check_user_input(update, context):
    # get last user text
    user_input = update.message.text
    # get user_data context
    user_data = context.user_data
    # set new context user_input
    user_data['user_input'] = user_input
    context.user_data['user_input'] = user_data['user_input']

    if "Text" in user_input:
        # do something... i.e reply w/o keyboard
        update.message.reply_text(
            ("{}?!, sounds interesting, tell me more".format(
            user_input)))
        return GUEST_CHOICE
    else:
        # ask again
        reply_keyboard = [['Text'],['Done']]
        markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
        update.message.reply_text(
            ("{}?!, i dont know anything...".format(
            user_input),reply_markup=markup))
        return CHECK_CHOICE

这似乎是处理和记住用户输入的首选方法。

现在可以根据需要在ConversationHandler / MessageHandlers中调用此函数。您只需返回指定的ConversationHandler状态。因此,我将使用两个状态(GUEST_CHOICE和CHECK_CHOICE状态)来处理单个用户输入验证。

    conv_handler = ConversationHandler(
        entry_points=[CommandHandler('start', start)],

        states={

            # Ask Guest
            GUEST_CHOICE: [MessageHandler(Filters.regex('^(Text)$'),
                                  guest_choice),
                        ],

            # Verify input
            CHECK_CHOICE: [MessageHandler(Filters.text,
                                          check_user_input),
                            ],
        },

        fallbacks=[MessageHandler(Filters.regex('^Done$'), done, CommandHandler('start', start))],
        allow_reentry = False,
        per_user=True,
        conversation_timeout=3600,
        name="test"
    )

按照定义,/ start用作用户启动对话处理程序。这将调用start()方法,即:

def start(update, context):           
    reply_keyboard = [['Text'],['Done']]
    markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)

    # Setup keyboard and reply
    update.message.reply_text(
            ("Hey {}, how can i help you?".format(
            update.message.chat['first_name'])),
            reply_markup=markup)

    return CHECK_CHOICE

start()将设置标记键盘,之后的任何输入都将以CHECK_CHOICE状态处理,此状态将在此处调用check_user_input(请参见上文)。这将返回GUEST_CHOICE,因此它将调用guest_choice(),即:

def guest_choice(update, context):  
    user_data = context.user_data

    # Check authentication request
    if "bob" in user_data['user_input']:
        update.message.reply_text("Hey {}".format(user_data['user_input']))         
    else:
        update.message.reply_text("Where is bob?!")
    return CHECK_INPUT

“完成”方法将清理对话

def done(update, context):
    markup = get_markup(context) 
    update.message.reply_text("Bye")

    return ConversationHandler.END

好的,很快就升级了……我从自己的会话处理程序的工作版本中重写了该代码,请检查是否存在错误:)也许必须在Done方法中清除user_data。