Обработчики и фильтры

vk-bot предоставляет декораторы для обработки различных событий: сообщений, нажатий на inline-кнопки и middleware-прослоек. Каждый декоратор принимает набор фильтров, определяющих, какие события будет обрабатывать функция.

Обработчики сообщений

Декоратор @bot.message_handler() регистрирует функцию для обработки входящих сообщений. Без фильтров обработчик срабатывает на все сообщения.

@bot.message_handler()
def handle_all(message: types.Message):
    bot.send_message(message.from_id, f"Получено: {message.text}")

Важно

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

Фильтр commands

Реагирует на команды вида /start, /help, и т.д. Слэш в начале не указывается:

@bot.message_handler(commands=["start", "help"])
def handle_commands(message: types.Message):
    bot.send_message(message.from_id, "Добро пожаловать!")

Чтобы получить аргументы команды, используйте утилиту extract_command:

from vk_bot.handlers import extract_command

@bot.message_handler(commands=["echo"])
def handle_echo(message: types.Message):
    cmd, args = extract_command(message.text)
    bot.send_message(message.from_id, args or "Нет аргументов")

# Сообщение "/echo привет мир" → args = "привет мир"

Фильтр regexp

Срабатывает при совпадении текста сообщения с регулярным выражением:

@bot.message_handler(regexp=r"привет|здравствуй")
def handle_greeting(message: types.Message):
    bot.send_message(message.from_id, "Привет!")

Фильтр func

Произвольная функция-предикат, принимающая Message и возвращающая bool:

@bot.message_handler(func=lambda m: m.text and m.text.startswith("!"))
def handle_exclamation(message: types.Message):
    bot.send_message(message.from_id, "Обнаружена команда с '!'")

# Пример с именованной функцией
def is_admin(message: types.Message) -> bool:
    return message.from_id in [123456, 789012]

@bot.message_handler(func=is_admin)
def handle_admin(message: types.Message):
    bot.send_message(message.from_id, "Вы администратор")

Фильтр content_types

Фильтрация по типу содержимого сообщения:

@bot.message_handler(content_types=["photo"])
def handle_photo(message: types.Message):
    photos = message.get_photos()
    bot.send_message(message.from_id, f"Получено {len(photos)} фото")

@bot.message_handler(content_types=["doc"])
def handle_doc(message: types.Message):
    docs = message.get_documents()
    bot.send_message(message.from_id, f"Документ: {docs[0].title}")

Доступные типы содержимого:

  • text - текстовое сообщение

  • photo - фотография

  • doc - документ

  • video - видео

  • audio - аудио

  • sticker - стикер

  • wall - запись со стены

Фильтр chat_types

Ограничивает обработчик определёнными типами чатов:

@bot.message_handler(chat_types=["private"])
def handle_private(message: types.Message):
    bot.send_message(message.from_id, "Это личное сообщение")

@bot.message_handler(chat_types=["group"])
def handle_group(message: types.Message):
    bot.send_message(message.peer_id, "Сообщение из беседы")

Фильтр state

Срабатывает только когда пользователь находится в определённом состоянии FSM:

from vk_bot.state.group import StatesGroup
from vk_bot.state.manager import State

class Form(StatesGroup):
    waiting_name = State()
    waiting_age = State()

@bot.message_handler(state=Form.waiting_name)
def handle_name(message: types.Message, state: StateContext):
    state.update(name=message.text)
    state.set(Form.waiting_age)
    bot.send_message(message.from_id, "Сколько вам лет?")

Совет

Когда обработчик принимает второй аргумент state: StateContext, библиотека автоматически передаёт контекст состояния пользователя.

Можно указать несколько состояний списком:

@bot.message_handler(state=[Form.waiting_name, Form.waiting_age])
def handle_any_form_step(message: types.Message, state: StateContext):
    ...

Комбинирование фильтров

Фильтры комбинируются через логическое И - все условия должны совпасть:

@bot.message_handler(
    content_types=["text"],
    chat_types=["private"],
    func=lambda m: len(m.text or "") > 10,
)
def handle_long_private_text(message: types.Message):
    bot.send_message(message.from_id, "Длинное сообщение!")

Обработчики callback-запросов

Декоратор @bot.callback_query_handler() обрабатывает нажатия на inline-кнопки:

@bot.callback_query_handler(data="confirm")
def handle_confirm(callback: types.CallbackQuery):
    bot.answer_callback_query(
        callback_query_id=callback.id,
        user_id=callback.from_id,
        peer_id=callback.peer_id,
        text="Подтверждено!",
    )

Фильтр data

Может быть строкой (точное совпадение) или регулярным выражением:

import re

# Точное совпадение
@bot.callback_query_handler(data="btn_like")
def on_like(callback: types.CallbackQuery):
    ...

# Регулярное выражение
@bot.callback_query_handler(data=re.compile(r"^page_\d+$"))
def on_page(callback: types.CallbackQuery):
    page = callback.data.split("_")[1]
    ...

Фильтр func

Произвольная функция-предикат:

@bot.callback_query_handler(func=lambda cb: cb.from_id == 12345)
def on_admin_callback(callback: types.CallbackQuery):
    ...

Фильтр state

Аналогичен фильтру состояния для сообщений:

@bot.callback_query_handler(data="next_step", state=Form.waiting_confirm)
def on_confirm(callback: types.CallbackQuery, state: StateContext):
    state.finish()
    bot.answer_callback_query(
        callback.id, callback.from_id, callback.peer_id,
        text="Готово!",
    )

Middleware

Middleware - функции, которые выполняются до обработчиков. Если middleware возвращает False, обработка события прекращается.

@bot.middleware_handler()
def log_all_events(bot_instance, update: types.Update):
    print(f"Событие: {update.type}")
    # Не возвращаем False - обработка продолжится

@bot.middleware_handler(update_types=["message_new"])
def check_ban_list(bot_instance, update: types.Update):
    if update.message and update.message.from_id in BANNED_USERS:
        return False  # Блокируем обработку

Параметр update_types

Ограничивает middleware определёнными типами событий. Если не указан - middleware срабатывает на все события:

@bot.middleware_handler(update_types=["message_new", "message_event"])
def only_messages(bot_instance, update: types.Update):
    print("Только сообщения и callback-события")

Вспомогательные функции

Модуль vk_bot.handlers предоставляет утилиты для работы с текстом сообщений:

from vk_bot.handlers import extract_command, extract_mentions, is_group_event

# Парсинг команд
cmd, args = extract_command("/start hello world")
# cmd = "start", args = "hello world"

cmd, args = extract_command("просто текст")
# cmd = None, args = None

# Извлечение упоминаний
user_ids = extract_mentions("Привет [id123|Иван] и @id456")
# user_ids = [123, 456]

# Проверка группового события
is_group_event("group_join")   # True
is_group_event("message_new")  # False