You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于python-telegram-bot与asyncio实现可顺序等待用户输入的组件?

实现支持顺序await用户输入的Telegram机器人组件库

需求与问题描述

想要构建一套Telegram机器人组件库,支持按顺序执行组件,每个组件可await用户输入后再继续后续代码,示例用法如下:

fname = await Question().run('Enter first name')
lname = await Question().run('Enter last name')

同时需保证代码中其他协程可正常运行。但当前实现的Question类中,run方法通过while循环轮询self.result并配合asyncio.sleep(1)等待输入,会导致无法接收用户消息(事件循环被无意义的轮询占用,无法及时处理on_message回调)。

解决方案:使用asyncio.Future替代轮询

核心思路是利用asyncio.Future对象异步等待结果,而非通过循环sleep轮询。当用户发送消息时,在回调中直接设置Future的结果,run方法只需await该Future即可,既不会阻塞事件循环,也能高效响应输入。

以下是改进后的Question类实现(基于python-telegram-bot v13+):

import asyncio
from telegram import Update
from telegram.ext import CallbackContext, MessageHandler, Filters

class Question:
    def __init__(self):
        self.future = asyncio.Future()
        self.handler = None

    async def on_message(self, update: Update, context: CallbackContext):
        # 仅在Future未完成时设置结果,避免重复触发
        if not self.future.done():
            self.future.set_result(update.message.text)
            # 移除临时注册的handler,防止后续消息干扰
            context.application.remove_handler(self.handler)

    async def run(self, prompt: str, update: Update, context: CallbackContext):
        # 创建仅监听当前用户文本消息的handler
        self.handler = MessageHandler(
            Filters.user(user_id=update.effective_user.id) & Filters.text,
            self.on_message
        )
        # 注册handler到机器人应用
        context.application.add_handler(self.handler)
        # 发送提示消息给用户
        await update.message.reply_text(prompt)
        # 等待用户输入,此操作会让出事件循环,不阻塞其他协程
        result = await self.future
        return result

使用示例

async def start_conversation(update: Update, context: CallbackContext):
    # 按顺序发起提问
    fname = await Question().run('请输入你的名字', update, context)
    lname = await Question().run('请输入你的姓氏', update, context)
    await update.message.reply_text(f"你好,{fname} {lname}!")

额外优化:添加超时处理

若需要限制用户输入的时间,可通过asyncio.wait_for为Future添加超时机制:

async def run(self, prompt: str, update: Update, context: CallbackContext, timeout: int = 60):
    self.handler = MessageHandler(
        Filters.user(user_id=update.effective_user.id) & Filters.text,
        self.on_message
    )
    context.application.add_handler(self.handler)
    await update.message.reply_text(prompt)
    
    try:
        result = await asyncio.wait_for(self.future, timeout=timeout)
        return result
    except asyncio.TimeoutError:
        # 超时后移除handler并提示用户
        context.application.remove_handler(self.handler)
        await update.message.reply_text("输入超时,请重新发起请求。")
        raise  # 抛出异常让调用方处理

注意事项

  • 确保使用的Telegram机器人库支持动态添加/移除handler(如python-telegram-bot v13+及以上版本)。
  • 若使用python-telegram-bot v20+版本,API结构有调整,需对应修改handler的注册方式,但核心的Future等待逻辑保持一致。

内容的提问来源于stack exchange,提问作者Lex Podgorny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 08:25:20