Discourse AI - Анализ тональности

:bookmark: Эта тема посвящена настройке функции анализа тональности (Sentiment) плагина Discourse AI.

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

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

Возможности

  • Общая тональность: сравнивает количество сообщений, классифицированных как позитивные или негативные.
  • Столбчатая диаграмма с возможностью переключения для отображения числовых значений позитивных, негативных и общих показателей.
  • Эмоции: количество тем и сообщений, классифицированных по множеству эмоций, сгруппированных по временным интервалам:
    • Сегодня
    • Вчера
    • Последние 7 дней
    • Последние 30 дней
  • Отчеты за любой период времени, доступные через настройки:
    • Годовой
    • Квартальный
    • Ежемесячный
    • Еженедельный
    • Пользовательский диапазон
  • Доступно для всех сотрудников (администраторов и модераторов)

Включение анализа тональности

Настройка

Анализ тональности включен по умолчанию для клиентов на хостинге. Для ручных шагов см. ниже.

  1. Перейдите в настройки AdminPlugins → найдите или выполните поиск discourse-ai и убедитесь, что он включен.
  2. Включите параметр ai_sentiment_enabled для анализа тональности.
  3. Перейдите по адресу /admin/dashboard/sentiment, чтобы просмотреть соответствующие отчеты.

:information_source: После включения функция анализа тональности автоматически классифицирует все новые сообщения и выполнит повторную обработку (backfill) сообщений за последние 60 дней с помощью запланированной задачи, которая выполняется каждые 5 минут. Для повторной обработки сообщений старше 60 дней увеличьте настройку сайта ai_sentiment_backfill_post_max_age_days.

:discourse2: Размещено нами?

Свяжитесь с нами по адресу team@discourse.org, если вам нужна помощь в настройке параметров повторной обработки.

:mechanic: Собственный хостинг?

Увеличьте значение ai_sentiment_backfill_post_max_age_days в настройках вашего сайта, чтобы охватить желаемый временной диапазон. Запланированная задача повторной обработки автоматически обработает более старые сообщения. Подробную информацию о настройке необходимых конечных точек моделей см. в статье Размещение анализа тональности и эмоций для DiscourseAI на собственном хостинге.

Технические вопросы и ответы

Как обрабатываются данные о темах/сообщениях? Как присваиваются оценки?

  • Анализ тональности работает с точностью «на каждое сообщение». Для каждого сообщения мы определяем тональность, а затем можем разбивать эти данные по различным критериям (по тегам, категориям, времени и т. д.). Он сравнивает количество сообщений, классифицированных как позитивные или негативные. Эти расчеты производятся, когда позитивные или негативные оценки превышают фиксированный порог 0,6 (в настоящее время не настраивается).

Планируется ли добавление поддержки других языков?

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

Какие модели используются для работы анализа тональности?

Ограничения

  • Сообщения, классифицированные как нейтральные (ни позитивные, ни негативные), не отображаются.
  • Личные сообщения (ЛС) исключаются из расчетов.
10 лайков

Пост был объединён с существующей темой: Проблемы с заполнением данных о тональности

Пост был объединен с существующей темой: Проблемы с заполнением данных о настроении

Оригинальный пост обновлён новым видео, демонстрирующим обновлённые функции Sentiment, включая значительно расширенный спектр эмоций и возможность определять, какие темы/сообщения связаны с каждой эмоцией.

Я настроил конфигурацию модели анализа тональности, указав model_name, endpoint и api_key, скопированные из настроек LLM. Тесты там проходят успешно, но в /logs я получаю ошибку, приведенную ниже.

(Но, возможно, я что-то понимаю неправильно, ведь почему анализ тональности не использует один из настроенных LLM?)

Используется claude-3-5-sonnet.


{"type":"error","error":{"type":"invalid_request_error","message":"anthropic-version: header is required"}} (Net::HTTPBadResponse)
/var/www/discourse/plugins/discourse-ai/lib/inference/hugging_face_text_embeddings.rb:71:in `classify'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:142:in `request_with'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:78:in `block (4 levels) in bulk_classify!'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:1593:in `evaluate_to'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:1776:in `block in on_resolvable'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:359:in `run_task'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:350:in `block (3 levels) in create_worker'
<internal:kernel>:187:in `loop'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:341:in `block (2 levels) in create_worker'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in `catch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in `block in create_worker'
Status: 400

{"type":"error","error":{"type":"invalid_request_error","message":"anthropic-version: header is required"}} (Net::HTTPBadResponse)
/var/www/discourse/plugins/discourse-ai/lib/inference/hugging_face_text_embeddings.rb:71:in `classify'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:142:in `request_wit...

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

3 лайка

@Falco, я только что заметил, что анализ тональности перестал работать с января 2025 года. Я предполагаю, что появилась новая настройка ai_sentiment_model, которая, как объясняется в ссылке выше, предназначена для запуска вашей собственной выделенной модели/изображения для анализа тональности. После обновления Discourse я заметил, что ai_sentiment_model_configs теперь полностью пуст (должно ли оно быть пустым?).

При попытке выполнить backfill через rake возникает ошибка:

rake ai:sentiment:backfill
rake aborted!
ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR:  syntax error at or near ")" (ActiveRecord::StatementInvalid)
LINE 1: ...e_upload_id", "posts"."outbound_message_id" FROM () as posts...
                                                             ^
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-3.3.1/lib/patches/db/pg.rb:69:in `exec_params'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-3.3.1/lib/patches/db/pg.rb:69:in `exec_params'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:894:in `block (2 levels) in exec_no_cache'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:1004:in `block in with_raw_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-7.2.2.1/lib/active_support/concurrency/null_lock.rb:9:in `synchronize'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:976:in `with_raw_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:893:in `block in exec_no_cache'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-7.2.2.1/lib/active_support/notifications/instrumenter.rb:58:in `instrument'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:1119:in `log'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:892:in `exec_no_cache'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:872:in `execute_and_clear'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:66:in `internal_exec_query'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:647:in `select'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:73:in `select_all'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/query_cache.rb:251:in `select_all'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/querying.rb:70:in `_query_by_sql'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1431:in `block (2 levels) in exec_main_query'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:415:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_handling.rb:296:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1430:in `block in exec_main_query'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/query_cache.rb:143:in `disable_query_cache'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/query_cache.rb:30:in `uncached'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/delegation.rb:78:in `block in uncached'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1355:in `_scoping'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:541:in `scoping'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/delegation.rb:78:in `uncached'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1450:in `skip_query_cache_if_necessary'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1414:in `exec_main_query'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1392:in `block in exec_queries'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/query_cache.rb:143:in `disable_query_cache'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/query_cache.rb:30:in `uncached'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/delegation.rb:120:in `public_send'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/delegation.rb:120:in `block in method_missing'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1355:in `_scoping'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:541:in `scoping'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/delegation.rb:120:in `method_missing'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1450:in `skip_query_cache_if_necessary'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1386:in `exec_queries'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1167:in `load'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:336:in `records'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/batches.rb:380:in `block in batch_on_unloaded_relation'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/batches.rb:378:in `batch_on_unloaded_relation'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/batches.rb:269:in `in_batches'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/batches.rb:157:in `find_in_batches'
/var/www/discourse/plugins/discourse-ai/lib/tasks/modules/sentiment/backfill.rake:7:in `block in <main>'
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'

Caused by:
PG::SyntaxError: ERROR:  syntax error at or near ")" (PG::SyntaxError)
LINE 1: ...e_upload_id", "posts"."outbound_message_id" FROM () as posts...
                                                             ^
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-3.3.1/lib/patches/db/pg.rb:69:in `exec_params'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-3.3.1/lib/patches/db/pg.rb:69:in `exec_params'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:894:in `block (2 levels) in exec_no_cache'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:1004:in `block in with_raw_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-7.2.2.1/lib/active_support/concurrency/null_lock.rb:9:in `synchronize'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:976:in `with_raw_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:893:in `block in exec_no_cache'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-7.2.2.1/lib/active_support/notifications/instrumenter.rb:58:in `instrument'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:1119:in `log'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:892:in `exec_no_cache'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:872:in `execute_and_clear'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:66:in `internal_exec_query'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:647:in `select'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:73:in `select_all'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/query_cache.rb:251:in `select_all'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/querying.rb:70:in `_query_by_sql'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1431:in `block (2 levels) in exec_main_query'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:415:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_handling.rb:296:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1430:in `block in exec_main_query'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/query_cache.rb:143:in `disable_query_cache'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/query_cache.rb:30:in `uncached'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/delegation.rb:78:in `block in uncached'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1355:in `_scoping'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:541:in `scoping'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/delegation.rb:78:in `uncached'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1450:in `skip_query_cache_if_necessary'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1414:in `exec_main_query'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1392:in `block in exec_queries'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/query_cache.rb:143:in `disable_query_cache'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/query_cache.rb:30:in `uncached'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/delegation.rb:120:in `public_send'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/delegation.rb:120:in `block in method_missing'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1355:in `_scoping'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:541:in `scoping'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/delegation.rb:120:in `method_missing'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1450:in `skip_query_cache_if_necessary'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1386:in `exec_queries'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1167:in `load'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:336:in `records'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/batches.rb:380:in `block in batch_on_unloaded_relation'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/batches.rb:378:in `batch_on_unloaded_relation'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/batches.rb:269:in `in_batches'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/batches.rb:157:in `find_in_batches'
/var/www/discourse/plugins/discourse-ai/lib/tasks/modules/sentiment/backfill.rake:7:in `block in <main>'
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'
Tasks: TOP => ai:sentiment:backfill
(See full trace by running task with --trace)

Мой вопрос: до ноября/декабря 2024 года всё работало нормально. Как это работало раньше без выделенной модели/сервера для анализа тональности? Есть ли способ снова запустить это, используя какой-то общий публичный сервис или встроенный сервис, без необходимости разворачивать отдельный сервер? Мне очень нравится, что Discourse представляет собой самодостаточную систему, что упрощает простое развёртывание. Необходимость кастомных развёртываний увеличивает сложность и затраты на поддержку, что проблематично для небольших установок. Есть ли способ вернуться к настройке до 2025 года, когда анализ тональности работал из коробки?

Плагин по умолчанию использовал сервер в DigitalOcean, который я настроил для упрощения тестирования.

С тех пор я сбросил настройки плагина до состояния «с чистого листа», и тем, кто хочет использовать классификацию с помощью ИИ, необходимо запускать серверы в соответствии с документацией здесь, на Meta.

Действительно, но мы несли эти расходы в целях тестирования. Предоставлять это каждому пользователю с собственным хостингом — неустойчивая модель.

Стоит упомянуть, что мы предоставляем эту услугу классификации на серверах с ускорением GPU в рамках нашего сервиса хостинга.

2 лайка

Проблемы анализа тональности Discourse AI: Формат модели Hugging Face и сбой конечной точки Azure


Привет, сообщество Discourse и разработчики,

Я столкнулся с серьезными проблемами при попытке настроить и использовать функцию анализа тональности в плагине Discourse AI на своем форуме. Похоже, существуют две отдельные проблемы, которые мешают её корректной работе.


Проблема 1: Несоответствие формата ответа модели Hugging Face

Я настроил модель cardiffnlp/twitter-roberta-base-sentiment из Hugging Face для анализа тональности. Хотя мой API-ключ действителен, и я могу успешно вызывать API с моего экземпляра Discourse через curl, плагин Discourse AI, похоже, неправильно парсит ответ из-за изменения формата вывода модели Hugging Face.

Моя команда curl (подтверждающая действительность API-ключа и новый формат):

Bashcurl -X POST https://api-inference.huggingface.co/models/cardiffnlp/twitter-roberta-base-sentiment \ -H "Authorization: Bearer hf_xxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d "{\"inputs\": \"I love Discourse!\"}"

Вывод из curl (показывающий новый вложенный формат массива):

[[{"label":"LABEL_2","score":0.9891520738601685},{"label":"LABEL_1","score":0.009014752693474293},{"label":"LABEL_0","score":0.0018332178005948663}]]

Проблема: Модель twitter-roberta-base-sentiment ранее возвращала один массив хешей «метка-оценка»: [{"label": "LABEL_2", "score": 0.98}, ...]. Однако теперь она возвращает вложенный массив: [[{"label": "LABEL_2", "score": 0.98}, ...]].

Закодированная логика парсинга плагина Discourse AI (в частности, classification["label"][/\d+/].to_i, как указано в трассировке стека) не учитывает этот внешний слой массива. Это приводит к ошибке TypeError, когда он пытается обратиться к Символу как к Целому числу.

Сообщение об ошибке (из исключения задачи):

no implicit conversion of Symbol into Integer (TypeError)
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:163:in block in transform_result’
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:163:in each’
/var/www/discourse/plugin…

Полная трассировка стека для проблемы с Hugging Face:

/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:1268:in `raise'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:1268:in `wait_until_resolved!'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:998:in `value!'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:93:in `bulk_classify!'
/var/www/discourse/plugins/discourse-ai/app/jobs/scheduled/sentiment_backfill.rb:27:in `execute'
/var/www/discourse/app/jobs/base.rb:316:in `block (2 levels) in perform'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management/null_instance.rb:49:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management.rb:21:in `with_connection'
/var/www/discourse/app/jobs/base.rb:303:in `block in perform'
/var/www/discourse/app/jobs/base.rb:299:in `each'
/var/www/discourse/app/jobs/base.rb:299:in `perform'
/var/www/discourse/app/jobs/base.rb:379:in `perform'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_scheduler-0.18.0/lib/mini_scheduler/manager.rb:137:in `process_queue'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_scheduler-0.18.0/lib/mini_scheduler/manager.rb:77:in `worker_loop'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_scheduler-0.18.0/lib/mini_scheduler/manager.rb:63:in `block (2 levels) in ensure_worker_threads'
<internal:kernel>:187:in `loop'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:341:in `block (2 levels) in create_worker'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in `catch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in `block in create_worker'
no implicit conversion of Symbol into Integer (TypeError)
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:163:in `block in transform_result'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:163:in `each'
/var/www/discourse/plugin...

Проблема 2: Конфигурация модели Microsoft Azure приводит к ошибке Hugging Face

Когда я попытался переключиться на модель Text Analytics от Microsoft в настройках Discourse AI, я получил ошибку 404 Resource not found, и, что удивительно, трассировка стека все еще указывает на hugging_face_text_embeddings.rb.

Сообщение об ошибке (из исключения задачи):

Job exception: 416 errors
{"error":{"code":"404","message": "Resource not found"}} (Net::HTTPBadResponse)

Фрагмент соответствующей трассировки стека (указывающий на Hugging Face, несмотря на выбранную модель Microsoft):

/var/www/discourse/plugins/discourse-ai/lib/inference/hugging_face_text_embeddings.rb:76:in `do_request!'
/var/www/discourse/plugins/discourse-ai/lib/inference/hugging_face_text_embeddings.rb:51:in `classify_by_sentiment!'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:156:in `request_with'

Наблюдение: Это указывает на то, что даже когда я выбираю и настраиваю конечную точку и API-ключ модели Microsoft, плагин Discourse AI, похоже, имеет жестко закодированную или неправильно маршрутизирует запросы анализа тональности через логику или конечные точки, специфичные для Hugging Face. Это полностью предотвращает использование модели Microsoft.


Скриншоты конфигурации:

Я прикрепил скриншот моих настроек Discourse AI, чтобы показать конфигурацию:

  • Подробная конфигурация моделей анализа тональности ИИ (показывающая как модели Hugging Face, так и Microsoft) — я тестировал только с конфигурациями Hugging Face или только Microsoft, получая тот же результат

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

Любая помощь или рекомендации по этим проблемам были бы очень полезны.

Спасибо!

2 лайка

Мне интересно, работает ли отчётность по тональности у других, или я что-то неправильно настроил. Я хотел бы узнать, что ещё нужно проверить или настроить, чтобы включить отчётность по тональности, так как у меня всё ещё сохраняется та же проблема.

1 лайк

Мы пытаемся использовать эту функцию с Azure AI Language (с нашего самохостингового экземпляра Discourse), так как мы уже используем нашу подписку Azure для интеграции GPT-4.5 с Discourse (для функций суммирования и чат-бота):

…однако в панели мониторинга настроенных данных ничего не отображается, и в логах видны следующие ошибки:

Discourse AI: Ошибки при массовой классификации: Не удалось классифицировать 208 сообщений (примеры ID: 2256, 909, 2270, 2260, 2797): JSON::ParserError: Пустая строка не является допустимой строкой JSON.

Следы выполнения показывают, что Discourse, возможно, пытается использовать HuggingFace. Являются ли это единственными поддерживаемыми моделями на данный момент?

Спасибо,

N

1 лайк

Итак, единственный способ использовать эту функцию — развернуть собственные экземпляры моделей (которые требуют ресурсоемких GPU-инстансов, что может быть дорогостоящим)? Эта функция выглядит очень полезной, но кажется, что её настройка обойдется мне дороже, чем само хостинг-решение для Discourse.

Да, поддерживаемые модели перечислены в первом сообщении темы (OP).

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

Ну, вся эта функция построена вокруг классификации постов с помощью ML-моделей, поэтому да, вам нужно где-то запускать их.

Поскольку Discourse может работать даже на самом дешевом VPS, запуск ML-моделей действительно обходится дороже. Если вы хотите реализовать эту функцию максимально дешево, это возможно сделать на сервере с всего несколькими ядрами CPU, при условии, что у вас достаточно оперативной памяти для загрузки моделей.

1 лайк

Извините, если этот вопрос уже задавался ранее, но я не смог найти ссылку на то, где именно можно настроить пороговый балл :sweat_smile:

1 лайк

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

1 лайк