Relatórios de análise de sentimento e emoção de IA

O plugin Discourse AI inclui capacidades de análise de sentimentos que podem ajudá-lo a obter uma compreensão mais profunda do tom emocional das discussões em toda a sua comunidade. Este tópico discute duas consultas detalhadas do Data Explorer que aproveitam essas capacidades de IA para fornecer insights sobre comunidades Discourse.

  1. Sentimento de IA por Categoria e Total de Nível de Confiança: Uma análise de série temporal que acompanha as tendências de sentimento por semana dentro de categorias e níveis de confiança específicos
  2. Tópicos de Exceção de Emoção de IA: Identifica tópicos de discussão que desencadeiam respostas emocionais significativas em um site Discourse.

Pré-requisitos

Para usar esses relatórios, você precisa:

  1. Plugin Discourse AI instalado e habilitado: O plugin Discourse AI deve estar instalado em sua instância
  2. Análise de sentimentos habilitada: O módulo Sentiment Analysis deve estar configurado e ativo
  3. Plugin Data Explorer: Necessário para executar essas consultas SQL
  4. Dados históricos de sentimentos: Postagens suficientes analisadas quanto ao sentimento para resultados significativos (pode exigir uma operação de preenchimento posterior)

Modelos de sentimento de IA e como funcionam

Antes de mergulhar nos relatórios, é útil entender o que os modelos de sentimento estão analisando nas postagens da sua comunidade:

Esses modelos analisam o texto de cada postagem e armazenam suas classificações em seu banco de dados, que podem então ser consultadas pelo plugin Data Explorer.

Relatório de Sentimento de IA por Categoria e Total de Nível de Confiança

-- [params]
-- date :start_date = 2025-01-01
-- date :end_date = 2025-12-31
-- category_id :category_id = 6
-- int :min_trust_level = 0
-- boolean :exclude_staff = false

-- Cria um conjunto de resultados temporário que agrega métricas de sentimento por semana para a categoria especificada
WITH sentiment_counts AS (
  SELECT 
    c.id as category_id,
    c.name as category_name,
    -- Agrupa postagens por semana para análise de série temporal
    DATE_TRUNC('week', p.created_at) as week_starting,
    EXTRACT(YEAR FROM p.created_at) as year,
    EXTRACT(WEEK FROM p.created_at) as week_number,
    -- Conta postagens com sentimento positivo (limiar > 0.6)
    COUNT(CASE WHEN (cr.classification::jsonb->'positive')::float > 0.6 THEN 1 
              ELSE NULL END) as positive_count,
    -- Conta postagens com sentimento negativo (limiar > 0.6)
    COUNT(CASE WHEN (cr.classification::jsonb->'negative')::float > 0.6 THEN 1 
              ELSE NULL END) as negative_count,
    -- Conta postagens com sentimento neutro (tanto positivo quanto negativo <= 0.6)
    COUNT(CASE WHEN (cr.classification::jsonb->'positive')::float <= 0.6 
               AND (cr.classification::jsonb->'negative')::float <= 0.6 THEN 1 
              ELSE NULL END) as neutral_count,
    -- Número total de postagens com análise de sentimento
    COUNT(*) as total_classifications
  FROM classification_results cr
  -- Junta dados de postagem para obter datas de criação e metadados
  JOIN posts p ON p.id = cr.target_id AND cr.target_type = 'Post'
  -- Junta dados de tópico para filtrar por categoria
  JOIN topics t ON t.id = p.topic_id
  -- Junta dados de usuário para filtrar por nível de confiança
  JOIN users u ON u.id = p.user_id
  -- Junta dados de categoria para obter o nome da categoria
  JOIN categories c ON c.id = t.category_id
  WHERE 
    -- Inclui apenas resultados de sentimento deste modelo específico
    cr.model_used = 'cardiffnlp/twitter-roberta-base-sentiment-latest'
    -- Inclui apenas tópicos regulares (sem MPs, etc.)
    AND t.archetype = 'regular'
    -- Exclui postagens do sistema
    AND p.user_id > 0
    -- Filtra pela categoria selecionada
    AND c.id = :category_id
    -- Filtra pelo nível de confiança mínimo
    AND u.trust_level >= :min_trust_level
    -- Exclui usuários da equipe se o parâmetro estiver marcado
    AND (:exclude_staff = false OR (u.admin = false AND u.moderator = false))
    -- Filtra pelo intervalo de datas
    AND p.created_at BETWEEN :start_date AND :end_date
  -- Agrupa por semana e categoria
  GROUP BY c.id, c.name, week_starting, year, week_number
)
-- Formata os resultados finais para exibição
SELECT 
  category_id,
  category_name,
  -- Converte para Date para exibição mais limpa
  week_starting::Date,
  -- Formata como notação de semana ISO (AAAA-SXX)
  year || '-W' || LPAD(week_number::text, 2, '0') as year_week,
  -- Calcula o saldo de sentimento (positivo menos negativo)
  positive_count - negative_count as sentiment_balance,
  positive_count,
  negative_count,
  neutral_count,
  -- Calcula a porcentagem de postagens positivas (arredondado para 2 casas decimais)
  ROUND(
    (positive_count::float / NULLIF(total_classifications, 0) * 100)::numeric,
    2
  ) as positive_percentage
FROM sentiment_counts
-- Ordena cronologicamente para mostrar tendências de sentimento ao longo do tempo
ORDER BY week_starting ASC

Este relatório fornece uma análise semanal das tendências de sentimento dentro de uma categoria específica, mostrando:

  • Contagens de postagens positivas, negativas e neutras para cada semana
  • Um cálculo de saldo de sentimento (postagens positivas menos postagens negativas)
  • A porcentagem de postagens positivas em relação ao total de postagens analisadas
  • Filtragem por nível de confiança do usuário e opção para excluir postagens da equipe

Este relatório é valioso para:

  • Acompanhar tendências de sentimento da comunidade ao longo do tempo em categorias específicas
  • Identificar flutuações no humor da comunidade que podem estar correlacionadas com eventos ou mudanças específicos
  • Comparar sentimento entre diferentes segmentos de usuários (por nível de confiança)
  • Medir o impacto de intervenções de moderação no sentimento geral da comunidade

Parâmetros

A consulta aceita vários parâmetros para personalizar sua análise:

  • Intervalo de datas: Defina datas de início e fim para o período de análise
  • Categoria: Selecione qual categoria analisar
  • Nível de confiança mínimo: Filtrar para incluir apenas postagens de usuários em ou acima de um nível de confiança específico
  • Excluir equipe: Opção para remover postagens da equipe da análise (para focar em membros regulares da comunidade)

Resultados

Os resultados são apresentados em uma tabela com cada linha representando uma semana de dados:

  • Informações da categoria: ID e nome da categoria analisada
  • Períodos de tempo: Data de início da semana e notação de semana ISO (AAAA-SXX)
  • Métricas de sentimento:
    • Saldo de sentimento: A diferença entre postagens positivas e negativas (valor positivo indica sentimento geral positivo)
    • Contagens positivas/negativas/neutras: O número de postagens em cada categoria de sentimento
    • Porcentagem positiva: A porcentagem de postagens classificadas como positivas

Exemplo de Resultados

category_name week_starting year_week sentiment_balance positive_count negative_count neutral_count positive_percentage
Product Discussion 2025-01-06 2025-W01 -8 24 32 145 11.94
Product Discussion 2025-01-13 2025-W02 -11 30 41 210 10.68
Product Discussion 2025-01-20 2025-W03 -9 28 37 220 9.82
Product Discussion 2025-01-27 2025-W04 -13 33 46 260 9.74
Product Discussion 2025-02-03 2025-W05 -15 22 37 180 9.21
Product Discussion 2025-02-10 2025-W06 -6 37 43 195 13.45

Relatório de Tópicos de Exceção de Emoção de IA

-- [params]
-- date :start_date = 2025-01-01
-- date :end_date = 2025-12-31
-- category_id :category_id = 6
-- int :min_trust_level = 1
-- int :emotion_threshold = 10  

-- Primeiro, crie uma Tabela Comum de Expressões (CTE) que agrega reações emocionais por tópico
WITH topic_emotions AS (
  SELECT
    topics.id AS topic_id,                 -- Armazena o ID do tópico para posterior junção/filtragem
    topics.title,                          -- Inclui o título do tópico para resultados legíveis
    topics.created_at::date AS topic_date, -- Armazena a data de criação do tópico
    
    -- Para cada tipo de emoção, conta postagens onde aquela emoção excede o limiar de confiança de 0.1
    -- A tabela classification_results armazena pontuações de emoção como valores JSON
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'admiration')::float > 0.1) AS admiration_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'amusement')::float > 0.1) AS amusement_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'anger')::float > 0.1) AS anger_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'annoyance')::float > 0.1) AS annoyance_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'approval')::float > 0.1) AS approval_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'caring')::float > 0.1) AS caring_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'confusion')::float > 0.1) AS confusion_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'curiosity')::float > 0.1) AS curiosity_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'desire')::float > 0.1) AS desire_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'disappointment')::float > 0.1) AS disappointment_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'disapproval')::float > 0.1) AS disapproval_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'disgust')::float > 0.1) AS disgust_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'embarrassment')::float > 0.1) AS embarrassment_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'excitement')::float > 0.1) AS excitement_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'fear')::float > 0.1) AS fear_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'gratitude')::float > 0.1) AS gratitude_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'grief')::float > 0.1) AS grief_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'joy')::float > 0.1) AS joy_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'love')::float > 0.1) AS love_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'nervousness')::float > 0.1) AS nervousness_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'neutral')::float > 0.1) AS neutral_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'optimism')::float > 0.1) AS optimism_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'pride')::float > 0.1) AS pride_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'realization')::float > 0.1) AS realization_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'relief')::float > 0.1) AS relief_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'remorse')::float > 0.1) AS remorse_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'sadness')::float > 0.1) AS sadness_count,
    COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'surprise')::float > 0.1) AS surprise_count,
    
    -- Calcula reações emocionais totais para fins de classificação
    COUNT(*) AS total_emotional_reactions
  FROM
    classification_results
  -- Junta à tabela posts para obter metadados de postagem e filtrar postagens excluídas
  INNER JOIN
    posts ON posts.id = classification_results.target_id AND
    posts.deleted_at IS NULL               -- Exclui postagens excluídas
  
  -- Junta à tabela topics para obter metadados de tópico e filtrar por tipo/status de tópico
  INNER JOIN
    topics ON topics.id = posts.topic_id AND
    topics.archetype = 'regular' AND       -- Inclui apenas tópicos padrão (não MPs ou mensagens do sistema)
    topics.deleted_at IS NULL              -- Exclui tópicos excluídos
  
  -- Junta à tabela users para obter nível de confiança do usuário para filtragem
  INNER JOIN
    users ON users.id = posts.user_id
  
  WHERE
    -- Inclui apenas classificações de emoção para postagens (não outros tipos de conteúdo)
    classification_results.target_type = 'Post' AND
    
    -- Usa apenas resultados deste modelo específico de detecção de emoção
    classification_results.model_used = 'SamLowe/roberta-base-go_emotions' AND
    
    -- Filtra por intervalo de datas usando valores parametrizados
    posts.created_at BETWEEN :start_date AND :end_date AND
    
    -- Filtra pela categoria especificada
    (topics.category_id = :category_id) AND
    
    -- Inclui apenas postagens de usuários com nível de confiança suficiente
    (users.trust_level >= :min_trust_level)
    
  -- Agrupa todas as contagens por tópico
  GROUP BY 
    topics.id, topics.title, topics.created_at::date
)

-- Consulta principal que formata e filtra os dados agregados da CTE
SELECT
  topic_id,                                -- Exibe ID do tópico (será renderizado como um link no Discourse)
  --title,                                   -- Exibe título do tópico
  topic_date,                              -- Exibe data de criação do tópico
  total_emotional_reactions,               -- Mostra contagem total de emoções detectadas
  
  -- Converte array de emoções significativas em uma string formatada
  -- Apenas emoções que excedem o limiar são incluídas, outras tornam-se NULL e são omitidas
  -- Cada emoção é formatada como "NomeEmoção(contagem)"
  ARRAY_TO_STRING(ARRAY[
    CASE WHEN admiration_count >= :emotion_threshold THEN 'Admiration(' || admiration_count || ')' ELSE NULL END,
    CASE WHEN amusement_count >= :emotion_threshold THEN 'Amusement(' || amusement_count || ')' ELSE NULL END,
    CASE WHEN anger_count >= :emotion_threshold THEN 'Anger(' || anger_count || ')' ELSE NULL END,
    CASE WHEN annoyance_count >= :emotion_threshold THEN 'Annoyance(' || annoyance_count || ')' ELSE NULL END,
    CASE WHEN approval_count >= :emotion_threshold THEN 'Approval(' || approval_count || ')' ELSE NULL END,
    CASE WHEN caring_count >= :emotion_threshold THEN 'Caring(' || caring_count || ')' ELSE NULL END,
    CASE WHEN confusion_count >= :emotion_threshold THEN 'Confusion(' || confusion_count || ')' ELSE NULL END,
    CASE WHEN curiosity_count >= :emotion_threshold THEN 'Curiosity(' || curiosity_count || ')' ELSE NULL END,
    CASE WHEN desire_count >= :emotion_threshold THEN 'Desire(' || desire_count || ')' ELSE NULL END,
    CASE WHEN disappointment_count >= :emotion_threshold THEN 'Disappointment(' || disappointment_count || ')' ELSE NULL END,
    CASE WHEN disapproval_count >= :emotion_threshold THEN 'Disapproval(' || disapproval_count || ')' ELSE NULL END,
    CASE WHEN disgust_count >= :emotion_threshold THEN 'Disgust(' || disgust_count || ')' ELSE NULL END,
    CASE WHEN embarrassment_count >= :emotion_threshold THEN 'Embarrassment(' || embarrassment_count || ')' ELSE NULL END,
    CASE WHEN excitement_count >= :emotion_threshold THEN 'Excitement(' || excitement_count || ')' ELSE NULL END,
    CASE WHEN fear_count >= :emotion_threshold THEN 'Fear(' || fear_count || ')' ELSE NULL END,
    CASE WHEN gratitude_count >= :emotion_threshold THEN 'Gratitude(' || gratitude_count || ')' ELSE NULL END,
    CASE WHEN grief_count >= :emotion_threshold THEN 'Grief(' || grief_count || ')' ELSE NULL END,
    CASE WHEN joy_count >= :emotion_threshold THEN 'Joy(' || joy_count || ')' ELSE NULL END,
    CASE WHEN love_count >= :emotion_threshold THEN 'Love(' || love_count || ')' ELSE NULL END,
    CASE WHEN nervousness_count >= :emotion_threshold THEN 'Nervousness(' || nervousness_count || ')' ELSE NULL END,
    CASE WHEN optimism_count >= :emotion_threshold THEN 'Optimism(' || optimism_count || ')' ELSE NULL END,
    CASE WHEN pride_count >= :emotion_threshold THEN 'Pride(' || pride_count || ')' ELSE NULL END,
    CASE WHEN realization_count >= :emotion_threshold THEN 'Realization(' || realization_count || ')' ELSE NULL END,
    CASE WHEN relief_count >= :emotion_threshold THEN 'Relief(' || relief_count || ')' ELSE NULL END,
    CASE WHEN remorse_count >= :emotion_threshold THEN 'Remorse(' || remorse_count || ')' ELSE NULL END,
    CASE WHEN sadness_count >= :emotion_threshold THEN 'Sadness(' || sadness_count || ')' ELSE NULL END,
    CASE WHEN surprise_count >= :emotion_threshold THEN 'Surprise(' || surprise_count || ')' ELSE NULL END
  ], ', ', '') AS significant_emotions     -- Junta com delimitadores de vírgula, string vazia se nenhum delimitador for necessário
  
FROM 
  topic_emotions
WHERE 
  -- Inclui apenas tópicos que têm pelo menos uma emoção excedendo o limiar
  -- Isso identifica tópicos com impacto emocional significativo
  (
    admiration_count >= :emotion_threshold OR
    amusement_count >= :emotion_threshold OR
    anger_count >= :emotion_threshold OR
    annoyance_count >= :emotion_threshold OR
    approval_count >= :emotion_threshold OR
    caring_count >= :emotion_threshold OR
    confusion_count >= :emotion_threshold OR
    curiosity_count >= :emotion_threshold OR
    desire_count >= :emotion_threshold OR
    disappointment_count >= :emotion_threshold OR
    disapproval_count >= :emotion_threshold OR
    disgust_count >= :emotion_threshold OR
    embarrassment_count >= :emotion_threshold OR
    excitement_count >= :emotion_threshold OR
    fear_count >= :emotion_threshold OR
    gratitude_count >= :emotion_threshold OR
    grief_count >= :emotion_threshold OR
    joy_count >= :emotion_threshold OR
    love_count >= :emotion_threshold OR
    nervousness_count >= :emotion_threshold OR
    optimism_count >= :emotion_threshold OR
    pride_count >= :emotion_threshold OR
    realization_count >= :emotion_threshold OR
    relief_count >= :emotion_threshold OR
    remorse_count >= :emotion_threshold OR
    sadness_count >= :emotion_threshold OR
    surprise_count >= :emotion_threshold
  )
-- Ordena resultados pelas reações emocionais mais altas primeiro
ORDER BY
  total_emotional_reactions DESC

Este relatório identifica tópicos que desencadearam respostas emocionais significativas em sua comunidade, com base em:

  • Uma contagem de cada tipo de emoção detectada nas postagens dentro do tópico
  • Um limiar configurável para determinar o que constitui uma resposta emocional “significativa”
  • Filtragem por categoria, intervalo de datas e nível de confiança do usuário

Este relatório ajuda você a:

  • Identificar discussões potencialmente problemáticas que estão gerando fortes emoções negativas
  • Encontrar conteúdo altamente envolvente que ressoa emocionalmente com sua comunidade
  • Detectar tópicos que podem precisar de atenção de moderação antes de escalar
  • Descobrir temas de conteúdo que desencadeiam respostas emocionais específicas
  • Entender melhor o que impulsiona o engajamento emocional em sua comunidade

Parâmetros

A consulta aceita vários parâmetros:

  • Intervalo de datas: Defina datas de início e fim para o período de análise
  • Categoria: Selecione qual categoria analisar
  • Nível de confiança mínimo: Filtrar para incluir apenas postagens de usuários em ou acima de um nível de confiança específico
  • Limiar de emoção: Defina quantas instâncias de uma emoção são necessárias para considerá-la significativa

Resultados

Os resultados mostram:

  • ID do tópico: Links diretamente para o tópico (clicável no Data Explorer)
  • Data do tópico: Quando o tópico foi criado
  • Reações emocionais totais: A contagem geral de reações emocionais detectadas
  • Emoções significativas: Uma lista formatada de emoções que excederam seu limiar, com suas contagens mostradas entre parênteses

As emoções detectadas incluem uma ampla gama: admiração, divertimento, raiva, irritação, aprovação, cuidado, confusão, curiosidade, desejo, desapontamento, desaprovação, desgosto, embaraço, excitação, medo, gratidão, luto, alegria, amor, nervosismo, neutro, otimismo, orgulho, realização, alívio, remorso, tristeza e surpresa.

Exemplo de Resultados

topic topic_date total_emotional_reactions significant_emotions
Feature Request: Increased API Rate Limits 2025-03-06 42 Approval(15), Confusion(9), Curiosity(7), Gratitude(8)
Authentication Error with Third-Party Integration 2025-01-07 33 Curiosity(6), Gratitude(5), Disapproval(8), Frustration(9)
Best Practices for Configuration Settings 2025-02-16 31 Curiosity(9), Excitement(6), Gratitude(5), Optimism(5)
Troubleshooting Database Connection Issues 2025-01-15 29 Curiosity(7), Confusion(8), Disappointment(6), Frustration(5)
Critical Bug in Latest Beta Release 2025-02-02 26 Confusion(7), Concern(6), Disapproval(5), Urgency(6)

Aplicações práticas na gestão de comunidades

Estes relatórios podem aprimorar seu fluxo de trabalho de gestão de comunidades de várias maneiras:

  • Intervenção precoce: Identificar tópicos carregados de emoção que podem precisar de moderação antes de se tornarem problemáticos
  • Planejamento de conteúdo: Usar insights sobre o que desencadeia emoções positivas para informar sua estratégia de conteúdo
  • Medindo impacto: Avaliar como mudanças de políticas, novos recursos ou eventos afetam o sentimento da comunidade
  • Engajamento direcionado: Focar a atenção da equipe em tópicos com fortes reações emocionais que podem se beneficiar de respostas oficiais

Recursos adicionais

1 curtida