bot-python icon indicating copy to clipboard operation
bot-python copied to clipboard

Проблема с фильтрами медиа при наличии подписей

Open SnipGhost opened this issue 5 months ago • 2 comments

Вероятно, нашел косяк в иерархии классов Filter. FileFilter отфильтровывает файлы/медиа с подписями (caption), т.к. VK Teams не возвращает поле text, если в сообщении в поле parts есть поле caption.

Возможные причины:

Так получается, потому что MessageFilter требует наличия поля text, от него наследуется FileFilter, а data/media-фильтры в свою очередь наследуются от него (ImageFilter/VideoFilter/AudioFilter → FileFilter → MessageFilter).

Что собственно и приводит к такому результату (первое сообщение ботом не обработалось): Image

Пример сниппета, который использовался для данной демонстрации:

from bot.bot import Bot
from bot.filter import Filter
from bot.handler import MessageHandler,

def download_cb(bot, event):
    chat_id = event.data['chat']['chatId']
    for p in event.data.get('parts', []):
        file_id = p['payload'].get('fileId')
        bot.send_text(chat_id=chat_id, text=f"File (ID: {file_id}) downloaded!")

if __name__ == "__main__":
    bot = Bot(token=TOKEN, name=NAME, version=VERSION, api_url_base=API_URL)
    bot.dispatcher.add_handler(MessageHandler(filters=Filter.file, callback=download_cb))
    bot.start_polling()
    bot.idle()

Первое сообщение (с подписью):

{
    'chat': {
        'chatId': '<REPLACED>',
        'type': 'private'
    },
    'from': {
        'firstName': 'Михаил', 'lastName': 'Кучеренко', 'userId': '<REPLACED>'
    },
    'msgId': '7535851623587774697',
    'parts': [
        {'payload': {'caption': 'test', 'fileId': 'kIZF0HRomMiAQgwbE4XESm6894b9201ai'}, 'type': 'file'}
    ],
    'timestamp': 1754577184
}

Второе сообщение (без подписи):

{
    'chat': {
        'chatId': '<REPLACED>',
        'type': 'private'
    },
    'from': {
        'firstName': 'Михаил', 'lastName': 'Кучеренко', 'userId': '<REPLACED>'
    },
    'msgId': '7535851988659994815',
    'parts': [
        {'payload': {'fileId': 'r7kYziEDN6elgM7t91Qp5f6894b9751ai'}, 'type': 'file'}
    ],
    'text': '<REPLACED>/get/r7kYziEDN6elgM7t91Qp5f6894b9751ai',
    'timestamp': 1754577269
}

Почему это плохо:

  • Приходится либо убирать фильтр из MessageHandler - что может ломать обработку других сообщений
  • Либо колхозить свой фильтр с наследованием от FilterBase и выстраиванием параллельной иерархии классов

Как можно исправить

Быстрое исправление - изменить MessageFilter так:

class MessageFilter(FilterBase):
    def filter(self, event):
        return ("text" in event.data and isinstance(event.data["text"], six.string_types)) or (
            "parts" in event.data and any(p.get("payload", {}).get("caption") for p in event.data["parts"])
        )

Что вроде бы логично (подписи тоже текст, который можно анализировать боту?), но может скрывать дополнительные проблемы, которые я просто пока не разглядел.

Однако, этот подход не сработал, вызова MessageFilter.filter на событие сообщения с подписью - просто не происходит. Ищу в чем дело. UPD: Подход сработал, но нашлась еще одна проблема, далее в комментариях рассмотрел.

SnipGhost avatar Aug 07 '25 17:08 SnipGhost