Rapports d'analyse des sentiments et des émotions de l'IA

Le plugin Discourse AI inclut des capacités d’analyse des sentiments qui peuvent vous aider à mieux comprendre le ton émotionnel des discussions au sein de votre communauté. Ce sujet présente deux requêtes détaillées pour l’explorateur de données qui exploitent ces capacités d’IA pour fournir des insights sur les communautés Discourse.

  1. Sentiment IA par catégorie et niveau de confiance total : Une analyse de séries temporelles qui suit les tendances des sentiments par semaine au sein de catégories et de niveaux de confiance spécifiques.
  2. Sujets aberrants d’émotion IA : Identifie les sujets de discussion qui déclenchent des réponses émotionnelles significatives sur un site Discourse.

Prérequis

Pour utiliser ces rapports, vous avez besoin de :

  1. Plugin Discourse AI installé et activé : Le plugin Discourse AI doit être installé sur votre instance.
  2. Analyse des sentiments activée : Le module Analyse des sentiments doit être configuré et actif.
  3. Plugin Data Explorer : Requis pour exécuter ces requêtes SQL.
  4. Données historiques de sentiments : Suffisamment de posts analysés pour des résultats significatifs (une opération de remplissage rétrospectif peut être nécessaire).

Modèles de sentiment IA et leur fonctionnement

Avant de plonger dans les rapports, il est utile de comprendre ce que les modèles de sentiment analysent dans les posts de votre communauté :

Ces modèles analysent le texte de chaque post et stockent leurs classifications dans votre base de données, qui peuvent ensuite être interrogées par le plugin Data Explorer.

Rapport Sentiment IA par catégorie et niveau de confiance total

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

-- Créer un jeu de résultats temporaire qui agrège les métriques de sentiment par semaine pour la catégorie spécifiée
WITH sentiment_counts AS (
  SELECT 
    c.id as category_id,
    c.name as category_name,
    -- Regrouper les posts par semaine pour l'analyse de séries temporelles
    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,
    -- Compter les posts avec un sentiment positif (seuil > 0.6)
    COUNT(CASE WHEN (cr.classification::jsonb->'positive')::float > 0.6 THEN 1 
              ELSE NULL END) as positive_count,
    -- Compter les posts avec un sentiment négatif (seuil > 0.6)
    COUNT(CASE WHEN (cr.classification::jsonb->'negative')::float > 0.6 THEN 1 
              ELSE NULL END) as negative_count,
    -- Compter les posts avec un sentiment neutre (positif et négatif <= 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,
    -- Nombre total de posts avec analyse de sentiment
    COUNT(*) as total_classifications
  FROM classification_results cr
  -- Joindre les données des posts pour obtenir les dates de création et les métadonnées
  JOIN posts p ON p.id = cr.target_id AND cr.target_type = 'Post'
  -- Joindre les données des sujets pour filtrer par catégorie
  JOIN topics t ON t.id = p.topic_id
  -- Joindre les données des utilisateurs pour filtrer par niveau de confiance
  JOIN users u ON u.id = p.user_id
  -- Joindre les données des catégories pour obtenir le nom de la catégorie
  JOIN categories c ON c.id = t.category_id
  WHERE 
    -- Inclure uniquement les résultats de sentiment de ce modèle spécifique
    cr.model_used = 'cardiffnlp/twitter-roberta-base-sentiment-latest'
    -- Inclure uniquement les sujets réguliers (pas de MP, etc.)
    AND t.archetype = 'regular'
    -- Exclure les posts système
    AND p.user_id > 0
    -- Filtrer par la catégorie sélectionnée
    AND c.id = :category_id
    -- Filtrer par le niveau de confiance minimum
    AND u.trust_level >= :min_trust_level
    -- Exclure les utilisateurs du personnel si le paramètre est coché
    AND (:exclude_staff = false OR (u.admin = false AND u.moderator = false))
    -- Filtrer par plage de dates
    AND p.created_at BETWEEN :start_date AND :end_date
  -- Regrouper par semaine et catégorie
  GROUP BY c.id, c.name, week_starting, year, week_number
)
-- Formater les résultats finaux pour l'affichage
SELECT 
  category_id,
  category_name,
  -- Convertir en Date pour un affichage plus propre
  week_starting::Date,
  -- Formater en notation de semaine ISO (AAAA-SXX)
  year || '-W' || LPAD(week_number::text, 2, '0') as year_week,
  -- Calculer le bilan des sentiments (positif moins négatif)
  positive_count - negative_count as sentiment_balance,
  positive_count,
  negative_count,
  neutral_count,
  -- Calculer le pourcentage de posts positifs (arrondi à 2 décimales)
  ROUND(
    (positive_count::float / NULLIF(total_classifications, 0) * 100)::numeric,
    2
  ) as positive_percentage
FROM sentiment_counts
-- Trier chronologiquement pour montrer les tendances des sentiments dans le temps
ORDER BY week_starting ASC

Ce rapport fournit une analyse hebdomadaire des tendances des sentiments au sein d’une catégorie spécifique, montrant :

  • Le nombre de posts positifs, négatifs et neutres pour chaque semaine
  • Un calcul de bilan des sentiments (posts positifs moins posts négatifs)
  • Le pourcentage de posts positifs par rapport au total des posts analysés
  • Un filtrage par niveau de confiance des utilisateurs et une option pour exclure les posts du personnel

Ce rapport est précieux pour :

  • Suivre les tendances des sentiments de la communauté dans le temps au sein de catégories spécifiques
  • Identifier les fluctuations de l’humeur de la communauté qui pourraient être corrélées à des événements ou des changements spécifiques
  • Comparer les sentiments entre différents segments d’utilisateurs (par niveau de confiance)
  • Mesurer l’impact des interventions de modération sur le sentiment global de la communauté

Paramètres

La requête accepte plusieurs paramètres pour personnaliser votre analyse :

  • Plage de dates : Définir les dates de début et de fin pour votre période d’analyse
  • Catégorie : Sélectionner la catégorie à analyser
  • Niveau de confiance minimum : Filtrer pour n’inclure que les posts d’utilisateurs ayant un niveau de confiance égal ou supérieur à un niveau spécifique
  • Exclure le personnel : Option pour supprimer les posts du personnel de l’analyse (pour se concentrer sur les membres réguliers de la communauté)

Résultats

Les résultats sont présentés dans un tableau où chaque ligne représente une semaine de données :

  • Informations sur la catégorie : ID et nom de la catégorie analysée
  • Périodes de temps : Date de début de semaine et notation de semaine ISO (AAAA-SXX)
  • Métriques de sentiment :
    • Bilan des sentiments : La différence entre les posts positifs et négatifs (une valeur positive indique un sentiment global positif)
    • Comptages positifs/négatifs/neutres : Le nombre de posts dans chaque catégorie de sentiment
    • Pourcentage positif : Le pourcentage de posts classés comme positifs

Exemple de résultats

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

Rapport Sujets aberrants d’émotion 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  

-- D'abord, créer une Expression de Table Commune (CTE) qui agrège les réactions émotionnelles par sujet
WITH topic_emotions AS (
  SELECT
    topics.id AS topic_id,                 -- Stocker l'ID du sujet pour une jointure/filtrage ultérieur
    topics.title,                          -- Inclure le titre du sujet pour des résultats lisibles
    topics.created_at::date AS topic_date, -- Stocker la date de création du sujet
    
    -- Pour chaque type d'émotion, compter les posts où cette émotion dépasse le seuil de confiance de 0.1
    -- La table classification_results stocke les scores d'émotion sous forme de valeurs 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,
    
    -- Calculer le total des réactions émotionnelles pour le classement
    COUNT(*) AS total_emotional_reactions
  FROM
    classification_results
  -- Joindre la table posts pour obtenir les métadonnées des posts et filtrer les posts supprimés
  INNER JOIN
    posts ON posts.id = classification_results.target_id AND
    posts.deleted_at IS NULL               -- Exclure les posts supprimés
  
  -- Joindre la table topics pour obtenir les métadonnées des sujets et filtrer par type/statut du sujet
  INNER JOIN
    topics ON topics.id = posts.topic_id AND
    topics.archetype = 'regular' AND       -- Inclure uniquement les sujets standards (pas de MP ni de messages système)
    topics.deleted_at IS NULL              -- Exclure les sujets supprimés
  
  -- Joindre la table users pour obtenir le niveau de confiance des utilisateurs pour le filtrage
  INNER JOIN
    users ON users.id = posts.user_id
  
  WHERE
    -- Inclure uniquement les classifications d'émotion pour les posts (pas d'autres types de contenu)
    classification_results.target_type = 'Post' AND
    
    -- Utiliser uniquement les résultats de ce modèle spécifique de détection d'émotion
    classification_results.model_used = 'SamLowe/roberta-base-go_emotions' AND
    
    -- Filtrer par plage de dates en utilisant des valeurs paramétrées
    posts.created_at BETWEEN :start_date AND :end_date AND
    
    -- Filtrer par la catégorie spécifiée
    (topics.category_id = :category_id) AND
    
    -- Inclure uniquement les posts d'utilisateurs ayant un niveau de confiance suffisant
    (users.trust_level >= :min_trust_level)
    
  -- Regrouper tous les comptages par sujet
  GROUP BY 
    topics.id, topics.title, topics.created_at::date
)

-- Requête principale qui formate et filtre les données agrégées de la CTE
SELECT
  topic_id,                                -- Afficher l'ID du sujet (sera rendu comme un lien dans Discourse)
  --title,                                   -- Afficher le titre du sujet
  topic_date,                              -- Afficher la date de création du sujet
  total_emotional_reactions,               -- Afficher le nombre total d'émotions détectées
  
  -- Convertir le tableau d'émotions significatives en une chaîne formatée
  -- Seules les émotions dépassant le seuil sont incluses, les autres deviennent NULL et sont omises
  -- Chaque émotion est formatée comme "NomEmotion(compte)"
  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 'Colère(' || anger_count || ')' ELSE NULL END,
    CASE WHEN annoyance_count >= :emotion_threshold THEN 'Agacement(' || annoyance_count || ')' ELSE NULL END,
    CASE WHEN approval_count >= :emotion_threshold THEN 'Approbation(' || approval_count || ')' ELSE NULL END,
    CASE WHEN caring_count >= :emotion_threshold THEN 'Bienveillance(' || 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 'Curiosité(' || curiosity_count || ')' ELSE NULL END,
    CASE WHEN desire_count >= :emotion_threshold THEN 'Désir(' || desire_count || ')' ELSE NULL END,
    CASE WHEN disappointment_count >= :emotion_threshold THEN 'Déception(' || disappointment_count || ')' ELSE NULL END,
    CASE WHEN disapproval_count >= :emotion_threshold THEN 'Désapprobation(' || disapproval_count || ')' ELSE NULL END,
    CASE WHEN disgust_count >= :emotion_threshold THEN 'Dégoût(' || disgust_count || ')' ELSE NULL END,
    CASE WHEN embarrassment_count >= :emotion_threshold THEN 'Embarras(' || embarrassment_count || ')' ELSE NULL END,
    CASE WHEN excitement_count >= :emotion_threshold THEN 'Excitation(' || excitement_count || ')' ELSE NULL END,
    CASE WHEN fear_count >= :emotion_threshold THEN 'Peur(' || 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 'Chagrin(' || grief_count || ')' ELSE NULL END,
    CASE WHEN joy_count >= :emotion_threshold THEN 'Joie(' || joy_count || ')' ELSE NULL END,
    CASE WHEN love_count >= :emotion_threshold THEN 'Amour(' || love_count || ')' ELSE NULL END,
    CASE WHEN nervousness_count >= :emotion_threshold THEN 'Nervosité(' || nervousness_count || ')' ELSE NULL END,
    CASE WHEN optimism_count >= :emotion_threshold THEN 'Optimisme(' || optimism_count || ')' ELSE NULL END,
    CASE WHEN pride_count >= :emotion_threshold THEN 'Fierté(' || pride_count || ')' ELSE NULL END,
    CASE WHEN realization_count >= :emotion_threshold THEN 'Réalisation(' || realization_count || ')' ELSE NULL END,
    CASE WHEN relief_count >= :emotion_threshold THEN 'Soulagement(' || relief_count || ')' ELSE NULL END,
    CASE WHEN remorse_count >= :emotion_threshold THEN 'Remords(' || remorse_count || ')' ELSE NULL END,
    CASE WHEN sadness_count >= :emotion_threshold THEN 'Tristesse(' || sadness_count || ')' ELSE NULL END,
    CASE WHEN surprise_count >= :emotion_threshold THEN 'Surprise(' || surprise_count || ')' ELSE NULL END
  ], ', ', '') AS significant_emotions     -- Joindre avec des délimiteurs virgule, chaîne vide si aucun délimiteur n'est nécessaire
  
FROM 
  topic_emotions
WHERE 
  -- Inclure uniquement les sujets ayant au moins une émotion dépassant le seuil
  -- Cela identifie les sujets ayant un impact émotionnel significatif
  (
    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
  )
-- Trier les résultats par le plus grand nombre de réactions émotionnelles en premier
ORDER BY
  total_emotional_reactions DESC

Ce rapport identifie les sujets qui ont déclenché des réponses émotionnelles significatives dans votre communauté, basé sur :

  • Un comptage de chaque type d’émotion détecté dans les posts au sein du sujet
  • Un seuil configurable pour déterminer ce qui constitue une réponse émotionnelle “significative”
  • Un filtrage par catégorie, plage de dates et niveau de confiance des utilisateurs

Ce rapport vous aide à :

  • Identifier les discussions potentiellement problématiques générant de fortes émotions négatives
  • Trouver du contenu très engageant qui résonne émotionnellement avec votre communauté
  • Détecter les sujets qui pourraient nécessiter une attention de modération avant qu’ils ne s’aggravent
  • Découvrir des thèmes de contenu qui déclenchent des réponses émotionnelles spécifiques
  • Mieux comprendre ce qui motive l’engagement émotionnel dans votre communauté

Paramètres

La requête accepte plusieurs paramètres :

  • Plage de dates : Définir les dates de début et de fin pour votre période d’analyse
  • Catégorie : Sélectionner la catégorie à analyser
  • Niveau de confiance minimum : Filtrer pour n’inclure que les posts d’utilisateurs ayant un niveau de confiance égal ou supérieur à un niveau spécifique
  • Seuil d’émotion : Définir le nombre d’occurrences d’une émotion requis pour la considérer comme significative

Résultats

Les résultats montrent :

  • ID du sujet : Lien direct vers le sujet (cliquable dans Data Explorer)
  • Date du sujet : Date de création du sujet
  • Total des réactions émotionnelles : Le nombre total de réactions émotionnelles détectées
  • Émotions significatives : Une liste formatée des émotions ayant dépassé votre seuil, avec leurs comptes indiqués entre parenthèses

Les émotions détectées incluent un large éventail : admiration, amusement, colère, agacement, approbation, bienveillance, confusion, curiosité, désir, déception, désapprobation, dégoût, embarras, excitation, peur, gratitude, chagrin, joie, amour, nervosité, neutre, optimisme, fierté, réalisation, soulagement, remords, tristesse et surprise.

Exemple de résultats

topic topic_date total_emotional_reactions significant_emotions
Feature Request: Increased API Rate Limits 2025-03-06 42 Approbation(15), Confusion(9), Curiosité(7), Gratitude(8)
Authentication Error with Third-Party Integration 2025-01-07 33 Curiosité(6), Gratitude(5), Désapprobation(8), Frustration(9)
Best Practices for Configuration Settings 2025-02-16 31 Curiosité(9), Excitation(6), Gratitude(5), Optimisme(5)
Troubleshooting Database Connection Issues 2025-01-15 29 Curiosité(7), Confusion(8), Déception(6), Frustration(5)
Critical Bug in Latest Beta Release 2025-02-02 26 Confusion(7), Préoccupation(6), Désapprobation(5), Urgence(6)

Applications pratiques dans la gestion de communauté

Ces rapports peuvent améliorer votre flux de travail de gestion de communauté de plusieurs façons :

  • Intervention précoce : Identifier les sujets chargés émotionnellement qui pourraient nécessiter une modération avant de devenir problématiques
  • Planification du contenu : Utiliser les insights sur ce qui déclenche des émotions positives pour informer votre stratégie de contenu
  • Mesure de l’impact : Évaluer comment les changements de politique, les nouvelles fonctionnalités ou les événements affectent le sentiment de la communauté
  • Engagement ciblé : Concentrer l’attention du personnel sur les sujets avec de fortes réactions émotionnelles qui pourraient bénéficier de réponses officielles

Ressources supplémentaires

1 « J'aime »