首页 > 解决方案 > Python Telegram Bot ConversationHandler 无法与 webhook 一起使用

问题描述

我想在我的机器人中创建一个使用 webhook 的 ConversationHandler,ConversationHandler 只在入口点运行该函数,之后它既不运行状态函数,也不运行回退函数。当 bot 通过轮询运行时,此 CommandHandler 运行良好。

对话处理程序:

conv_handler = ConversationHandler(
    entry_points=[CommandHandler("start", start)],
    states={
        NEW_PROJECT: [CallbackQueryHandler(project_name)],
        PROJECT_NAME: [MessageHandler(Filters.regex(".*"), store_name_maybe_project_type)],
        PROJECT_TYPE: [CallbackQueryHandler(store_type_maybe_admin)]
    },
    fallbacks=[CommandHandler('cancel', cancel)],
)

所有必需的功能:

def start(update, context):
    # Gives button of add project
    # We can use for loop to display buttons
    keyboard = [
        [InlineKeyboardButton("Add Project", callback_data="add_project")],
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    update.message.reply_text("You have no projects right now.", reply_markup=reply_markup)
    # if existing project then PROJECT or else NEW_PROJECT
    return NEW_PROJECT

def project_name(update, context):
    # asks for project name
    query = update.callback_query
    update.message.reply_text(text="Okay, Please enter your project name:")
    return PROJECT_NAME
    
def store_name_maybe_project_type(update, context):
    # stores project name and conditionally asks for project type
    print(update.message.text)

    keyboard = [
        [InlineKeyboardButton("Telegram Group", callback_data="group")],
        [InlineKeyboardButton("Telegram Channel", callback_data="channel")]
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    update.message.reply_text("What do you want to make?", reply_markup=reply_markup)

    return PROJECT_TYPE

def store_type_maybe_admin(update, context):
    # stores project type and conditonally asks for making admin
    print(update.message.text)
    keyboard = [[InlineKeyboardButton("Done", callback_data="done")]]
    reply_markup = InlineKeyboardMarkup(keyboard)
    update.message.reply_text(f"Make a private {update.message.text} and make this bot the admin", reply_markup=reply_markup)

    return ConversationHandler.END

def cancel(update, context):
    update.message.reply_text("Awww, that's too bad")
    return ConversationHandler.END

这就是我设置 webhook 的方式(我认为问题出在某个地方):

@app.route(f"/{TOKEN}", methods=["POST"])
def respond():
    """Run the bot."""
    update = telegram.Update.de_json(request.get_json(force=True), bot)
    dispatcher = setup(bot, update)
    dispatcher.process_update(update)
    return "ok"

设置功能

def setup(bot, update):
    # Create bot, update queue and dispatcher instances
    dispatcher = Dispatcher(bot, None, workers=0)
    ##### Register handlers here #####
    bot_handlers = initialize_bot(update)
    for handler in bot_handlers:
        dispatcher.add_handler(handler)
    return dispatcher

然后我使用这条路线手动设置 webhook:

@app.route("/setwebhook", methods=["GET", "POST"])
def set_webhook():
    s = bot.setWebhook(f"{URL}{TOKEN}")
    if s:
        return "webhook setup ok"
    else:
        return "webhook setup failed"

添加项目按钮不执行任何操作。

标签: telegram-botpython-telegram-bottelegram-webhook

解决方案


ConversationHandler将当前状态存储在内存中,因此一旦conv_handler到达其生命周期的末尾(即变量被删除或进程关闭),它就会丢失。现在您的代码片段没有显示您在哪里初始化ConversationHandler,但我觉得您为每个传入的更新重新创建它 - 每个新实例都不知道前一个实例。

我有这种感觉,因为您Dispatcher也会为每次更新创建一个新的。这没有必要,事实上我强烈建议不要这样做。不仅需要时间来初始化Dispatcher,您可以保存它,而且如果您正在使用chat/user/bot_data,每次创建新实例时数据都会丢失。

initialize_bot函数在 中调用setup,您在其中创建新的Dispatcher,这就是为什么我的猜测是您ConversationHandler为每次更新创建一个新的。在我看来,该函数的返回值似乎取决于update- 调度程序使用的处理程序应该是固定的,这对我来说似乎很奇怪......


免责声明:我目前是python-telegram-bot


推荐阅读