Informes de análisis de sentimiento y emoción de IA

El plugin Discourse AI incluye capacidades de análisis de sentimientos que pueden ayudarte a obtener una comprensión más profunda del tono emocional de las discusiones en tu comunidad. Este tema discute dos consultas detalladas del Explorador de Datos que aprovechan estas capacidades de IA para ofrecer información sobre las comunidades de Discourse.

  1. Sentimiento de IA por Categoría y Total por Nivel de Confianza: Un análisis de series temporales que rastrea las tendencias de sentimiento por semana dentro de categorías y niveles de confianza específicos.
  2. Temas de Valores Atípicos de Emociones de IA: Identifica temas de discusión que desencadenan respuestas emocionales significativas en un sitio de Discourse.

Requisitos previos

Para utilizar estos informes, necesitas:

  1. Plugin Discourse AI instalado y habilitado: El plugin Discourse AI debe estar instalado en tu instancia.
  2. Análisis de sentimientos habilitado: El módulo Análisis de Sentimientos debe estar configurado y activo.
  3. Plugin Explorador de Datos: Requerido para ejecutar estas consultas SQL.
  4. Datos históricos de sentimiento: Suficientes publicaciones analizadas por sentimiento para obtener resultados significativos (puede requerir una operación de relleno).

Modelos de sentimiento de IA y cómo funcionan

Antes de profundizar en los informes, es útil entender qué están analizando los modelos de sentimiento en las publicaciones de tu comunidad:

Estos modelos analizan el texto de cada publicación y almacenan sus clasificaciones en tu base de datos, las cuales luego pueden ser consultadas por el plugin Explorador de Datos.

Informe: Sentimiento de IA por Categoría y Total por Nivel de Confianza

-- [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

-- Crear un conjunto de resultados temporal que agrupa métricas de sentimiento por semana para la categoría especificada
WITH sentiment_counts AS (
  SELECT 
    c.id as category_id,
    c.name as category_name,
    -- Agrupar publicaciones por semana para análisis de series temporales
    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,
    -- Contar publicaciones con sentimiento positivo (umbral > 0.6)
    COUNT(CASE WHEN (cr.classification::jsonb->'positive')::float > 0.6 THEN 1 
              ELSE NULL END) as positive_count,
    -- Contar publicaciones con sentimiento negativo (umbral > 0.6)
    COUNT(CASE WHEN (cr.classification::jsonb->'negative')::float > 0.6 THEN 1 
              ELSE NULL END) as negative_count,
    -- Contar publicaciones con sentimiento neutral (tanto positivo como 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 publicaciones con análisis de sentimiento
    COUNT(*) as total_classifications
  FROM classification_results cr
  -- Unir datos de publicaciones para obtener fechas de creación y metadatos
  JOIN posts p ON p.id = cr.target_id AND cr.target_type = 'Post'
  -- Unir datos de temas para filtrar por categoría
  JOIN topics t ON t.id = p.topic_id
  -- Unir datos de usuarios para filtrar por nivel de confianza
  JOIN users u ON u.id = p.user_id
  -- Unir datos de categorías para obtener el nombre de la categoría
  JOIN categories c ON c.id = t.category_id
  WHERE 
    -- Incluir solo resultados de sentimiento de este modelo específico
    cr.model_used = 'cardiffnlp/twitter-roberta-base-sentiment-latest'
    -- Incluir solo temas regulares (sin MP, etc.)
    AND t.archetype = 'regular'
    -- Excluir publicaciones del sistema
    AND p.user_id > 0
    -- Filtrar por la categoría seleccionada
    AND c.id = :category_id
    -- Filtrar por nivel de confianza mínimo
    AND u.trust_level >= :min_trust_level
    -- Excluir usuarios del personal si el parámetro está marcado
    AND (:exclude_staff = false OR (u.admin = false AND u.moderator = false))
    -- Filtrar por rango de fechas
    AND p.created_at BETWEEN :start_date AND :end_date
  -- Agrupar por semana y categoría
  GROUP BY c.id, c.name, week_starting, year, week_number
)
-- Formatear los resultados finales para su visualización
SELECT 
  category_id,
  category_name,
  -- Convertir a Fecha para una visualización más limpia
  week_starting::Date,
  -- Formatear como notación de semana ISO (AAAA-SXX)
  year || '-W' || LPAD(week_number::text, 2, '0') as year_week,
  -- Calcular el balance de sentimiento (positivo menos negativo)
  positive_count - negative_count as sentiment_balance,
  positive_count,
  negative_count,
  neutral_count,
  -- Calcular el porcentaje de publicaciones positivas (redondeado a 2 decimales)
  ROUND(
    (positive_count::float / NULLIF(total_classifications, 0) * 100)::numeric,
    2
  ) as positive_percentage
FROM sentiment_counts
-- Ordenar cronológicamente para mostrar las tendencias de sentimiento a lo largo del tiempo
ORDER BY week_starting ASC

Este informe proporciona un análisis semanal de las tendencias de sentimiento dentro de una categoría específica, mostrando:

  • Conteos de publicaciones positivas, negativas y neutrales para cada semana.
  • Un cálculo de balance de sentimiento (publicaciones positivas menos publicaciones negativas).
  • El porcentaje de publicaciones positivas en relación con el total de publicaciones analizadas.
  • Filtrado por nivel de confianza del usuario y opción para excluir publicaciones del personal.

Este informe es valioso para:

  • Rastrear las tendencias de sentimiento de la comunidad a lo largo del tiempo en categorías específicas.
  • Identificar fluctuaciones en el estado de ánimo de la comunidad que podrían correlacionarse con eventos o cambios específicos.
  • Comparar el sentimiento entre diferentes segmentos de usuarios (por nivel de confianza).
  • Medir el impacto de las intervenciones de moderación en el sentimiento general de la comunidad.

Parámetros

La consulta acepta varios parámetros para personalizar tu análisis:

  • Rango de fechas: Establece las fechas de inicio y fin para tu período de análisis.
  • Categoría: Selecciona qué categoría analizar.
  • Nivel de confianza mínimo: Filtra para incluir solo publicaciones de usuarios en o por encima de un nivel de confianza específico.
  • Excluir personal: Opción para eliminar las publicaciones del personal del análisis (para centrarse en los miembros regulares de la comunidad).

Resultados

Los resultados se presentan en una tabla donde cada fila representa una semana de datos:

  • Información de la categoría: ID y nombre de la categoría analizada.
  • Períodos de tiempo: Fecha de inicio de la semana y notación de semana ISO (AAAA-SXX).
  • Métricas de sentimiento:
    • Balance de sentimiento: La diferencia entre publicaciones positivas y negativas (un valor positivo indica un sentimiento general positivo).
    • Conteos positivos/negativos/neutrales: El número de publicaciones en cada categoría de sentimiento.
    • Porcentaje positivo: El porcentaje de publicaciones clasificadas como positivas.

Resultados de ejemplo

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

Informe: Temas de Valores Atípicos de Emociones 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  

-- Primero, crear una Expresión de Tabla Común (CTE) que agrupe las reacciones emocionales por tema
WITH topic_emotions AS (
  SELECT
    topics.id AS topic_id,                 -- Almacenar el ID del tema para uniones/filtros posteriores
    topics.title,                          -- Incluir el título del tema para resultados legibles
    topics.created_at::date AS topic_date, -- Almacenar la fecha de creación del tema
    
    -- Para cada tipo de emoción, contar publicaciones donde esa emoción supera el umbral de confianza de 0.1
    -- La tabla classification_results almacena las puntuaciones de emoción 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,
    
    -- Calcular reacciones emocionales totales para fines de clasificación
    COUNT(*) AS total_emotional_reactions
  FROM
    classification_results
  -- Unir a la tabla posts para obtener metadatos de publicaciones y filtrar publicaciones eliminadas
  INNER JOIN
    posts ON posts.id = classification_results.target_id AND
    posts.deleted_at IS NULL               -- Excluir publicaciones eliminadas
  
  -- Unir a la tabla topics para obtener metadatos de temas y filtrar por tipo/estado de tema
  INNER JOIN
    topics ON topics.id = posts.topic_id AND
    topics.archetype = 'regular' AND       -- Incluir solo temas estándar (no MP ni mensajes del sistema)
    topics.deleted_at IS NULL              -- Excluir temas eliminados
  
  -- Unir a la tabla users para obtener el nivel de confianza del usuario para filtrado
  INNER JOIN
    users ON users.id = posts.user_id
  
  WHERE
    -- Incluir solo clasificaciones de emociones para publicaciones (no otros tipos de contenido)
    classification_results.target_type = 'Post' AND
    
    -- Usar solo resultados de este modelo específico de detección de emociones
    classification_results.model_used = 'SamLowe/roberta-base-go_emotions' AND
    
    -- Filtrar por rango de fechas usando valores parametrizados
    posts.created_at BETWEEN :start_date AND :end_date AND
    
    -- Filtrar por la categoría especificada
    (topics.category_id = :category_id) AND
    
    -- Incluir solo publicaciones de usuarios con suficiente nivel de confianza
    (users.trust_level >= :min_trust_level)
    
  -- Agrupar todos los conteos por tema
  GROUP BY 
    topics.id, topics.title, topics.created_at::date
)

-- Consulta principal que formatea y filtra los datos agregados de la CTE
SELECT
  topic_id,                                -- Mostrar ID del tema (se renderizará como un enlace en Discourse)
  --title,                                   -- Mostrar título del tema
  topic_date,                              -- Mostrar fecha de creación del tema
  total_emotional_reactions,               -- Mostrar conteo total de emociones detectadas
  
  -- Convertir el array de emociones significativas en una cadena formateada
  -- Solo se incluyen las emociones que superan el umbral; las demás se vuelven NULL y se omiten
  -- Cada emoción se formatea como "NombreEmocion(conteo)"
  ARRAY_TO_STRING(ARRAY[
    CASE WHEN admiration_count >= :emotion_threshold THEN 'Admiración(' || admiration_count || ')' ELSE NULL END,
    CASE WHEN amusement_count >= :emotion_threshold THEN 'Divertimiento(' || amusement_count || ')' ELSE NULL END,
    CASE WHEN anger_count >= :emotion_threshold THEN 'Ira(' || anger_count || ')' ELSE NULL END,
    CASE WHEN annoyance_count >= :emotion_threshold THEN 'Molestia(' || annoyance_count || ')' ELSE NULL END,
    CASE WHEN approval_count >= :emotion_threshold THEN 'Aprobación(' || approval_count || ')' ELSE NULL END,
    CASE WHEN caring_count >= :emotion_threshold THEN 'Cuidado(' || caring_count || ')' ELSE NULL END,
    CASE WHEN confusion_count >= :emotion_threshold THEN 'Confusión(' || confusion_count || ')' ELSE NULL END,
    CASE WHEN curiosity_count >= :emotion_threshold THEN 'Curiosidad(' || curiosity_count || ')' ELSE NULL END,
    CASE WHEN desire_count >= :emotion_threshold THEN 'Deseo(' || desire_count || ')' ELSE NULL END,
    CASE WHEN disappointment_count >= :emotion_threshold THEN 'Decepción(' || disappointment_count || ')' ELSE NULL END,
    CASE WHEN disapproval_count >= :emotion_threshold THEN 'Desaprobación(' || disapproval_count || ')' ELSE NULL END,
    CASE WHEN disgust_count >= :emotion_threshold THEN 'Asco(' || disgust_count || ')' ELSE NULL END,
    CASE WHEN embarrassment_count >= :emotion_threshold THEN 'Vergüenza(' || embarrassment_count || ')' ELSE NULL END,
    CASE WHEN excitement_count >= :emotion_threshold THEN 'Emoción(' || excitement_count || ')' ELSE NULL END,
    CASE WHEN fear_count >= :emotion_threshold THEN 'Miedo(' || fear_count || ')' ELSE NULL END,
    CASE WHEN gratitude_count >= :emotion_threshold THEN 'Gratitud(' || gratitude_count || ')' ELSE NULL END,
    CASE WHEN grief_count >= :emotion_threshold THEN 'Duelo(' || grief_count || ')' ELSE NULL END,
    CASE WHEN joy_count >= :emotion_threshold THEN 'Alegría(' || joy_count || ')' ELSE NULL END,
    CASE WHEN love_count >= :emotion_threshold THEN 'Amor(' || love_count || ')' ELSE NULL END,
    CASE WHEN nervousness_count >= :emotion_threshold THEN 'Nerviosismo(' || nervousness_count || ')' ELSE NULL END,
    CASE WHEN optimism_count >= :emotion_threshold THEN 'Optimismo(' || optimism_count || ')' ELSE NULL END,
    CASE WHEN pride_count >= :emotion_threshold THEN 'Orgullo(' || pride_count || ')' ELSE NULL END,
    CASE WHEN realization_count >= :emotion_threshold THEN 'Conciencia(' || realization_count || ')' ELSE NULL END,
    CASE WHEN relief_count >= :emotion_threshold THEN 'Alivio(' || relief_count || ')' ELSE NULL END,
    CASE WHEN remorse_count >= :emotion_threshold THEN 'Arrepentimiento(' || remorse_count || ')' ELSE NULL END,
    CASE WHEN sadness_count >= :emotion_threshold THEN 'Tristeza(' || sadness_count || ')' ELSE NULL END,
    CASE WHEN surprise_count >= :emotion_threshold THEN 'Sorpresa(' || surprise_count || ')' ELSE NULL END
  ], ', ', '') AS significant_emotions     -- Unir con delimitadores de coma, cadena vacía si no se necesita delimitador
  
FROM 
  topic_emotions
WHERE 
  -- Incluir solo temas que tengan al menos una emoción que supere el umbral
  -- Esto identifica temas con un 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
  )
-- Ordenar resultados por la mayor cantidad de reacciones emocionales primero
ORDER BY
  total_emotional_reactions DESC

Este informe identifica temas que han desencadenado respuestas emocionales significativas en tu comunidad, basándose en:

  • Un conteo de cada tipo de emoción detectada en las publicaciones dentro del tema.
  • Un umbral configurable para determinar qué constituye una respuesta emocional “significativa”.
  • Filtrado por categoría, rango de fechas y nivel de confianza del usuario.

Este informe te ayuda a:

  • Identificar discusiones potencialmente problemáticas que están generando emociones negativas fuertes.
  • Encontrar contenido altamente atractivo que resuena emocionalmente con tu comunidad.
  • Detectar temas que podrían necesitar atención de moderación antes de escalar.
  • Descubrir temas de contenido que desencadenan respuestas emocionales específicas.
  • Comprender mejor qué impulsa el compromiso emocional en tu comunidad.

Parámetros

La consulta acepta varios parámetros:

  • Rango de fechas: Establece las fechas de inicio y fin para tu período de análisis.
  • Categoría: Selecciona qué categoría analizar.
  • Nivel de confianza mínimo: Filtra para incluir solo publicaciones de usuarios en o por encima de un nivel de confianza específico.
  • Umbral de emoción: Establece cuántas instancias de una emoción se requieren para considerarla significativa.

Resultados

Los resultados muestran:

  • ID del tema: Enlace directo al tema (clicable en el Explorador de Datos).
  • Fecha del tema: Cuándo se creó el tema.
  • Reacciones emocionales totales: El conteo general de reacciones emocionales detectadas.
  • Emociones significativas: Una lista formateada de emociones que superaron tu umbral, con sus conteos mostrados entre paréntesis.

Las emociones detectadas incluyen una amplia gama: admiración, divertimiento, ira, molestia, aprobación, cuidado, confusión, curiosidad, deseo, decepción, desaprobación, asco, vergüenza, emoción, miedo, gratitud, duelo, alegría, amor, nerviosismo, neutral, optimismo, orgullo, conciencia, alivio, arrepentimiento, tristeza y sorpresa.

Resultados de ejemplo

topic topic_date total_emotional_reactions significant_emotions
Feature Request: Increased API Rate Limits 2025-03-06 42 Aprobación(15), Confusión(9), Curiosidad(7), Gratitud(8)
Authentication Error with Third-Party Integration 2025-01-07 33 Curiosidad(6), Gratitud(5), Desaprobación(8), Frustración(9)
Best Practices for Configuration Settings 2025-02-16 31 Curiosidad(9), Emoción(6), Gratitud(5), Optimismo(5)
Troubleshooting Database Connection Issues 2025-01-15 29 Curiosidad(7), Confusión(8), Decepción(6), Frustración(5)
Critical Bug in Latest Beta Release 2025-02-02 26 Confusión(7), Preocupación(6), Desaprobación(5), Urgencia(6)

Aplicaciones prácticas en la gestión de comunidades

Estos informes pueden mejorar tu flujo de trabajo de gestión de comunidades de varias maneras:

  • Intervención temprana: Identificar temas cargados emocionalmente que podrían necesitar moderación antes de volverse problemáticos.
  • Planificación de contenido: Utilizar información sobre qué desencadena emociones positivas para informar tu estrategia de contenido.
  • Medición del impacto: Evaluar cómo los cambios de política, nuevas características o eventos afectan el sentimiento de la comunidad.
  • Compromiso dirigido: Concentrar la atención del personal en temas con reacciones emocionales fuertes que podrían beneficiarse de respuestas oficiales.

Recursos adicionales

1 me gusta