Skip to content

FSM (Конечные автоматы)

lxstvayne edited this page Nov 20, 2021 · 1 revision

Если вашему боту необходима система диалогов, то в дело вступают конечные автоматы. Это некая математическая модель, которая представляет собой набор конечных состояний, которые переключаются в определённых условиях. В библиотеке это реализовано с помощью классов:

from vk_maria.longpoll.fsm import StatesGroup, State, MemoryStorage, FSMContext


class Form(StatesGroup):
    waiting_for_name: State
    waiting_for_age: State
    waiting_for_gender: State

Необходимо описать в классе переменные состояний.

Чтобы имелась возможность запоминать текущие состояния для диалогов всех пользователей, в класс LongPoll необходимо передать экземпляр хранилища состояний.

lp = LongPoll(vk, MemoryStorage())

Пример работы конечных автоматов:

@lp.message_handler(commands=['/start'])
def cmd_start(event: types.Message):
    Form.waiting_for_name.set()
    event.reply("Hi there! What's your name?")


@lp.message_handler(state=Form.waiting_for_name)
def process_name(event: types.Message, state: FSMContext):
    state.update_data(name=event.message.text)
    Form.next()
    event.reply("How old are you?")


@lp.message_handler(state=Form.waiting_for_age)
def process_age(event: types.Message, state: FSMContext):
    Form.next()
    state.update_data(age=event.message.text)

    markup = KeyboardMarkup(one_time=True)
    markup.add_button(Button.Text(Color.PRIMARY, 'Male'))
    markup.add_button(Button.Text(Color.PRIMARY, 'Female'))
    markup.add_button(Button.Text(Color.PRIMARY, 'Other'))

    event.reply('What is your gender?', keyboard=markup)


@lp.message_handler(state=Form.waiting_for_gender)
def process_gender(event: types.Message, state: FSMContext):
    state.update_data(gender=event.message.text)
    user_data = state.get_data()
    event.answer(f'Hi! Nice to meet you, {user_data["name"]}\n'
                 f'Age: {user_data["age"]}\n'
                 f'Gender: {user_data["gender"]}')
    Form.finish()


lp.polling()

Чтобы каждый раз не писать

state = FSMContext.get_current()

Можно передавать второй аргумент в функцию обработчик.

@lp.message_handler(state=Form.waiting_for_gender)
def process_gender(event: types.Message, state: FSMContext):

Чтобы отлавливать состояние, передаётся аргумент state для message_handler:

@lp.message_handler(state=Form.waiting_for_gender)