我是编写电报机器人的新手,我正在使用
python-telegram-bot
库来做到这一点。
我想编写一个机器人,它从用户那里获取一些输入并在最后返回它们。例如以下状态:
用户发送命令:
/set_username
机器人发送文本:
Enter the username:
用户以文本形式发送用户名:
negar-amiri
机器人发送文本:
Username that you set is:\nnegar-amiri
我编写了下面的代码,仅正确获取文件路径,无论我向其发送哪个命令,机器人总是将答案放入
self.file_path
变量中。
我发现这个问题,因为所有
MessageHandler
都有相同的过滤器,无论用户选择什么命令,每条不是命令的消息都会进入 self.file_path
变量,但我不知道如何修复它。你能帮我吗?
#!/usr/bin/env python
import logging
from telegram import Update
from telegram.ext import (
filters,
ConversationHandler,
Application,
MessageHandler,
CommandHandler,
)
import config
BOT_API_TOKEN = config.BOT_API_TOKEN
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
)
logging.getLogger("httpx").setLevel(logging.WARNING)
logger = logging.getLogger(__name__)
class TelegramBot:
def __init__(self) -> None:
self.file_path: str = ""
self.username: str = ""
self.password: str = ""
self.host: str = ""
async def start_command(self, update: Update) -> None:
user = update.effective_user
await update.message.reply_html(f"Hi {user.mention_html()}!")
async def set_file_path_command(self, update: Update) -> int:
self.file_path = update.message.text
await update.message.reply_html(
f"File address that you set is:\n{self.file_path}"
)
return ConversationHandler.END
async def set_username_command(self, update: Update) -> int:
self.username = update.message.text
await update.message.reply_html(f"Username that you set is:\n{self.username}")
return ConversationHandler.END
async def set_password_command(self, update: Update) -> int:
self.password = update.message.text
await update.message.reply_html(f"Password that you set is:\n{self.password}")
return ConversationHandler.END
async def set_host_command(self, update: Update) -> int:
self.host = update.message.text
await update.message.reply_html(f"Host that you set is:\n{self.host}")
return ConversationHandler.END
async def echo_set_file_path(self, update: Update) -> None:
await update.message.reply_text("Enter the file path:")
async def echo_set_username(self, update: Update) -> None:
await update.message.reply_text("Enter the username:")
async def echo_set_password(self, update: Update) -> None:
await update.message.reply_text("Enter the password:")
async def echo_set_host(self, update: Update) -> None:
await update.message.reply_text(
"Enter the host(IP or URL e.g. 192.168.1.4 or test.com):"
)
async def end_command(self, update: Update) -> None:
await update.message.reply_html(
f"You Enter '{self.file_path}' as a file path.\nYou Enter '{self.username}' as a username.\nYou Enter '{self.password}' as a password.\nYou Enter '{self.host}' as a host."
)
def main() -> None:
application = Application.builder().token(BOT_API_TOKEN).build()
bot = TelegramBot()
application.add_handlers(
[
CommandHandler("start", bot.start_command),
CommandHandler("end", bot.end_command),
CommandHandler("set_file_path", bot.echo_set_file_path),
CommandHandler("set_username", bot.echo_set_username),
CommandHandler("set_password", bot.echo_set_password),
CommandHandler("set_host", bot.echo_set_host),
MessageHandler(
filters.TEXT & ~filters.COMMAND,
bot.set_file_path_command,
),
MessageHandler(
filters.TEXT & ~filters.COMMAND,
bot.set_username_command,
),
MessageHandler(
filters.TEXT & ~filters.COMMAND,
bot.set_password_command,
),
MessageHandler(
filters.TEXT & ~filters.COMMAND,
bot.set_host_command,
),
]
)
application.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == "__main__":
main()
我尝试了一些代码,但它没有按照我想要的方式工作。
一旦您以文本形式发送用户名,您就会触发第一个
MessageHandler(filters.TEXT & ~filters.COMMAND, bot.set_file_path_command)
它将执行
set_file_path_command
。 python-telegram-bot 将按顺序处理处理程序并获取与传入消息匹配的第一个处理程序。在您的代码中,消息处理程序都匹配相同的输入,因此它只需要第一个。
您是否使用更复杂的过滤器或查看对话处理程序,例如https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot.py
使用 ConversationHandlers,您可以构建整个对话并处理对话中的不同状态。