在处理需要外部API请求的语音消息时,异步Telegram机器人会卡住。
import os
import tempfile
import requests
from dotenv import load_dotenv
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes, MessageHandler, filters
load_dotenv()
BOT_TOKEN = os.getenv("BOT_TOKEN")
BACKEND_URL = os.getenv("BACKEND_URL", "http://localhost:3000")
VOICE_TIMEOUT = int(os.getenv("VOICE_TIMEOUT", 600))
def profile(update: Update):
user = update.effective_user
return {
"telegramId": str(user.id),
"username": user.username or "",
"firstName": user.first_name or "",
}
def keyboard(buttons):
return InlineKeyboardMarkup([
[InlineKeyboardButton(button["text"], callback_data=button["data"]) for button in row]
for row in buttons
])
async def send(update: Update, data):
target = update.message or update.callback_query.message
markup = keyboard(data.get("buttons", [])) if data.get("buttons") else None
await target.reply_text(data.get("reply", ""), reply_markup=markup)
if data.get("imagePath"):
with open(data["imagePath"], "rb") as image:
await target.reply_photo(image)
def post(path, data=None, files=None, timeout=120):
kwargs = {"data": data, "files": files} if files else {"json": data}
response = requests.post(f"{BACKEND_URL}{path}", **kwargs, timeout=timeout)
response.raise_for_status()
return response.json()
def command(msg):
async def _handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
await send(update, post("/chat", {**profile(update), "message": msg}))
return _handler
async def text(update: Update, context: ContextTypes.DEFAULT_TYPE):
data = post("/chat", {**profile(update), "message": update.message.text})
await send(update, data)
async def callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
await query.answer()
data = post("/callback", {"telegramId": str(query.from_user.id), "callbackData": query.data})
await send(update, data)
async def voice(update: Update, context: ContextTypes.DEFAULT_TYPE):
voice_file = await update.message.voice.get_file()
path = None
try:
await update.message.reply_text("Processing your voice note. First run can take a little time.")
with tempfile.NamedTemporaryFile(suffix=".oga", delete=False) as temp:
path = temp.name
await voice_file.download_to_drive(path)
with open(path, "rb") as audio:
data = post("/voice", profile(update), {"audio": ("voice.oga", audio, "audio/ogg")}, timeout=VOICE_TIMEOUT)
await send(update, data)
except requests.exceptions.Timeout:
await update.message.reply_text("Voice processing is taking too long. Try a shorter voice note once the model finishes loading.")
except Exception as error:
print("[BOT ERROR]", error)
await update.message.reply_text("Could not process voice. Please try again.")
finally:
if path and os.path.exists(path):
os.remove(path)
def main():
app = Application.builder().token(BOT_TOKEN).build()
app.add_handler(CommandHandler("start", command("/start")))
app.add_handler(CommandHandler("menu", command("/menu")))
app.add_handler(CallbackQueryHandler(callback))
app.add_handler(MessageHandler(filters.VOICE, voice))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, text))
print("[BOT] ArthSaathi bot is running...")
app.run_polling()
if __name__ == "__main__":
main()
我正在用Python搭建一个Telegram机器人,使用 python-telegram-bot(v20+)和异步处理程序。
机器人接收文本消息、回调查询和语音消息。
对于语音消息,它会下载 .oga 文件,发送到外部后端API进行语音处理,然后再用API的返回结果进行回复。
问题在于,当语音消息正在处理时,机器人对所有其他用户和消息都无响应。看起来像是在“冻结”,直到外部API调用完成为止。这段时间内文本消息和回调查询都不会被处理。
后端处理可能需要从30秒到几分钟不等,因为它需要加载一个AI模型并执行语音转文本和大语言模型推断。
解决方案
你的函数 post 不是异步的。请将其改为异步,使用诸如 aiohttp 这样的异步工具,替代 requests。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。