Discourse AI — Тональность

:bookmark: В этом руководстве объясняется, как настроить классификацию тональности и эмоций в Discourse AI и использовать отчеты для анализа публикаций вашего сообщества.

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

Классификация тональности и эмоций помогает выявлять закономерности в обсуждениях вашего сообщества:

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

Это отдельные функции. Вы можете включить одну или обе, а также выбрать разные механизмы классификации для каждой. Отчеты подсчитывают классифицированные публикации, а не уникальных пользователей или типы личности. Используйте их для поиска обсуждений, заслуживающих внимания, а не как замену пониманию контекста.

Перед началом

Вам необходимо включить Discourse AI через discourse_ai_enabled и настроить механизм классификации.

Размещено на Discourse? На вашем сайте уже могут быть предоставлены выделенные конечные точки для классификации. Проверьте существующую конфигурацию перед ее изменением. Если вам нужна помощь с доступностью, настройкой конечных точек или лимитами для обработки исторических данных, свяжитесь с team@discourse.org.

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

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

Настройка тональности и эмоций

  1. Откройте Админ → Плагины → ИИ → Функции.
  2. Перейдите в раздел «Тональность и эмоции».
  3. В разделе «Тональность» выберите «Включено», если вы хотите выполнять классификацию на позитивную, нейтральную и негативную тональность. Это управляет параметром ai_sentiment_enabled.
  4. Выберите «Механизм» и настройте соответствующую конечную точку, агента или модель, как описано ниже.
  5. В разделе «Эмоции» выберите «Включено», если вы хотите выполнять классификацию эмоций. Это управляет параметром ai_sentiment_emotion_enabled.
  6. Выберите для него механизм и настройте его независимо.
  7. Установите лимиты фоновой обработки, описанные в следующем разделе.
  8. Нажмите «Отправить» и убедитесь, что ваши выборки сохранены.

В этом примере модель решений используется для обеих функций. Параметр «Публикаций в час» намеренно установлен в 0, чтобы приостановить автоматическое сканирование во время тестирования. Используйте положительное значение для автоматической обработки новых и исторических публикаций.

Использование выделенных конечных точек классификации

Выберите «Выделенная конечная точка классификации» для каждой функции, которую вы хотите запускать с выделенной моделью. Следуйте инструкциям в «Настройка выделенных конечных точек классификации» для параметра ai_sentiment_model_configs.

Справочные выделенные модели:

Функция Модель
Тональность cardiffnlp/twitter-roberta-base-sentiment-latest
Эмоции SamLowe/roberta-base-go_emotions

Каждая запись конфигурации идентифицирует свой classification_type (sentiment или emotion), model_name, endpoint и api_key. Предоставьте отдельную запись для каждого используемого выделенного классификатора. Храните учетные данные в секрете; не включайте их в сообщения поддержки или скриншоты.

См. Самостоятельное размещение тональности и эмоций для Discourse AI для развертывания сервера вывода. Включайте и выбирайте каждую функцию отдельно с помощью элементов управления выше.

Выделенный механизм ожидает совместимый API классификации. Копирование конечной точки Anthropic, чата OpenAI или Azure Language в этот параметр не делает ее совместимой. Успешное тестирование подключения для языковой модели в другом месте Discourse не проверяет выделенную конечную точку тональности.

Использование агента ИИ или модели решений

Для «Агента LLM» выберите подходящего агента-классификатора с настроенной языковой моделью. Discourse включает агентов-классификаторов для тональности и эмоций. Универсальный диалоговый агент не может заменить агента, настроенного на возвращение ожидаемых оценок меток.

Для «Модели решений» сначала настройте и протестируйте совместимую модель решений, затем выберите ее для каждой включенной функции. Модель решений не требует отдельной диалоговой языковой модели для этой классификации.

Запросы к агентам и моделям решений могут вызывать взимание платы провайдером или расходовать кредиты. Ознакомьтесь с правилами обработки данных выбранной модели перед назначением ее для автоматически обрабатываемой функции.

Управление обработкой и охватом исторических данных

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

Элемент управления Параметр сайта Значение по умолчанию Эффект
Публикаций в час ai_sentiment_backfill_maximum_posts_per_hour 240 Приблизительное количество обрабатываемых публикаций в час. 0 останавливает запланированное сканирование, включая новые публикации.
Ограничение возраста публикации в днях ai_sentiment_backfill_post_max_age_days 60 Сканировать публикации, созданные в этом временном окне. 0 означает только сегодняшние публикации, а не всю историю.

Увеличьте ограничение по возрасту, чтобы включить более старые публикации. Запланированная задача обрабатывает отсутствующие результаты со временем; выбор более старого диапазона дат в отчете сам по себе не классифицирует эту историю.

Скорость является приблизительной, а не точным ограничением запросов или расходов. Включение обоих классификаторов может привести к двум запросам на публикацию. Неудачные запросы или отказы могут быть повторены. Отредактированные публикации проверяются отдельно и не контролируются скоростью или ограничением возраста запланированного сканирования.

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

Анализ тональности по категориям или тегам

  1. Откройте Админ → Отчеты → Анализ тональности или посетите /admin/reports/sentiment_analysis на вашем сайте.
  2. Выберите даты начала и окончания.
  3. Выберите «Категория» или «Тег», чтобы сгруппировать результаты.
  4. Используйте соответствующий фильтр категорий или тегов, чтобы сузить результаты. Фильтрация по категориям также предоставляет опцию включения подкатегорий.
  5. Просмотрите общее количество в каждой группе и ее разбивку на позитивные, негативные и нейтральные публикации.
  6. Нажмите на строку группы, чтобы изучить ее график и исходные публикации.

В примере девять классифицированных публикаций: три позитивные, три негативные и три нейтральные. Нейтральные публикации включены в этот отчет.

В представлении деталей:

  • Выберите «Все», «Позитивные», «Нейтральные» или «Негативные», чтобы отфильтровать загруженные публикации.
  • Откройте тему публикации, чтобы прочитать окружающее обсуждение.
  • Используйте значок ссылки рядом с графиком, чтобы скопировать URL-адрес этого представления отчета. Получателям все равно нужен доступ персонала.
  • Нажмите «Назад», чтобы вернуться к сгруппированным результатам.

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

Анализ общей тенденции тональности

Откройте отчет «Общая тональность» в разделе Админ → Отчеты или посетите /admin/reports/overall_sentiment.

Счет рассчитывается как:

Количество позитивных публикаций − количество негативных публикаций

Позитивная или негативная оценка должна быть больше 0.6, чтобы публикация была учтена в этой группе. Если ни одна не превышает порог, в сгруппированном отчете публикация считается нейтральной. Порог фиксированный; нет параметра сайта для его изменения.

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

Анализ эмоций

Для каждой эмоции есть отчет в разделе Админ → Отчеты. Например, посетите /admin/reports/emotion_anger для «Гневы» или /admin/reports/emotion_curiosity для «Любопытства». Выберите диапазон дат и группировку по дням, неделям или месяцам для исследования тенденции.

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

Вы также можете фильтровать темы по эмоции. Посетите /filter?q=order:emotion_anger, чтобы найти подходящие темы, отсортированные по количеству публикаций, классифицированных как гнев, а не по средней оценке эмоции. Используйте order:emotion_anger-asc, чтобы изменить порядок сортировки. Без фильтра activity-after: такая сортировка учитывает подходящие публикации за последний год. Обычные права доступа к списку тем по-прежнему применяются.

Доступные метки эмоций

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

Понимание ограничений

  • Классификация зависит от модели. Сарказм, цитируемые материалы, специализированный язык и многоязычные обсуждения могут быть неверно интерпретированы. Охват языков и точность зависят от выбранной вами модели. Оценки из разных механизмов могут быть не откалиброваны одинаково.
  • Отчеты охватывают только сохраненные результаты. Включенная функция без работающего механизма, приостановленная обработка или недостаточный охват исторических данных могут привести к пустым или неполным отчетам.
  • Существующие классификации повторно используются. Редактирование классифицированной публикации не заменяет автоматически ее результаты. Изменение выбранного агента или модели решений в пределах одного механизма также не приводит к переклассификации существующих результатов.
  • Изменение механизма меняет источник данных отчета. Старые результаты не конвертируются для выбранного механизма. Отчеты могут казаться пустыми, пока обрабатываются отсутствующие классификации.
  • Отчеты исключают личные сообщения. Это исключение в отчетах отличается от ограничения обработки данных, описанного выше.

Устранение неполадок с отсутствующими или неожиданными результатами

Проблема Что проверить
Нет результатов после включения Убедитесь, что соответствующая функция включена, ее механизм настроен, «Публикаций в час» положительно, и фоновые задачи выполняются. Дайте время для пятиминутного сканирования и очереди обработки.
Тональность работает, но эмоции пустые Включите и настройте «Эмоции» отдельно. Выделенная конечная точка только для тональности не предоставляет классификации эмоций.
Нет результатов за более старые даты Увеличьте ограничение возраста публикации, дайте время для обработки и убедитесь, что диапазон отчета включает даты создания публикаций.
Выделенная конечная точка возвращает ошибку Проверьте ее URL-адрес, учетные данные, модель и формат ответа. Адаптер ожидает плоский массив меток и оценок, с метками тональности, такими как positive, neutral и negative, а не произвольные ответы чата или метки вида LABEL_0.
Не удается достичь конечной точки в частной сети Проверьте подключение и, где требуется, добавьте только доверенное имя хоста или IP-адрес конечной точки вывода в allowed_internal_hosts. Не отключайте широко защиту от подделки серверных запросов.
Результаты не меняются после редактирования или выбора модели Существующие результаты повторно используются. Не предполагайте, что редактирование контента или сохранение другой модели запланирует полную переклассификацию.
Фильтр показывает меньше публикаций, чем счетчик Счетчик описывает всю группу, а вкладки тональности фильтруют загруженные публикации. Проверьте, есть ли больше результатов для загрузки, и откройте исходные темы при исследовании несоответствий.

Администраторы могут просматривать записи запросов агентов и моделей решений в Админ → Плагины → ИИ → Журналы. Проверьте /logs на наличие ошибок фоновой классификации, включая сбои выделенных конечных точек. Рассматривайте содержимое журналов как конфиденциальное: оно может содержать текст публикации и ответы модели. Удалите учетные данные и приватный контент перед обменом диагностикой.

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

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 лайк