Речь про беседы сообщества: бот добавлен в чат, ему выданы права администратора, а в настройках сообщества включены «Сообщения из бесед». Без этого ВК не пришлёт содержимое сообщений беседы.

Подключение сообщества описано в статье «Как создать чат-бота ВКонтакте».

Id беседы

vk_id (он же platform_id) — это peer_id: 2000000000 + номер беседы. Номер виден в адресной строке сообщества при открытой беседе. Первая беседа сообщества — 2000000001, вторая — 2000000002 и так далее.

Переменные, которые появляются сами

Заполняются на каждом событии беседы, настраивать их не нужно.

Переменная Что внутри Пример
vk_id, platform_id id беседы (peer_id) 2000000005
from_id id автора текущего сообщения 493121376652230668
conversation_message_id номер сообщения внутри беседы 142
reply_from_id id автора процитированного сообщения 413984787162726410
reply_text текст цитаты кто дежурит сегодня?
reply_cmid номер процитированного сообщения в беседе 139
reply_attachments вложения цитаты
message_from_outside 0 — сообщение человека, 3 — служебное событие 0
question текст входящего сообщения спасибо!
chat_member_id участник, которого касается служебное событие 413984787162726410
chat_action_by_self 1 — участник сделал это сам, 0 — его добавили или исключили 1
chat_action_text новое название беседы при её переименовании Общий чат

Группа reply_* заполняется, только когда сообщение является ответом на другое. На обычном сообщении они очищаются, поэтому проверка reply_from_id != '' надёжно отличает ответ от обычного сообщения.

from_id и reply_from_id есть только в беседах. В личной переписке с сообществом их нет — механики, завязанные на них, там просто не сработают.

Имён участников в переменных нет. name и full_name у клиента — это название беседы. Имя автора берётся отдельным вызовом:

#{vk_get_name(from_id)}

Три группы chat_member_id, chat_action_by_self, chat_action_text приходят только на служебных событиях беседы — см. следующий раздел.

События беседы

Кроме сообщений в воронку приходят служебные события. Их тип попадает в question, так что ловятся они обычным текстовым условием.

Текст в question Когда Кто в chat_member_id
chat_invite_user участника добавили в беседу кого добавили
chat_invite_user_by_link участник зашёл по ссылке-приглашению кто зашёл
chat_kick_user участник вышел или его исключили о ком речь
chat_title_update беседу переименовали кто переименовал
chat_pin_message сообщение закрепили кто закрепил
chat_unpin_message сообщение открепили кто открепил
chat_photo_update, chat_photo_remove сменили или убрали аватар беседы кто сменил

У chat_kick_user различить «вышел сам» и «исключили» помогает chat_action_by_self: 1 — ушёл сам, 0 — исключил кто-то другой (его id лежит в from_id).

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

message_from_outside == '0'

Это отсечёт все служебные события разом — надёжнее, чем перечислять их тексты: участник может написать chat_invite_user руками. Кавычки вокруг '0' обязательны.

Сообщения

Функция Что делает
vk_send_message(peer_id, text) написать в беседу или личку
vk_edit_message(peer_id, message_id, text) изменить своё сообщение
vk_delete_messages(peer_id, cmids) удалить сообщения беседы
vk_pin_message(peer_id, conversation_message_id) закрепить
vk_unpin_message(peer_id) открепить
vk_send_chat_action(peer_id, action) показать «печатает»: typing или audiomessage
vk_send_sticker(peer_id, sticker_id) отправить стикер

Удалять и редактировать ВК разрешает только сообщения не старше суток. В vk_delete_messages для беседы передаётся номер сообщения внутри беседы — conversation_message_id, он же лежит в одноимённой переменной:

vk_delete_messages(vk_id, conversation_message_id)

Сообщение, отправленное через vk_send_message, уходит в беседу, но не попадает в историю диалога в кабинете — там видны только ответы самого блока.

Участники

Функция Что делает
vk_get_name(user_id, full) имя участника; со вторым аргументом true — имя и фамилия
vk_is_admin(peer_id, user_id) 1 — администратор беседы, 0 — обычный участник
vk_remove_chat_user(user_id) исключить из беседы
vk_get_chat_member_count(peer_id) сколько человек в беседе
vk_export_chat_link(peer_id, new) ссылка-приглашение; со вторым аргументом true старая ссылка сбрасывается

vk_is_admin возвращает число, поэтому его можно сравнивать прямо в условии блока:

vk_id == 2000000005 and vk_is_admin(vk_id, from_id) == 0

Такое условие — типичный «гейт админов»: блок модерации не тронет администраторов беседы. При любой ошибке (беседа недоступна, у бота нет прав) функция вернёт 0, то есть модерация продолжит работать, а не отключится.

Исключить администратора беседы бот не сможет — это ограничение ВКонтакте.

Очки и рейтинг

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

Функция Что делает
vk_add_thanks_score(value) начислить очки автору цитируемого сообщения
vk_add_thanks_score_for_answer(value) начислить тому, кто ответил
vk_minus_thanks_score(value) снять очки; со значением 0 обнуляет
vk_get_score(user_id) очки участника числом; без аргумента — автор события
vk_get_level(user_id, points_per_level) уровень участника; порог по умолчанию 100 очков
vk_get_user_info(user_id) очки, место в рейтинге и имя одним объектом
vk_get_top(count, shift, delimiter, humanize) лидерборд
vk_get_user_link() упоминание автора цитаты вида [id123
vk_mark_ban_user(), vk_mark_unban_user() исключить автора цитаты из начислений и вернуть обратно

У vk_get_top аргумент count — сколько строк вывести, shift — со скольких пропустить (для листания), delimiter — чем разделять имя и очки, humanize по умолчанию true и возвращает готовый текст с кликабельными упоминаниями. Со значением false вернётся список объектов — если лидерборд рисуется своей разметкой.

Порядок аргументов у vk_get_top отличается от дискордового и максового: там третьим идёт humanize, а здесь delimiter. Так сделано, чтобы не сломать воронки, написанные до появления humanize.

В условии блока очки надо сравнивать через vk_get_score — эта функция возвращает число, с которым сравнение работает как ожидается. get(vk_get_user_info(), 'score') отдаёт строку, и сравнение с числом внутри одного выражения молча не сработает.

Очки беседы ВК хранятся в переменной проекта vk_thanks_score_data, отдельно от телеграмных, дискордовых и максовых — в проекте с несколькими каналами лидерборды не смешиваются.

Примеры

Приветствие новичка

Условие блока — chat_invite_user, текст ответа:

Привет, #{vk_get_name(chat_member_id)}! Загляни в закреплённые правила 👋

Удалить сообщение со стоп-словом, кроме админов

Условие — список стоп-слов, дополнительное условие:

vk_id == 2000000005 and message_from_outside == '0' and vk_is_admin(vk_id, from_id) == 0

В поле переменных:

vk_delete_messages(vk_id, conversation_message_id)

vk_send_message(vk_id, '⚠️ #{vk_get_name(from_id)}, сообщение удалено: запрещённое слово.')

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

Условие — слова спасибо;спс;благодарю, дополнительное условие:

vk_id == 2000000005 and message_from_outside == '0' and reply_from_id != '' and reply_from_id != from_id

В поле переменных:

now = int(float(timestamp))

last_map = if(gm_xp_last == None, {}, gm_xp_last)

last = last_map[from_id]

last = if(last == None, 0, last)

if (now - last >= 60) {

  vk_add_thanks_score(1)

  last_map[from_id] = now

  project.gm_xp_last = last_map

  lvl = vk_get_level(reply_from_id, 100)

  granted_map = if(gm_lvl == None, {}, gm_lvl)

  granted = granted_map[reply_from_id]

  granted = if(granted == None, 0, granted)

  if (lvl > granted) {

    vk_send_message(vk_id, '#{vk_get_name(reply_from_id)} вышел на уровень #{lvl} 🎉')

    granted_map[reply_from_id] = lvl

    project.gm_lvl = granted_map

  }

}

reply_from_id != from_id не даёт начислять очки самому себе, а словарь gm_xp_last держит кулдаун в 60 секунд на каждого дающего.

Обратите внимание: поздравление считается по получателю очков (reply_from_id), а не по автору сообщения, и отправляется в том же блоке. На одно входящее сообщение срабатывает только один блок воронки, поэтому вынести награду в отдельный блок нельзя — он не получит управление.

Показать свои очки по команде

Условие — /xp, поле переменных:

points = vk_get_score()

lvl = vk_get_level()

place = get(vk_get_user_info(), 'place')

Текст ответа:

#{vk_get_name(from_id)}, у тебя #{points} XP · уровень #{lvl} · место #{place}

Лидерборд по команде

Условие — /top, поле переменных:

top = vk_get_top(10, 0, ' — ')

top = if(top == '', 'Пока никто не заработал XP', top)

Текст ответа:

🏆 Топ по XP:

#{top}