Пишем бота для «Отечественного WeChat» — Max на Python

Недавно VK сделал новый мессенджер - Max - который рекламируют как отечественный аналог WeChat. Пока что он немного сыроват, но в нём видно потенциал. Сегодня мы будем писать бота на Python для этого мессенджера.

Создаём бота

Для создания аккаунтов ботов есть специальный бот - @MasterBot. Переходим в него и нажимаем "Начать"

Команды MasterBot
Команды MasterBot

Дальше пишем /create, чтобы создать нового бота.

MasterBot предложит нам придумать уникальное имя пользователя для бота, которое должно быть больше 11 символов (да, не меньше) и должно заканчиваться на _bot или bot. Я назову своего бота @aiomax_test_bot.

Дальше пишем имя бота, которое будет отображаться в чатах и вверху диалога с ботом. Оно не должно быть уникальным. Я назову своего "Кликер бот"

Ник и имя бота
Ник и имя бота

Бюрократическая часть окончена! Копируем токен бота, который вам прислал MasterBot и переходим в редактор кода.

Скелет бота

Переходим в командную строку и пишем следующее:

pip install aiomax

В новом Python-файле пишем это:

import aiomax import logging

Библиотека logging нам понадобится для проверки, точно ли бот работает и получать от него вывод. Использовать её необязательно.

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

bot = aiomax.Bot("TOKEN", default_format="markdown")

Вместо TOKEN вставляем ваш токен.

default_format="markdown" устанавливает систему разметки Markdown сообщений по умолчанию. Если её не указать тут, то разметку (жирный, курсивный и все другие шрифты) использовать не получится.

В конец вашего файла пишем это:

if __name__ == "__main__": logging.basicConfig(level=logging.INFO) bot.run()

logging.basicConfig(level=logging.INFO) настраивает логгер для вывода нужной информации, а bot.run() запустит бота при запуске Python-файла.

Скелет готов! Приступаем к созданию самого бота.

Эхо-бот

Очень часто первые написанные боты делают эхо-ботами. И мы не будем исключением. Пишем вот этот код до блока if __name__ == "__main__":

# Отправка информации о боте при нажатии кнопки "Начать" в мессенджере @bot.on_bot_start() async def info(pd: aiomax.BotStartPayload): await pd.send("Я повторяю за тобой") # Функция будет выполняться при отправке любого сообщения @bot.on_message() async def echo(message: aiomax.Message): await message.send(message.content)

Давайте разберём код.

Декоратор @bot.on_bot_start() запускает функцию ниже него, когда кто-то запускает бота в мессенджере и передаёт функции параметр pd (Payload). У этого pd есть функция send, которая отправляет сообщение в чат тому, кто запустил бота.

Декоратор @bot.on_message() запускает функцию ниже него, когда кто-то отправляет сообщение в любой чат и передает функции параметр message (отправленное сообщение). У message есть функция send, которая отправляет сообщение в тот же чат, в который поступило сообщение, и параметр content, в котором содержится текст сообщения.

Вместо send в await message.send(message.content) можно написать reply - тогда вы не просто отправите сообщение в тот же чат, а ответите на поступившее сообщение.

Полный код бота, которого мы только что написали:

import aiomax import logging bot = aiomax.Bot("TOKEN", default_format="markdown") # Создаём бота и задаем ему систему разметки Markdown # При запуске бота должна быть информация о нём @bot.on_bot_start() async def info(pd: aiomax.BotStartPayload): await pd.send("Я повторяю за тобой") # Следующая функция должна выполняться при получении сообщения @bot.on_message() async def echo(message: aiomax.Message): await message.send(message.content) if __name__ == "__main__": # Уровень логирования logging.basicConfig(level=logging.INFO) # Запуск бота bot.run()

Запускаем Python-файл, пишем боту и видим, что всё работает!

Эхо бот
Эхо бот

Кликер-бот

А теперь напишем бота с кнопками у сообщений.

Есть глобальный счётчик. При нажатии пользователем на кнопку, этот счётчик будет увеличиваться для всех.

Для начала возьмём старый скелет и добавим туда функции:

import aiomax import logging bot = aiomax.Bot("TOKEN", default_format="markdown") taps = 0 # Создаём клавиатуру kb = aiomax.buttons.KeyboardBuilder() button = aiomax.buttons.CallbackButton('Нажми на меня!', 'click') kb.add(button) # Отправляем сообщение с информацией о боте при запуске @bot.on_bot_start() async def info(pd: aiomax.BotStartPayload): await pd.send(f"**Жми**!\nТапы: {taps}", keyboard=kb) # Отправляем сообщение с кнопкой при вводе команды /tap @bot.on_command('tap') async def tap_command(ctx: aiomax.CommandContext): await ctx.reply(f"**Жми!**\nТапы: {taps}", keyboard=kb) # Обрабатываем нажатие на кнопку в сообщении @bot.on_button_callback('click') async def on_tap(callback: aiomax.Callback): global taps # Делаем taps глобальной переменной, чтобы изменять её по всему боту taps += 1 await callback.answer(text=f"Жми!\nТапы: **{taps}**") if __name__ == "__main__": logging.basicConfig(level=logging.INFO) bot.run()

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

kb = aiomax.buttons.KeyboardBuilder() создаёт новую клавиатуру, которую мы будем прикреплять к сообщениям.

button = aiomax.buttons.CallbackButton('Нажми на меня!', 'click') создаёт новую кнопку с текстом "Нажми на меня!" и специальным пейлоадом click, по которому можно проверять, какая именно кнопка нажата.И наконец, kb.add(button) добавляет эту кнопку на нашу клавиатуру.

@bot.on_command('tap') создаёт новую команду с именем "tap".Наш декоратор on_command вызовется тогда, когда пользователь отправит боту /tap.

Вместо message декоратор on_command передаёт нам объект CommandContext, который отличается от Message, но точно также имеет функции send и reply.

Функция после @bot.on_button_callback('click') запускается при нажатии кнопки с указанным ожидаемым пейлоадом. Так как пейлоад у нашей кнопки - click, тут напишем также.Этот декоратор возвращает объект Callback, который уже отличается от прошлых on_command и on_message. В нём есть функция answer - она отвечает на нажатие кнопки определенным действием. В нашем случае мы просто поменяем текст сообщения на новый, который напишем после text=.

Будьте внимательны - если не указать text=, а просто написать строку, то текст сообщения не изменится. Вместо этого пользователю отправится уведомление, которые сейчас отображаются только на iPhone.

Запускаем файл, и видим, что бот работает как нужно!

FSM

Если захотелось, чтобы у каждого пользователя был свой отдельный счётчик, то можно использовать FSM.

import aiomax import logging from aiomax import fsm bot = aiomax.Bot("TOKEN", default_format="markdown") # Создаём клавиатуру kb = aiomax.buttons.KeyboardBuilder() button = aiomax.buttons.CallbackButton('Нажми на меня!', 'click') kb.add(button) # Отправляем сообщение с информацией о боте при запуске @bot.on_bot_start() async def info(pd: aiomax.BotStartPayload, cursor: fsm.FSMCursor): taps = cursor.get_data() if not taps: taps = 0 await pd.send(f"**Жми**!\nТапы: {taps}", keyboard=kb) # Отправляем сообщение с кнопкой при вводе команды /tap @bot.on_command('tap') async def tap_command(ctx: aiomax.CommandContext, cursor: fsm.FSMCursor): taps = cursor.get_data() if not taps: taps = 0 await ctx.reply(f"**Жми!**\nТапы: {taps}", keyboard=kb) # Обрабатываем нажатие на кнопку в сообщении @bot.on_button_callback('click') async def on_tap(callback: aiomax.Callback, cursor: fsm.FSMCursor): taps = cursor.get_data() if not taps: taps = 0 taps += 1 cursor.change_data(taps) await callback.answer(text=f"Жми!\nТапы: **{taps}**") if __name__ == "__main__": logging.basicConfig(level=logging.INFO) bot.run()

Можно сразу заметить, что taps сверху пропало, добавилось from aiomax import fsm и в каждой функции появились конструкции с cursor. Давайте рассмотрим.

Чтобы получить курсор пользователя в почти любом декораторе, в списках аргументов вашей функции можно добавить аргумент cursor - aiomax его увидит и передаст туда курсор. С помощью курсора можно менять состояние и данные определенного пользователя.

taps = cursor.get_data() получает данные, которые хранятся у пользователя в текущий момент.

if not taps: taps = 0 проверяет, хранятся ли какие-либо данные у пользователя - если нет, то сохраняет в переменной 0, дабы избежать ошибок.

cursor.change_data(taps) изменяет текущие хранящиеся данные пользователя на новые - в нашем случае новое количество нажатий.

Заключение

Если вы хотите подробнее ознакомиться с библиотекой aiomax, можете почитать документацию в репозитории проекта.

Обсудить aiomax или задать вопросы можно в чатах aiomax Community в Telegram или самом Max.

2
5 комментариев