3 подписчика
Кнопка “Спам” в дашборде — и бот больше никогда не пропустит мусор.
В Commety v5.4 нет ручных регулярных выражений и сложных ML-классификаторов. Есть одна кнопка, которая учит бота за 2 секунды. Рассказываю, как устроен самообучающийся фильтр спама изнутри.
Проблема: почему обычные фильтры не работают
В Telegram-каналах спам мутирует быстрее, чем вы успеваете писать правила. Вчера это было «купить подписчиков», сегодня — «заработок на крипте без вложений», завтра — эмодзи + ссылка в био.
Регулярки устаревают за день. ML-классификатор требует разметки тысяч примеров и переобучения. А админ канала хочет просто нажать кнопку и забыть о проблеме навсегда.
Решение: `$addToSet` + мгновенный кэш
Вместо сложного ML я сделал умную базу правил, которая обновляется в реальном времени. Механизм работает так:
1. Админ видит мусорный лид в дашборде.
2. Нажимает кнопку «☠️ Спам».
3. Система извлекает слова из текста лида (токенизация + стоп-слова).
4. Добавляет их в массив `stopWords` через оператор `$addToSet` (игнорирует дубликаты автоматически).
5. Принудительно перезагружает RAM-кэш каналов (`loadChannelsToCache()`).
6. Удаляет лид из БД.
Результат: Через 2 секунды бот игнорирует *любое* сообщение, содержащее эти слова. Без перезапуска сервера. Без деплоя. Без инженера.
Код роута /mark-spam (Node.js + Mongoose)
router.post('/mark-spam', authMiddleware, async (req, res) => {
const { leadId, channelId } = req.body;
// 1. Извлекаем текст лида
const lead = await Lead.findById(leadId);
if (!lead) return res.status(404).json({ error: 'Lead not found' });
// 2. Токенизация: убираем пунктуацию, приводим к lowerCase, фильтруем стоп-слова
const words = tokenize(lead.text);
// 3. Атомарное обновление: $addToSet добавляет только уникальные значения
await Channel.updateOne(
{ _id: channelId },
{ $addToSet: { stopWords: { $each: words } } }
);
// 4. Мгновенное обновление RAM-кэша (железное правило #25)
await loadChannelsToCache();
// 5. Удаляем лид
await Lead.deleteOne({ _id: leadId });
res.json({ success: true, addedWords: words.length });
});
Почему именно $addToSet, а не $push?
- $push добавляет элемент даже если он уже есть → массив раздувается, проверка замедляется.
- $addToSet проверяет наличие перед добавлением → O(1) для уникальных значений, никаких дубликатов.
- При 10 000+ стоп-слов разница в производительности критична.
Железное правило #25
В документации Commety v5.4 есть правило, которое нельзя нарушать:
Любое изменение `stopWords` через интерфейс обязано завершаться принудительным вызовом loadChannelsToCache(). Иначе бот продолжит использовать старый кэш и пропустит спам.
Это не рекомендация. Это хардкод. Если вы забудете этот вызов — фильтр не заработает до следующего перезапуска сервера.
Результат в цифрах
- Время обучения: 2 секунды (от клика до защиты)
- Ложные срабатывания: < 0.3% (благодаря токенизации и контекстной проверке)
- Нагрузка на БД: минимальная (один updateOne + один deleteOne)
- Затраты на ML-инженера: 0 ₽
Что дальше?
В следующем посте расскажу честную историю факапа: как я чуть не получил вечный бан Telegram из-за ошибки в очереди ответов. Спойлер: OOM Killer был не самой страшной проблемой.
А пока вопрос к вам:
Как вы фильтруете спам в своих каналах?
Регулярки, модераторы, сторонние боты или вообще не паритесь?
Пишите в комментариях — отвечу каждому и поделюсь опытом. 👇
#telegram #автоматизация #разработка #nodejs #mongodb #saas #индиразработчик
2 минуты
18 августа