Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit 48d08de

Browse files
authored
FEATURE: Emotion activity metrics table (#916)
1 parent b10be23 commit 48d08de

File tree

16 files changed

+389
-207
lines changed

16 files changed

+389
-207
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<div class="cell title">
2+
{{#if this.model.icon}}
3+
{{d-icon this.model.icon}}
4+
{{/if}}
5+
<a href="{{this.filterURL}}{{this.model.type}}">{{this.model.title}}</a>
6+
</div>
7+
8+
<div class="cell value today-count">{{number this.model.todayCount}}</div>
9+
10+
<div
11+
class="cell value yesterday-count {{this.model.yesterdayTrend}}"
12+
title={{this.model.yesterdayCountTitle}}
13+
>
14+
{{number this.model.yesterdayCount}}
15+
{{d-icon this.model.yesterdayTrendIcon}}
16+
</div>
17+
18+
<div
19+
class="cell value sevendays-count {{this.model.sevenDaysTrend}}"
20+
title={{this.model.sevenDaysCountTitle}}
21+
>
22+
{{number this.model.lastSevenDaysCount}}
23+
{{d-icon this.model.sevenDaysTrendIcon}}
24+
</div>
25+
26+
<div
27+
class="cell value thirty-days-count {{this.model.thirtyDaysTrend}}"
28+
title={{this.model.thirtyDaysCountTitle}}
29+
>
30+
{{number this.model.lastThirtyDaysCount}}
31+
32+
{{#if this.model.canDisplayTrendIcon}}
33+
{{d-icon this.model.thirtyDaysTrendIcon}}
34+
{{/if}}
35+
</div>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Component from "@ember/component";
2+
import { attributeBindings, classNames } from "@ember-decorators/component";
3+
import getURL from "discourse-common/lib/get-url";
4+
5+
@classNames("admin-report-counters")
6+
@attributeBindings("model.description:title")
7+
export default class AdminReportEmotion extends Component {
8+
get filterURL() {
9+
let aMonthAgo = moment().subtract(1, "month").format("YYYY-MM-DD");
10+
return getURL(`/filter?q=activity-after%3A${aMonthAgo}%20order%3A`);
11+
}
12+
}
Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,37 @@
1-
import { computed } from "@ember/object";
21
import AdminDashboardTabController from "admin/controllers/admin-dashboard-tab";
32

43
export default class AdminDashboardSentiment extends AdminDashboardTabController {
5-
@computed("startDate", "endDate")
6-
get filters() {
7-
return { startDate: this.startDate, endDate: this.endDate };
4+
get emotions() {
5+
const emotions = [
6+
"admiration",
7+
"amusement",
8+
"anger",
9+
"annoyance",
10+
"approval",
11+
"caring",
12+
"confusion",
13+
"curiosity",
14+
"desire",
15+
"disappointment",
16+
"disapproval",
17+
"disgust",
18+
"embarrassment",
19+
"excitement",
20+
"fear",
21+
"gratitude",
22+
"grief",
23+
"joy",
24+
"love",
25+
"nervousness",
26+
"neutral",
27+
"optimism",
28+
"pride",
29+
"realization",
30+
"relief",
31+
"remorse",
32+
"sadness",
33+
"surprise",
34+
];
35+
return emotions;
836
}
937
}

assets/javascripts/discourse/templates/admin-dashboard-sentiment.hbs

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,43 @@
2222
@filters={{this.filters}}
2323
@showHeader={{true}}
2424
/>
25-
26-
<AdminReport
27-
@dataSourceName="post_emotion"
28-
@filters={{this.filters}}
29-
@showHeader={{true}}
30-
/>
25+
<div class="admin-report activity-metrics">
26+
<div class="header">
27+
<ul class="breadcrumb">
28+
<li class="item report">
29+
<LinkTo @route="adminReports" class="report-url">
30+
{{i18n "admin.dashboard.emotion"}}
31+
</LinkTo>
32+
</li>
33+
</ul>
34+
</div>
35+
<div class="report-body">
36+
<div class="counters-list">
37+
<div class="counters-header">
38+
<div class="counters-cell"></div>
39+
<div class="counters-cell">{{i18n
40+
"admin.dashboard.reports.today"
41+
}}</div>
42+
<div class="counters-cell">{{i18n
43+
"admin.dashboard.reports.yesterday"
44+
}}</div>
45+
<div class="counters-cell">{{i18n
46+
"admin.dashboard.reports.last_7_days"
47+
}}</div>
48+
<div class="counters-cell">{{i18n
49+
"admin.dashboard.reports.last_30_days"
50+
}}</div>
51+
</div>
52+
{{#each this.emotions as |metric|}}
53+
<AdminReport
54+
@showHeader={{false}}
55+
@forcedModes="emotion"
56+
@dataSourceName="emotion_{{metric}}"
57+
/>
58+
{{/each}}
59+
</div>
60+
</div>
61+
</div>
3162
</div>
3263
</div>
3364
</div>

assets/stylesheets/modules/sentiment/common/dashboard.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@
44
grid-template-columns: repeat(12, 1fr);
55
grid-column-gap: 1em;
66
grid-row-gap: 1em;
7+
.admin-report {
8+
grid-column: span 12;
9+
}
710
}
811
}

assets/stylesheets/modules/sentiment/desktop/dashboard.scss

Lines changed: 0 additions & 8 deletions
This file was deleted.

assets/stylesheets/modules/sentiment/mobile/dashboard.scss

Lines changed: 0 additions & 10 deletions
This file was deleted.

config/locales/client.en.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ en:
1111
site_settings:
1212
categories:
1313
discourse_ai: "Discourse AI"
14+
dashboard:
15+
emotion: "Emotion"
1416
js:
1517
discourse_automation:
1618
scriptables:

config/locales/server.en.yml

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ en:
8686
ai_custom_summarization_allowed_groups: "Groups allowed to use create new summaries."
8787
ai_pm_summarization_allowed_groups: "Groups allowed to create and view summaries in PMs."
8888
ai_summarize_max_hot_topics_gists_per_batch: "After updating topics in the hot list, we'll generate brief summaries of the first N ones. (Disabled when 0)"
89-
ai_hot_topic_gists_allowed_groups: "Groups allowed to see gists in the hot topics list."
89+
ai_hot_topic_gists_allowed_groups: "Groups allowed to see gists in the hot topics list."
9090
ai_summary_backfill_maximum_topics_per_hour: "Number of topic summaries to backfill per hour."
9191

9292
ai_bot_enabled: "Enable the AI Bot module."
@@ -112,14 +112,65 @@ en:
112112
reports:
113113
overall_sentiment:
114114
title: "Overall sentiment"
115-
description: "The chart compares the number of posts classified as either positive or negative. These are calculated when positive or negative scores > the set threshold score. This means neutral posts are not shown. Private messages (PMs) are also excluded. Classified with \"cardiffnlp/twitter-roberta-base-sentiment-latest\""
115+
description: 'The chart compares the number of posts classified as either positive or negative. These are calculated when positive or negative scores > the set threshold score. This means neutral posts are not shown. Private messages (PMs) are also excluded. Classified with "cardiffnlp/twitter-roberta-base-sentiment-latest"'
116116
xaxis: "Positive(%)"
117117
yaxis: "Date"
118-
post_emotion:
119-
title: "Post emotion"
120-
description: "Number of posts classified with one of the following emotions, grouped by poster's trust level. Posts that are not positive or negative and considered neutral, are not shown. Private messages (PMs) are also excluded. Classified with \"j-hartmann/emotion-english-roberta-large\""
121-
xaxis:
122-
yaxis:
118+
emotion_admiration:
119+
title: Admiration
120+
emotion_amusement:
121+
title: Amusement
122+
emotion_anger:
123+
title: Anger
124+
emotion_annoyance:
125+
title: Annoyance
126+
emotion_approval:
127+
title: Approval
128+
emotion_caring:
129+
title: Caring
130+
emotion_confusion:
131+
title: Confusion
132+
emotion_curiosity:
133+
title: Curiosity
134+
emotion_desire:
135+
title: Desire
136+
emotion_disappointment:
137+
title: Disappointment
138+
emotion_disapproval:
139+
title: Disapproval
140+
emotion_disgust:
141+
title: Disgust
142+
emotion_embarrassment:
143+
title: Embarrassment
144+
emotion_excitement:
145+
title: Excitement
146+
emotion_fear:
147+
title: Fear
148+
emotion_gratitude:
149+
title: Gratitude
150+
emotion_grief:
151+
title: Grief
152+
emotion_joy:
153+
title: Joy
154+
emotion_love:
155+
title: Love
156+
emotion_nervousness:
157+
title: Nervousness
158+
emotion_neutral:
159+
title: Neutral
160+
emotion_optimism:
161+
title: Optimism
162+
emotion_pride:
163+
title: Pride
164+
emotion_realization:
165+
title: Realization
166+
emotion_relief:
167+
title: Relief
168+
emotion_remorse:
169+
title: Remorse
170+
emotion_sadness:
171+
title: Sadness
172+
emotion_surprise:
173+
title: Surprise
123174

124175
discourse_ai:
125176
unknown_model: "Unknown AI model"
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# frozen_string_literal: true
2+
3+
module DiscourseAi
4+
module Sentiment
5+
class EmotionDashboardReport
6+
def self.register!(plugin)
7+
Emotions::LIST.each do |emotion|
8+
plugin.add_report("emotion_#{emotion}") do |report|
9+
query_results = DiscourseAi::Sentiment::EmotionDashboardReport.fetch_data
10+
report.data = query_results.pop(30).map { |row| { x: row.day, y: row.send(emotion) } }
11+
report.prev30Days =
12+
query_results.take(30).map { |row| { x: row.day, y: row.send(emotion) } }
13+
end
14+
end
15+
16+
def self.fetch_data
17+
DB.query(<<~SQL, end: Time.now.tomorrow.midnight, start: 60.days.ago.midnight)
18+
SELECT
19+
posts.created_at::DATE AS day,
20+
#{
21+
DiscourseAi::Sentiment::Emotions::LIST
22+
.map do |emotion|
23+
"COUNT(*) FILTER (WHERE (classification_results.classification::jsonb->'#{emotion}')::float > 0.1) AS #{emotion}"
24+
end
25+
.join(",\n ")
26+
}
27+
FROM
28+
classification_results
29+
INNER JOIN
30+
posts ON posts.id = classification_results.target_id AND
31+
posts.deleted_at IS NULL AND
32+
posts.created_at BETWEEN :start AND :end
33+
INNER JOIN
34+
topics ON topics.id = posts.topic_id AND
35+
topics.archetype = 'regular' AND
36+
topics.deleted_at IS NULL
37+
WHERE
38+
classification_results.target_type = 'Post' AND
39+
classification_results.model_used = 'SamLowe/roberta-base-go_emotions'
40+
GROUP BY 1
41+
ORDER BY 1 ASC
42+
SQL
43+
end
44+
end
45+
end
46+
end
47+
end

0 commit comments

Comments
 (0)