Перейти к содержанию

Бранчи

Бранчи — это удобная и быстрая short-term замена FSM, цепи событий, позволяющие делать всё: от тестов, анкет и опросов до чатов, обработчиков и т. п.

Инструкции по посадке

Импорты

В VKBottle представлены два вида бранчей: росток (sprout) и ветка (branch). Первый вид — росток — невероятно минималистичный и простой. Чтобы его использовать, импортируем следующие классы:

from vkbottle.branch import Branch, ExitBranch 

Чтобы использовать ветку, необходимо импортировать эти объекты:

from vkbottle.branch import ClsBranch, rule_disposal

Работаем с бранчами

Создание обработчика

Теперь создадим хендлер, в котором пользователь попадёт в нашу цепь:

@bot.on.message(text="хочу в бранч", lower=True)
async def wrapper(ans: Message):
    await ans("Теперь ты в бранче!")
    await bot.branch.add(ans.peer_id, "my_branch")

А сейчас приступим к написанию кода для нашего ростка:

@bot.branch.simple_branch("my_branch")
async def branch(ans: Message):
    if ans.text.lower() == "выйти":
        await ans("Окей, выхожу!")
        await bot.branch.exit(ans.peer_id)

    await ans("Ты в бранче. Пиши «выйти», чтобы выйти отсюда.")

Тоже самое можно провернуть и с ветками — более продвинутым инструментом:

@bot.branch.cls_branch("my_branch")
class Branch(ClsBranch):
    @rule_disposal(VBMLRule("выйти", lower=True))
    async def exit_branch(self, ans: Message):
        await ans("Окей, вывожу!")
        await bot.branch.exit(ans.peer_id)

    async def branch(self, ans: Message, *args):
        await ans("Ты в бранче. Пиши «выйти», чтобы выйти отсюда.")

Теперь, если пользователь напишет «Хочу в бранч», бот ответит ему «Теперь ты в бранче». В дальнейшем на любое сообщение пользователя поступит ответ «Ты в бранче. Пиши «выйти», чтобы выйти отсюда.», но если он напишет «Выйти», то цепочка разорвется.

Kwargs в бранчах

При инициализации бранча возможно передать все необходимые значения. Они будут переданы в хендлер бранча.

На примере ростков

@bot.on.message(text="ставлю боту <mark:int>", lower=True)
async def wrapper(ans: Message, mark):
    await ans("Теперь расскажи, что ты думаешь о нем:")
    await bot.branch.add(ans.peer_id, "my_branch", mark=mark)

@bot.branch.simple_branch("my_branch")
async def branch(ans: Message, mark):
    if ans.text.lower() in ["это все", "да"]:
        await ans(f"Окей, твоя оценка «{mark}» и рассказ о боте заcчитан!")
        await bot.branch.exit(ans.peer_id)

    await ans(f"Ты считаешь, что {ans.text}. Мы тебя поняли. Это все?")

На примере веток

from vkbottle.branch import ClsBranch, rule_disposal
from vkbottle.rule import VBMLRule

@bot.on.message(text="ставлю боту <mark:int>", lower=True)
async def wrapper(ans: Message, mark):
    await ans("Теперь расскажи, что ты думаешь о нем:")
    await bot.branch.add(ans.peer_id, "my_branch", mark=mark)

@bot.branch.cls_branch("my_branch")
class Branch(ClsBranch):
    @rule_disposal(VBMLRule(["это все", "да"], lower=True))
    async def exit_branch(self, ans: Message):
        await ans(f"Окей, твоя оценка «{self.context['mark']}» и рассказ о боте заcчитан!")
        await bot.branch.exit(ans.peer_id)

    async def branch(self, ans: Message, *args):
        await ans(f"Ты считаешь, что {ans.text}. Мы тебя поняли. Это все?")

Альтернативный синтаксис входа и выхода

Существует альтернативный return-синтаксис для входа/выхода из бранчей.

async def wrapper(ans: Message):
    # Для ввода пользователя в бранч
    return Branch("branch-name")

async def branch(ans: Message):
    # Для вывода пользователя из бранча
    return ExitBranch()

Другие способы хранения состояний

Существуют также другие виды хранения бранчей, один из них vkbottle.framework.framework.branch.database_branch.DatabaseBranch

Для того чтобы использовать его, требуется заполнить 4 метода абстрактного класса DatabaseBranch с помощью API вашего ORM. Пример вы можете найти здесь

Ключ проверки состояний

Данная фишка только для ботов и позволяет изменить стандартное поле хранения состояний то есть peer_id на from_id

from vkbottle.framework import BranchCheckupKey
bot.branch_checkup_key = BranchCheckupKey.FROM_ID
# ...
await bot.branch.add(message.from_id, "branch")