基于python-telegram-bot实现按钮兼具用户消息发送与回调触发功能
实现Telegram按钮同时触发回调+模拟用户发送消息(python-telegram-bot)
可以实现你的需求,下面提供两种适配不同场景的解决方案,基于python-telegram-bot框架:
方案一:用ReplyKeyboardButtons实现原生用户视角消息(推荐)
ReplyKeyboardButtons点击后会自动以用户身份发送按钮文本到聊天框,同时我们可以通过存储消息关联关系,触发对应回调逻辑,完美匹配你的需求:
步骤1:发送带关联配置的按钮消息
当管理员给用户推送带按钮的消息时,将消息ID、按钮文本与回调函数的映射关系存入chat_data,确保后续能关联到原消息:
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove from telegram.ext import CommandHandler, MessageHandler, Filters def send_button_msg(update, context): chat_id = update.effective_chat.id # 原消息内容 content = "请选择回复选项:" # 定义按钮文本与回调标识的映射 btn_config = [ {"text": "同意", "callback": "handle_agree"}, {"text": "拒绝", "callback": "handle_refuse"} ] # 构建键盘 keyboard = [[btn["text"]] for btn in btn_config] reply_markup = ReplyKeyboardMarkup(keyboard, one_time_keyboard=True) # 发送消息并获取原消息ID sent_msg = context.bot.send_message(chat_id, content, reply_markup=reply_markup) msg_id = sent_msg.message_id # 存储关联信息到chat_data context.chat_data[msg_id] = { "btn_map": {b["text"]: b["callback"] for b in btn_config}, "original_msg_id": msg_id }
步骤2:处理用户发送的按钮文本
捕获用户发送的文本,匹配chat_data中的按钮映射,执行对应回调逻辑并关联原消息:
# 预定义回调函数 def handle_agree(update, context, original_msg_id): # 这里写同意操作的逻辑,比如关联原消息ID处理业务 update.message.reply_text(f"已处理您对消息[{original_msg_id}]的同意请求") def handle_refuse(update, context, original_msg_id): update.message.reply_text(f"已处理您对消息[{original_msg_id}]的拒绝请求") # 消息处理器 def process_btn_reply(update, context): user_text = update.message.text # 遍历存储的消息配置,匹配按钮文本 for msg_id, config in list(context.chat_data.items()): if user_text in config["btn_map"]: callback_func = config["btn_map"][user_text] original_msg_id = config["original_msg_id"] # 执行对应回调 globals()[callback_func](update, context, original_msg_id) # 清理已处理的配置(避免重复匹配) del context.chat_data[msg_id] # 移除键盘(可选) context.bot.send_message(update.effective_chat.id, "回复已记录", reply_markup=ReplyKeyboardRemove()) return # 非按钮文本的处理 update.message.reply_text("请通过按钮回复")
步骤3:注册处理器
def main(): updater = Updater("YOUR_BOT_TOKEN") dp = updater.dispatcher dp.add_handler(CommandHandler("send_btn", send_button_msg)) dp.add_handler(MessageHandler(Filters.text & ~Filters.command, process_btn_reply)) updater.start_polling() updater.idle() if __name__ == "__main__": main()
方案二:用InlineKeyboardButton模拟用户消息效果
如果需要保留InlineKeyboard的回调特性,同时模拟用户发送消息的视觉效果,可以在回调函数中让机器人发送一条带用户昵称前缀的消息,再执行回调逻辑:
from telegram import InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import CallbackQueryHandler def send_inline_btn(update, context): chat_id = update.effective_chat.id content = "请选择回复选项:" # 发送初始消息 sent_msg = context.bot.send_message(chat_id, content) msg_id = sent_msg.message_id # 构建Inline按钮,data包含回调标识和原消息ID keyboard = [ [InlineKeyboardButton("同意", data=f"agree:{msg_id}")], [InlineKeyboardButton("拒绝", data=f"refuse:{msg_id}")] ] reply_markup = InlineKeyboardMarkup(keyboard) # 编辑消息添加按钮 context.bot.edit_message_text(content, chat_id, msg_id, reply_markup=reply_markup) def process_inline_callback(update, context): query = update.callback_query query.answer() # 解析回调数据 callback_tag, original_msg_id = query.data.split(":") btn_text = query.text user_name = update.effective_user.first_name # 模拟用户发送消息的视觉效果 context.bot.send_message(update.effective_chat.id, f"{user_name}:{btn_text}") # 执行回调逻辑 if callback_tag == "agree": handle_agree(update, context, original_msg_id) elif callback_tag == "refuse": handle_refuse(update, context, original_msg_id) # 移除按钮(可选) query.edit_message_reply_markup(reply_markup=None) # 注册处理器 dp.add_handler(CommandHandler("send_inline", send_inline_btn)) dp.add_handler(CallbackQueryHandler(process_inline_callback))
关键说明
- 方案一完全满足“用户视角消息气泡+回调触发+关联原消息”的需求,是最优解;
- 方案二更适合依赖InlineKeyboard特性的场景,但消息实际发送者仍是机器人;
- 两种方案都通过
chat_data或按钮data字段关联原消息ID,支持用户跨消息顺序回复。
内容的提问来源于stack exchange,提问作者kmf
相关产品推荐
相关产品推荐

