Найти в Дзене
Записки сисадмина

Python. MAX бот. Кнопки и клавиатуры ч1. Диалог с пользователем.

Прошлый раз, когда я сел разбираться с api telegram, мне еще целый год подряд пришлось писать различных ботов для автоматизации своей рутины. Не то, чтобы мне это не нравилось, но некоторые флешбеки накатывают. По этой теме у меня на канале есть куча статей, при желании можете ознакомиться. А пока что возвращаемся к нашему мессенджеру MAX. В прошлых статьях мы создали первого бота и научились отправлять сообщения (да еще и с вложениями). Настало время разбираться с кнопками, клавиатурами и учиться вести диалог с пользователями. По данной теме будет точно несколько постов, т.к. в один это слишком сложно уложить. Для использования клавиатур и кнопок импортируем дополнительно модули: from maxapi.types import LinkButton, CallbackButton, MessageCallback, MessageButton
from maxapi.utils.inline_keyboard import InlineKeyboardBuilder Также дополнительно импортируем модуль F для реализации фильтров текстовых сообщений (MagicFilter) from maxapi import Bot, Dispatcher, F Данные модули дадут нам ба
Оглавление

Прошлый раз, когда я сел разбираться с api telegram, мне еще целый год подряд пришлось писать различных ботов для автоматизации своей рутины. Не то, чтобы мне это не нравилось, но некоторые флешбеки накатывают. По этой теме у меня на канале есть куча статей, при желании можете ознакомиться.

А пока что возвращаемся к нашему мессенджеру MAX. В прошлых статьях мы создали первого бота и научились отправлять сообщения (да еще и с вложениями).

Настало время разбираться с кнопками, клавиатурами и учиться вести диалог с пользователями.

По данной теме будет точно несколько постов, т.к. в один это слишком сложно уложить.

Начнем

Для использования клавиатур и кнопок импортируем дополнительно модули:

from maxapi.types import LinkButton, CallbackButton, MessageCallback, MessageButton
from maxapi.utils.inline_keyboard import InlineKeyboardBuilder

Также дополнительно импортируем модуль F для реализации фильтров текстовых сообщений (MagicFilter)

from maxapi import Bot, Dispatcher, F

Данные модули дадут нам базовый функционал кнопок. Принцип работы с Inline и Reply кнопками тот же, что и в telegram.

В нашем случае:

MessageButton - Кнопка, генерирующая текст у пользователя.

MessageButton(text='Текст кнопки')

CallbackButton - Кнопка, генерирующая callback (для обработки внутри бота).

CallbackButton(text='Текст кнопки', payload='callback данные')

LinkButton - Кнопка с встроенной ссылкой.

LinkButton(text='Текст кнопки', url='URL сайта')

Как предисловие уточним главное правило: если мы создаем кнопку с каким-то событием, мы обязаны написать обработчик этого события.

Текстовые кнопки

Создадим обработчик команды /test, который будет выдавать пользователю сообщение с двумя кнопками "Да" и "Нет".

-2
@dp.message_created(Command('test'))
async def test_message(event: MessageCreated):
reply_kb = InlineKeyboardBuilder()
reply_kb.row(MessageButton(text='Да'),
MessageButton(text='Нет'))
await bot.send_message(user_id=event.from_user.user_id, text='Текстовое сообщение с кнопками',
attachments=[reply_kb.as_markup()])

reply_kb = InlineKeyboardBuilder() - cоздаст клавиатуру

reply_kb.row(MessageButton(text='Да'), MessageButton(text='Нет')) - добавит в клавиатуру две кнопки.

При нажатии на каждую из этих кнопок, в чат будет отправляться сообщение с текстом данной кнопки:

-3

Однако, у нас пока что нет никакого обработчика для данных сообщений, т.к. они по своей сути являются просто текстом:

-4

Создаем обработчик текстовых кнопок

Тут нам и пригодится MagicFilter. Создадим обработку входящих текстовых сообщений:

-5

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

-6

Проблема в том, что данная функция будет реагировать абсолютно на все текстовые сообщения.

Для этого мы можем в декораторе фильтровать получаемый текст:

-7
-8

Мы видим, что бот теперь реагирует только на тот текст, на который настроен обработчик.

Однако, так делать не стоит.

Текстовые кнопки созданы для того, чтобы вести последовательный диалог с пользователем.

Создаем обработку диалога

Для начала подгружаем модули для проверки контекста пользователя:

from maxapi.context import MemoryContext, StatesGroup, State

Заранее оговариваем, что пользователь должен будет сделать два последовательных выбора.

Для этого создаем класс диалога:

-9
class DialogForm(StatesGroup):
first_choice = State()
second_choice = State()

Дописываем обработчик команды /test

-10

context.set_state(DialogForm.first_choice) - команда, которая посчитает следующее сообщение пользователя командой к заполнению поля first_choice в классе диалога.

Создаем обработчик, который будет реагировать только тогда, когда вызвано заполнение DialogForm.first_choice

-11

context.update_data(first_choice=event.message.body.text) - команда запишет текст из сообщения пользователя в поле first_choice

context.set_state(DialogForm.second_choice) - команда, которая передаст сообщение в обработчик DialogForm.second_choice

Создаем обработчик, который будет реагировать только тогда, когда вызвано заполнение DialogForm.second_choice

-12

context.update_data(second_choice=event.message.body.text) - команда запишет текст из сообщения пользователя в поле second_choice

data = await context.get_data() - команда, которая передаст весь контекст в переменную.

Весь контекст будет выглядеть как словарь:

{'first_choice': 'Да', 'second_choice': 'Нет'}
-13

Осталось дело за малым: После обработки всех сообщений от пользователя, нам нужно очищать контекст, чтобы в дальнейшем не было проблем.

Для этого есть команда context.clear()

Данная команда записывает None в контекст, поэтому при следующем взаимодействии пользователя с ботом, контекст будет наполняться с нуля.

Проверяем:

-14
-15

Как мы понимаем, для ведения диалога, не обязательно использовать кнопки. Можно просить пользователя печатать сообщения самому. В остальном, логика взаимодействия останется той же.

Код из статьи выложил здесь