Python Telegram API -- 如何使用 ForceReply?
Python Telegram API -- how do I use ForceReply?
我想在 python 中有一个小 Telegram 机器人,用户发出命令后,机器人会提出问题并根据答案做出反应。官方 Telegram API 提到可以使用 ForceReply(),例如如需逐步创建投票,请参阅此处 Official Telegram API # ForceReply。
我写了下面的代码:
def test_function(update: Update, context: CallbackContext) -> None:
msg = context.bot.send_message(chat_id=update.message.chat_id,
text="Please enter some text.",
reply_markup=telegram.ForceReply(True))
if __name__ == '__main__':
dispatcher.add_handler(CommandHandler("test", test_function))
updater.start_polling()
updater.idle()
所以当用户发出 /test
时,他被要求输入一些文本,并且由于 ForceReply(True)
,用户被迫回复消息。但是我如何得到这个回复的结果,即用户回复的文本呢? API 文档中没有任何提示,我也花了一些时间在互联网和 SO 上搜索,但没有找到任何东西。因此,很可能答案很简单明了,但我现在不明白。
感谢任何形式的帮助。
aiogram 框架已经解决了你的任务
每一步都是用户的一种状态。
它叫做 FSM
(finite state machine
)。
你甚至不需要用 ForceReply
做任何事情。
例子
import logging
import aiogram.utils.markdown as md
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters import Text
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.types import ParseMode
from aiogram.utils import executor
bot = Bot(token='your:token')
storage = MemoryStorage() # external storage is supported!
dp = Dispatcher(bot, storage=storage)
# Defining available states
class Form(StatesGroup):
name = State()
age = State()
gender = State()
@dp.message_handler(commands='start')
async def cmd_start(message: types.Message):
"""
Conversation's entry point
"""
# Set state
await Form.name.set()
await message.reply("Hi there! What's your name?")
# You can use state '*' if you need to handle all states
@dp.message_handler(state='*', commands='cancel')
@dp.message_handler(Text(equals='cancel', ignore_case=True), state='*')
async def cancel_handler(message: types.Message, state: FSMContext):
"""
Allow user to cancel any action
"""
current_state = await state.get_state()
if current_state is None:
return
# Cancel state and inform user about it
await state.finish()
# And remove keyboard (just in case)
await message.reply('Cancelled.', reply_markup=types.ReplyKeyboardRemove())
@dp.message_handler(state=Form.name)
async def process_name(message: types.Message, state: FSMContext):
"""
Process user name
"""
async with state.proxy() as data:
data['name'] = message.text
await Form.next()
await message.reply("How old are you?")
# Check age. Age gotta be digit
@dp.message_handler(lambda message: not message.text.isdigit(), state=Form.age)
async def process_age_invalid(message: types.Message):
"""
If age is invalid
"""
return await message.reply("Age gotta be a number.\nHow old are you? (digits only)")
@dp.message_handler(lambda message: message.text.isdigit(), state=Form.age)
async def process_age(message: types.Message, state: FSMContext):
# Update state and data
await Form.next()
await state.update_data(age=int(message.text))
# Configure ReplyKeyboardMarkup
markup = types.ReplyKeyboardMarkup(resize_keyboard=True, selective=True)
markup.add("Male", "Female")
markup.add("Other")
await message.reply("What is your gender?", reply_markup=markup)
@dp.message_handler(lambda message: message.text not in ["Male", "Female", "Other"], state=Form.gender)
async def process_gender_invalid(message: types.Message):
"""
In this example gender has to be one of: Male, Female, Other.
"""
return await message.reply("Bad gender name. Choose your gender from the keyboard.")
@dp.message_handler(state=Form.gender)
async def process_gender(message: types.Message, state: FSMContext):
async with state.proxy() as data:
data['gender'] = message.text
# Remove keyboard
markup = types.ReplyKeyboardRemove()
# And send message
await bot.send_message(
message.chat.id,
md.text(
md.text('Hi! Nice to meet you,', md.bold(data['name'])),
md.text('Age:', md.code(data['age'])),
md.text('Gender:', data['gender']),
sep='\n',
),
reply_markup=markup,
parse_mode=ParseMode.MARKDOWN,
)
# Finish conversation
await state.finish()
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)
我想在 python 中有一个小 Telegram 机器人,用户发出命令后,机器人会提出问题并根据答案做出反应。官方 Telegram API 提到可以使用 ForceReply(),例如如需逐步创建投票,请参阅此处 Official Telegram API # ForceReply。
我写了下面的代码:
def test_function(update: Update, context: CallbackContext) -> None:
msg = context.bot.send_message(chat_id=update.message.chat_id,
text="Please enter some text.",
reply_markup=telegram.ForceReply(True))
if __name__ == '__main__':
dispatcher.add_handler(CommandHandler("test", test_function))
updater.start_polling()
updater.idle()
所以当用户发出 /test
时,他被要求输入一些文本,并且由于 ForceReply(True)
,用户被迫回复消息。但是我如何得到这个回复的结果,即用户回复的文本呢? API 文档中没有任何提示,我也花了一些时间在互联网和 SO 上搜索,但没有找到任何东西。因此,很可能答案很简单明了,但我现在不明白。
感谢任何形式的帮助。
aiogram 框架已经解决了你的任务
每一步都是用户的一种状态。
它叫做 FSM
(finite state machine
)。
你甚至不需要用 ForceReply
做任何事情。
例子
import logging
import aiogram.utils.markdown as md
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters import Text
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.types import ParseMode
from aiogram.utils import executor
bot = Bot(token='your:token')
storage = MemoryStorage() # external storage is supported!
dp = Dispatcher(bot, storage=storage)
# Defining available states
class Form(StatesGroup):
name = State()
age = State()
gender = State()
@dp.message_handler(commands='start')
async def cmd_start(message: types.Message):
"""
Conversation's entry point
"""
# Set state
await Form.name.set()
await message.reply("Hi there! What's your name?")
# You can use state '*' if you need to handle all states
@dp.message_handler(state='*', commands='cancel')
@dp.message_handler(Text(equals='cancel', ignore_case=True), state='*')
async def cancel_handler(message: types.Message, state: FSMContext):
"""
Allow user to cancel any action
"""
current_state = await state.get_state()
if current_state is None:
return
# Cancel state and inform user about it
await state.finish()
# And remove keyboard (just in case)
await message.reply('Cancelled.', reply_markup=types.ReplyKeyboardRemove())
@dp.message_handler(state=Form.name)
async def process_name(message: types.Message, state: FSMContext):
"""
Process user name
"""
async with state.proxy() as data:
data['name'] = message.text
await Form.next()
await message.reply("How old are you?")
# Check age. Age gotta be digit
@dp.message_handler(lambda message: not message.text.isdigit(), state=Form.age)
async def process_age_invalid(message: types.Message):
"""
If age is invalid
"""
return await message.reply("Age gotta be a number.\nHow old are you? (digits only)")
@dp.message_handler(lambda message: message.text.isdigit(), state=Form.age)
async def process_age(message: types.Message, state: FSMContext):
# Update state and data
await Form.next()
await state.update_data(age=int(message.text))
# Configure ReplyKeyboardMarkup
markup = types.ReplyKeyboardMarkup(resize_keyboard=True, selective=True)
markup.add("Male", "Female")
markup.add("Other")
await message.reply("What is your gender?", reply_markup=markup)
@dp.message_handler(lambda message: message.text not in ["Male", "Female", "Other"], state=Form.gender)
async def process_gender_invalid(message: types.Message):
"""
In this example gender has to be one of: Male, Female, Other.
"""
return await message.reply("Bad gender name. Choose your gender from the keyboard.")
@dp.message_handler(state=Form.gender)
async def process_gender(message: types.Message, state: FSMContext):
async with state.proxy() as data:
data['gender'] = message.text
# Remove keyboard
markup = types.ReplyKeyboardRemove()
# And send message
await bot.send_message(
message.chat.id,
md.text(
md.text('Hi! Nice to meet you,', md.bold(data['name'])),
md.text('Age:', md.code(data['age'])),
md.text('Gender:', data['gender']),
sep='\n',
),
reply_markup=markup,
parse_mode=ParseMode.MARKDOWN,
)
# Finish conversation
await state.finish()
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)