python-telegram-bot点击按钮触发ConversationHandler实现教程
Telegram文件共享机器人开发问题与解决方案
需求逻辑
我正在基于python-telegram-bot库开发Telegram机器人,核心逻辑如下:
- 用户发送
/start指令时,机器人返回带按钮的主菜单,每个按钮对应用户可申请访问的文件; - 用户点击任意按钮后启动对话流程,机器人索要用户的Gmail邮箱地址;
- 用户提交Gmail地址后,机器人校验格式,格式正确则授予文件访问权限并推送文件链接到对话窗口。
我参考了官方两个示例项目作为开发基础:
- conversationbot.py
- conversationbot2.py
初始代码与问题
我编写的初始代码如下:
from telegram import ( Bot, Update, InlineKeyboardMarkup, InlineKeyboardButton, ) from telegram.ext import ( Updater, CommandHandler, MessageHandler, Filters, CallbackContext, CallbackQueryHandler, ConversationHandler, ) def startCommand(update: Update, context: CallbackContext): keyboardMarkup = InlineKeyboardMarkup( [[InlineKeyboardButton('共享文件1', callback_data='sharingFile1')]] ) update.message.reply_text(f'你好, {update.effective_user.first_name}。\n这里是主菜单。', reply_markup=keyboardMarkup) def convGetGMailAddr(update: Update, context: CallbackContext): update.message.reply_text('请提供你的Gmail邮箱地址。\n\n发送/end可终止当前流程。') return convEmailAddr def convMismatch(update: Update, context: CallbackContext): text = """抱歉,你提供的Gmail地址格式不正确。 请重新提交你的Gmail地址。\n\n发送/end可终止当前流程。 """ update.message.reply_text(text) return convEmailAddr def convGiveLink(update: Update, context: CallbackContext): link = 'https://docs.google.com/spreadsheets/d/1ZP1xZ0WaH8w2yaQTSx99gafNZWawQabcdVW5DSngavQ' update.message.reply_text(f'感谢配合!这是你申请的共享文件链接:\n{link}') return ConversationHandler.END def convEnd(update: Update, context: CallbackContext): update.message.reply_text('已终止当前流程。\n\n发送/start可返回主菜单。') return ConversationHandler.END def sharingFileHandler(update: Update, context: CallbackContext): if update.callback_query.data == 'sharingFile1': update.callback_query.edit_message_text( update.effective_message.text, reply_markup=InlineKeyboardMarkup([]) ) conv_sharing = ConversationHandler( entry_points=[MessageHandler(Filters.regex('.*[文件1]*.*'), convGetGMailAddr)], states={ convEmailAddr: [ MessageHandler(~Filters.regex('.*@gmail.com$') & ~Filters.command, convMismatch), MessageHandler(Filters.regex('.*@gmail.com$'), convGiveLink), ], }, fallbacks=[CommandHandler('end', convEnd)], ) disp.add_handler(conv_sharing) bot.send_message(update.effective_chat.id, '我将为你共享文件1。') bot_token = 'abcd1234' bot = Bot(bot_token) updater = Updater(bot_token, use_context=True) convEmailAddr = '' disp = updater.dispatcher disp.add_handler(CommandHandler('start', startCommand)) disp.add_handler(CallbackQueryHandler(sharingFileHandler)) updater.start_polling(drop_pending_updates=True) updater.idle()
当前遇到两个待解决问题:
- 机器人无法识别自身在
sharingFileHandler函数中发送的回复来触发对话处理器,当前对话入口设置为匹配字符串"文件1",只有用户主动发送包含"文件1"的内容时流程才能正常启动; - 希望机器人仅在对话流程生效期间监听用户提交的邮箱地址,当前
convGetGMailAddr函数会在任意时刻被触发,请问该如何实现该需求?
2021-10-20更新:解决方案
修改代码后问题已全部解决,我删除了convGetGMailAddr函数,修改后的sharingFileHandler和核心处理器注册逻辑如下:
def sharingFileHandler(update: Update, context: CallbackContext): if update.callback_query.data == 'sharingFile1': update.callback_query.edit_message_text( update.effective_message.text, reply_markup=InlineKeyboardMarkup([]) ) text = """我将把文件1共享到你的Google账户。 请提供你的Gmail邮箱地址。\n\n发送/end可终止当前流程。""" bot.send_message(update.effective_chat.id, text) return convEmailAddr bot_token = '1234abcd' bot = Bot(bot_token) updater = Updater(bot_token, use_context=True) convEmailAddr = '' disp = updater.dispatcher disp.add_handler(CommandHandler('start', startCommand)) conv_sharing = ConversationHandler( entry_points=[CallbackQueryHandler(sharingFileHandler)], states={ convEmailAddr: [ MessageHandler(~Filters.regex('.*@gmail.com$') & ~Filters.command, convMismatch), MessageHandler(Filters.regex('.*@gmail.com$'), convGiveLink), ], }, fallbacks=[CommandHandler('end', convEnd)], ) disp.add_handler(conv_sharing) updater.start_polling(drop_pending_updates=True) updater.idle()
修改后机器人运行完全符合预期,所有需求均已实现。
内容的提问来源于stack exchange,提问作者Serge-M
相关产品推荐
相关产品推荐

