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.
- 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.
- 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:
- Plugin Discourse AI instalado y habilitado: El plugin Discourse AI debe estar instalado en tu instancia.
- Análisis de sentimientos habilitado: El módulo Análisis de Sentimientos debe estar configurado y activo.
- Plugin Explorador de Datos: Requerido para ejecutar estas consultas SQL.
- 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:
- Sentimiento general: El modelo cardiffnlp/twitter-roberta-base-sentiment-latest clasifica las publicaciones como positivas, negativas o neutrales.
- Detección de emociones: El modelo SamLowe/roberta-base-go_emotions identifica emociones específicas en las publicaciones, como alegría, tristeza, ira, etc.
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.