如何使用机器人回复触发对话处理程序? [电报机器人] [Python] [python-电报机器人]
How to trigger a conversation handler with the bot reply? [Telegram Bot] [Python] [python-telegram-bot]
逻辑如下:
- 使用 /start 命令,机器人会显示带有按钮的主菜单(每个按钮代表用户想要访问的文件);
- 按下任意按钮后,对话开始,机器人会要求提供 gmail 地址;
- 用户发送他们的 gmail 地址,bot 检查它,如果地址格式正确则 bot 授予查看文件的权限并将 link 发布到聊天。
我使用这些示例作为起点:
- https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot.py
- https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/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('Share File 1', callback_data='sharingFile1')]]
)
update.message.reply_text(f'Howdy, {update.effective_user.first_name}.\nThis is the Main Menu.',
reply_markup=keyboardMarkup)
def convGetGMailAddr(update: Update, context: CallbackContext):
update.message.reply_text('Waiting for your gmail address.\n\nSend /end and I\'ll stop waiting.')
return convEmailAddr
def convMismatch(update: Update, context: CallbackContext):
text = f"""Sorry, I don't understand this gmail address.
Please, send me your gmail address again.\n\nSend /end and I\'ll stop waiting.
"""
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'Thank you! Here\'s your link to the shared file:\n{link}')
return ConversationHandler.END
def convEnd(update: Update, context: CallbackContext):
update.message.reply_text('I\'ve stopped waiting.\n\nSend /start to go to the Main Menu.')
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('.*[File 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, 'I\'ll share the File 1 with you.')
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
中的回复来启动对话处理程序。对话的入口点是发布字符串“File 1”,当我发送类似“asdklhasdlkh file 1 asdaskldha”的内容时,一切正常。
另一个问题是机器人是否可以只在对话中收听电子邮件地址?现在函数 convGetGMailAddr
随时启动。
更新 1 (2021-10-20)
根据 CallMeStag 的回答,我更改了代码。
删除了函数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 = f"""I\'ll share the File 1 with you to your Google account.
Please, send me your gmail address.\n\nSend /end and I\'ll stop waiting."""
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()
现在我的机器人完全按照我的意愿去做,它停止了我希望它停止做的事情。
谢谢你,CallMeStag!
您正在构建一个新的会话处理程序并在每次调用 sharingFileHandler
时将其添加到调度程序。那肯定不是你想要的。相反,您应该只构建它一次并将它添加到调度程序中,也只在您添加其他处理程序的地方(在代码段的最后)添加一次。
然后您应该将 CallbackQueryHandler(sharingFileHandler)
作为该对话的切入点。这将自动解决您的第二个问题。
免责声明:我目前是 python-telegram-bot
.
的维护者
逻辑如下:
- 使用 /start 命令,机器人会显示带有按钮的主菜单(每个按钮代表用户想要访问的文件);
- 按下任意按钮后,对话开始,机器人会要求提供 gmail 地址;
- 用户发送他们的 gmail 地址,bot 检查它,如果地址格式正确则 bot 授予查看文件的权限并将 link 发布到聊天。
我使用这些示例作为起点:
- https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot.py
- https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/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('Share File 1', callback_data='sharingFile1')]]
)
update.message.reply_text(f'Howdy, {update.effective_user.first_name}.\nThis is the Main Menu.',
reply_markup=keyboardMarkup)
def convGetGMailAddr(update: Update, context: CallbackContext):
update.message.reply_text('Waiting for your gmail address.\n\nSend /end and I\'ll stop waiting.')
return convEmailAddr
def convMismatch(update: Update, context: CallbackContext):
text = f"""Sorry, I don't understand this gmail address.
Please, send me your gmail address again.\n\nSend /end and I\'ll stop waiting.
"""
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'Thank you! Here\'s your link to the shared file:\n{link}')
return ConversationHandler.END
def convEnd(update: Update, context: CallbackContext):
update.message.reply_text('I\'ve stopped waiting.\n\nSend /start to go to the Main Menu.')
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('.*[File 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, 'I\'ll share the File 1 with you.')
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
中的回复来启动对话处理程序。对话的入口点是发布字符串“File 1”,当我发送类似“asdklhasdlkh file 1 asdaskldha”的内容时,一切正常。
另一个问题是机器人是否可以只在对话中收听电子邮件地址?现在函数 convGetGMailAddr
随时启动。
更新 1 (2021-10-20)
根据 CallMeStag 的回答,我更改了代码。
删除了函数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 = f"""I\'ll share the File 1 with you to your Google account.
Please, send me your gmail address.\n\nSend /end and I\'ll stop waiting."""
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()
现在我的机器人完全按照我的意愿去做,它停止了我希望它停止做的事情。
谢谢你,CallMeStag!
您正在构建一个新的会话处理程序并在每次调用 sharingFileHandler
时将其添加到调度程序。那肯定不是你想要的。相反,您应该只构建它一次并将它添加到调度程序中,也只在您添加其他处理程序的地方(在代码段的最后)添加一次。
然后您应该将 CallbackQueryHandler(sharingFileHandler)
作为该对话的切入点。这将自动解决您的第二个问题。
免责声明:我目前是 python-telegram-bot
.