Cat

AIOgram3 14. Фильтруем запрещённые слова

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

Все статьи

Icon Link

Дополнительные материалы

Icon Link

Реклама

Icon Link
Telegram-бот на AIOgram3 proDream 05 Октябрь 2023 Просмотров: 2336

Следующей задачей для бота является фильтрация сообщений от запрещённый слов.

Задача не самая сложная, но есть пара нюансов.

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

Решение будет следующим:

  • Пользовательское сообщение проверяется на наличие слова в нём
  • В случае нахождения, создаётся копия сообщения
  • Затем из копии удаляются / заменяются на звёздочки / модифицируются слова. Тут уже зависит от того, какой результат вы хотите получить. В моём случае слова будут заменяться на звёздочки.
  • Далее удаляется оригинальное сообщение и от имени бота отправляется новое, содержащее имя отправителя и отредактированное сообщение.

 

Второй - сложность алгоритма и затрачиваемые ресурсы.
В используемом списке бранных слов насчитывается свыше 1000 слов.
Сообщение от пользователя очищается от пунктуации и разделяется на множество (set) слов.
При большом потоке сообщений, это может сильно увеличить нагрузку на сервер и замедлить работу бота.
Я опишу уже улучшенный вариант, к которому мы пришли с подписчиком @rusheslav после тестирования фильтра в чате, но если у вас есть комментарии или рекомендации по улучшению кода, буду рад!

 

Множество запрещённых слов.

Использовать будем готовый список: https://github.com/bars38/Russian_ban_words
Вы можете составить свой или найти другой.

Скачиваем файл words.txt. Для большей наглядности, я его переименовал в ban_words.txt.

В корне проекта создаём директорию res и помещаем туда файл.

Открываем файл settings.py и в начале, после импортов создаём константу BAN_WORDS.
В этой константе создаётся множество из слов в файле.

BAN_WORDS = set(line.strip() for line in open('res/ban_words.txt'))

 

Фильтрующая функция.

В пакете handlers создадим новый файл filter_words.py.

Создаём асинхронную функцию check_message, принимающую message.

 

Код функции:

import string

from aiogram.types import Message

from botlogic import views
from botlogic.settings import BAN_WORDS, logger


async def check_message(message: Message):
    contains_ban_word = False

    if message.text:
        message_words = set(message.text.translate(str.maketrans('', '', string.punctuation)).split())
        filtered_message = message.text
        for word in message_words:
            if word.lower() in BAN_WORDS:
                filtered_message = filtered_message.replace(word, "*" * len(word))
                contains_ban_word = True

    if contains_ban_word:
        await message.delete()
        logger.info(f"Удалено сообщение от пользователя {message.from_user.username}: {message.text}")
        await message.answer_sticker('CAACAgIAAxkBAAEKbW1lGVW1I6zFVLyovwo2rSgIt1l35QADJQACYp0ISWYMy8-mubjIMAQ')
        await message.answer(views.filtered_message(message.from_user.username, filtered_message))

 

По ходу действий:

Создаём переменную contains_ban_word. Это "флаг", по умолчанию считаем, что в сообщении нет запрещённых слов.
После проверки на наличие сообщения создаём переменную message_words, в которой создаём множество очищенных от пунктуации слов. Множество не позволяет хранить в себе два одинаковых объекта, тем самым в переменной будут только уникальные слова. И переменную filtered_message, в которую помещаем копию сообщения.

Далее проходимся циклом for по множеству слов из сообщения.
Если слово есть среди запрещённых, заменяем его на звёздочки в количестве длинны слова и выставляем "флаг" о наличии в тексте запрещённых слов.

Далее проверка "флага", если переменная contains_ban_word по-прежнему в изначальном состоянии False, то бот ничего не делает. 
В противном случае бот сперва удаляет исходное сообщение. Записывает сообщение и информацию от кого в лог файл. 

Затем отправляет стикер по его идентификатору.

 

После чего отправляет сообщение с исправленным текстом.

 

Как получить идентификатор стикера.

Для получения идентификатора стикера, достаточно отправить боту https://t.me/idstickerbot стикер, идентификатор которого хотите получить. 
В ответ он пришлёт идентификатор. 
Готово.

 

Завершение.

Осталось только зарегистрировать обработчик. Добавляем в файл main.py следующую строку: dp.message.register(check_message). Отсутствие второго аргумента означает, что бот будет обрабатывать все сообщения.

Готово. Теперь бот фильтрует нежелательные слова в сообщениях. Конечно это не панацея и мы все знаем, как можно исхитриться в Русском языке, но основную часть отсеивать будет. А потом просто добавляем слова.

Пост на сайте.
Поддержать канал.

 

Дополнительно: Изменение логгера.

Изначально логгер находился в файле main.py и не записывал никуда события, только отображал в терминале.

Вынес логгер в файл settings.py. Определил два обработчика, для терминала и для файла.

 

Код нового логгера:

# Логгер  
logger = logging.getLogger()  
logger.setLevel(logging.INFO)  
formatter = logging.Formatter(  
    "%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s")  

console_handler = logging.StreamHandler()  
console_handler.setLevel(logging.INFO)  
console_handler.setFormatter(formatter)  

file_handler = logging.FileHandler("logs.txt")  
file_handler.setLevel(logging.INFO)  
file_handler.setFormatter(formatter)  

logger.addHandler(console_handler)  
logger.addHandler(file_handler)

 

Автор

    Нет комментариев

    Реклама