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.
- 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
- 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:
- Plugin Discourse AI instalado e habilitado: O plugin Discourse AI deve estar instalado em sua instância
- Análise de sentimentos habilitada: O módulo Sentiment Analysis deve estar configurado e ativo
- Plugin Data Explorer: Necessário para executar essas consultas SQL
- 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:
- Sentimento geral: O modelo cardiffnlp/twitter-roberta-base-sentiment-latest classifica as postagens como positivas, negativas ou neutras
- Detecção de emoção: O modelo SamLowe/roberta-base-go_emotions identifica emoções específicas nas postagens, como alegria, tristeza, raiva, etc.
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