【问题标题】:Python Telegram Bot ConversationHandler not working with webhookPython Telegram Bot ConversationHandler 无法与 webhook 一起使用
【发布时间】:2021-09-19 05:53:46
【问题描述】:

我想在我的机器人中创建一个使用 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"

The add project button doesn't do anything.

【问题讨论】:

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


    【解决方案1】:

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

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

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


    免责声明:我目前是python-telegram-bot的维护者

    【讨论】:

    • 你的猜测完全正确!啊,这是有道理的,所以我应该将调度程序存储在某种全局/会话变量中,这样就不会在每次电报到达请求时都调用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-12
    • 2020-09-22
    • 1970-01-01
    • 2016-04-10
    • 1970-01-01
    • 2017-10-17
    • 2020-09-26
    相关资源
    最近更新 更多