Discourse AI - NSFW

:bookmark: Эта тема посвящена настройке функции NSFW (Not Safe For Work) плагина Discourse AI.



:person_raising_hand: Требуемый уровень пользователя: Администратор

Модули NSFW могут автоматически определять уровень NSFW для каждой новой загруженной картинки в постах и сообщениях чата вашего экземпляра Discourse. Эта система помогает выявлять и управлять контентом, который может быть неуместным или откровенным для профессиональной или публичной среды.

Вы также можете включить автоматическую маркировку контента, превышающего установленный порог.

Настройки

  • ai_nsfw_detection_enabled: Включает или отключает модуль

  • ai_nsfw_inference_service_api_endpoint: URL-адрес, где работает API для модуля. Если вы используете хостинг от CDCK, это настраивается автоматически. Если вы размещаете систему самостоятельно, ознакомьтесь с руководством по самостоятельному размещению.

  • ai_nsfw_inference_service_api_key: Ключ API для настроенного выше API. Если вы используете хостинг от CDCK, это настраивается автоматически. Если вы размещаете систему самостоятельно, ознакомьтесь с руководством по самостоятельному размещению.

  • ai_nsfw_models: Модель, которую мы будем использовать для классификации изображений. Мы предлагаем две различные модели со своими пороговыми значениями:

    • opennsfw2 возвращает один показатель от 0.0 до 1.0. Установите порог, при превышении которого загрузка будет считаться NSFW, через параметр ai_nsfw_flag_threshold_general.
    • nsfw_detector возвращает показатели для четырёх категорий: drawings (рисунки), hentai, porn (порнография) и sexy. Установите порог для каждой категории через соответствующий параметр ai_nsfw_flag_threshold_${category}. Если общий порог ниже любого из них, контент будет считаться NSFW.
  • ai_nsfw_flag_automatically: Автоматически помечать посты и сообщения чата, превышающие настроенные пороги. Если эта настройка отключена, мы только сохраняем результаты классификации в базе данных.

Дополнительные ресурсы

11 лайков

Спасибо.

Я столкнулся с этой проблемой при использовании сервиса nsfw после загрузки изображения. Я использую S3 для хранения изображений, если это имеет значение.

INFO:     10.0.2.145:23412 - "POST /api/v1/classify HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/anyio/streams/memory.py", line 94, in receive
    return self.receive_nowait()
  File "/usr/local/lib/python3.9/dist-packages/anyio/streams/memory.py", line 89, in receive_nowait
    raise WouldBlock
anyio.WouldBlock

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/base.py", line 77, in call_next
    message = await recv_stream.receive()
  File "/usr/local/lib/python3.9/dist-packages/anyio/streams/memory.py", line 114, in receive
    raise EndOfStream
anyio.EndOfStream

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/uvicorn/protocols/http/h11_impl.py", line 404, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/usr/local/lib/python3.9/dist-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/applications.py", line 124, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.9/dist-packages/starlette_exporter/middleware.py", line 289, in __call__
    await self.app(scope, receive, wrapped_send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/cors.py", line 84, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/base.py", line 106, in __call__
    response = await self.dispatch_func(request, call_next)
  File "./app.py", line 49, in dispatch
    response = await call_next(request)
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/base.py", line 80, in call_next
    raise app_exc
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/base.py", line 69, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.9/dist-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "./app.py", line 79, in classify
    results = models[parsed_params.model](tfile)
  File "/usr/local/lib/python3.9/dist-packages/opennsfw2/_inference.py", line 31, in predict_image
    pil_image = Image.open(image_path)
  File "/usr/local/lib/python3.9/dist-packages/PIL/Image.py", line 3283, in open
    raise UnidentifiedImageError(msg)
PIL.UnidentifiedImageError: cannot identify image file '/tmp/tmpbqq82655'
ERROR:uvicorn.error:Exception in ASGI application
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/anyio/streams/memory.py", line 94, in receive
    return self.receive_nowait()
  File "/usr/local/lib/python3.9/dist-packages/anyio/streams/memory.py", line 89, in receive_nowait
    raise WouldBlock
anyio.WouldBlock

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/base.py", line 77, in call_next
    message = await recv_stream.receive()
  File "/usr/local/lib/python3.9/dist-packages/anyio/streams/memory.py", line 114, in receive
    raise EndOfStream
anyio.EndOfStream

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/uvicorn/protocols/http/h11_impl.py", line 404, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/usr/local/lib/python3.9/dist-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/applications.py", line 124, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.9/dist-packages/starlette_exporter/middleware.py", line 289, in __call__
    await self.app(scope, receive, wrapped_send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/cors.py", line 84, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/base.py", line 106, in __call__
    response = await self.dispatch_func(request, call_next)
  File "./app.py", line 49, in dispatch
    response = await call_next(request)
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/base.py", line 80, in call_next
    raise app_exc
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/base.py", line 69, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/usr/local/lib/python3.9/dist-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.9/dist-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.9/dist-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "./app.py", line 79, in classify
    results = models[parsed_params.model](tfile)
  File "/usr/local/lib/python3.9/dist-packages/opennsfw2/_inference.py", line 31, in predict_image
    pil_image = Image.open(image_path)
  File "/usr/local/lib/python3.9/dist-packages/PIL/Image.py", line 3283, in open
    raise UnidentifiedImageError(msg)
PIL.UnidentifiedImageError: cannot identify image file '/tmp/tmpbqq82655'

В Sidekiq это выглядит так:

Что я делаю не так?

Я думаю, это действительно связано с S3. При загрузке изображения в журналах ошибок отображаются следующие сообщения:
URL для S3 скрыт…

Похоже, что плагин пытается загрузить изображение слишком рано или не может его найти по другим причинам.

Я тестировал это только для сайтов, использующих CDN для S3 или локальное хранилище. При использовании объектного хранилища рекомендую использовать CDN в качестве фронтенда.

1 лайк

Вот именно этим мы и занимаемся — AWS CloudFront. Стек основан на GitHub - aws-samples/aws-cdk-for-discourse: AWS CDK for Discourse · GitHub. Я попробую отладить и опубликую результаты.

2 лайка

Откуда мне взять API-ключ для этого?

Это должно быть в панели администратора, верно?

Это кажется мне слишком чувствительным — система помечает контент слишком часто. Даже просто фотографии людей помечаются как NSFW.

У меня пороги установлены на 60. Неясно, нужно ли увеличивать это число или уменьшать, и каков предельный порог? Если я установлю значение 100, это фактически отключит систему? Похоже, что документации по этому вопросу почти нет.

Кроме того, почему нельзя полностью отключить эту функцию для определённых ролей, как это сделано для фильтрации токсичности? Я уверен, что наши сотрудники не будут публиковать ничего грубого, но они постоянно спорят с ИИ, потому что он помечает их контент. На моём форуме это уже стало своего рода шуткой.

Используется opennsfw2.

1 лайк

К сожалению, эти старые модели машинного обучения не обладают гибкостью. Хотя они менее требовательны к ресурсам для запуска собственного экземпляра, мы обнаружили, что их жесткость становится серьезным препятствием для разнообразного сообщества пользователей Discourse.

В настоящее время мы планируем отказаться от всех функций, основанных на этих старых моделях, и мигрировать всё на современные большие языковые модели (LLM), где вы сможете настраивать промпты, чтобы лучше соответствовать вашим потребностям.

1 лайк

Произошли ли какие-либо изменения в этом плане? Детектор контента 18+ по-прежнему крайне неточен и срабатывает на большинстве изображений с людьми.

Да, мы уже изложили наш план в статье Что дальше для обнаружения контента NSFW в Discourse AI, но если кратко: вы можете использовать Правило автоматизации «Классификатор постов Discourse AI» для значительно более высокой точности и гибкости.

Мы провели оценку для сценария обнаружения NSFW с помощью визуальных LLM и получили отличные результаты, поэтому сейчас внедряем это решение для наших корпоративных клиентов и опубликуем руководства по этой теме в ближайшие недели.

2 лайка