2023-02-23 12:25:00 -03:00
|
|
|
# frozen_string_literal: true
|
2023-03-14 16:03:50 -03:00
|
|
|
|
|
|
|
module DiscourseAi
|
2023-02-23 12:25:00 -03:00
|
|
|
module Sentiment
|
|
|
|
class EntryPoint
|
2023-02-23 15:50:10 -03:00
|
|
|
def load_files
|
2023-02-24 13:25:02 -03:00
|
|
|
require_relative "sentiment_classification"
|
2023-02-24 07:53:43 -03:00
|
|
|
require_relative "jobs/regular/post_sentiment_analysis"
|
2023-02-23 15:50:10 -03:00
|
|
|
end
|
2023-02-23 12:25:00 -03:00
|
|
|
|
2023-02-23 15:50:10 -03:00
|
|
|
def inject_into(plugin)
|
|
|
|
sentiment_analysis_cb =
|
|
|
|
Proc.new do |post|
|
|
|
|
if SiteSetting.ai_sentiment_enabled
|
|
|
|
Jobs.enqueue(:post_sentiment_analysis, post_id: post.id)
|
|
|
|
end
|
|
|
|
end
|
2023-02-23 12:25:00 -03:00
|
|
|
|
2023-02-23 15:50:10 -03:00
|
|
|
plugin.on(:post_created, &sentiment_analysis_cb)
|
|
|
|
plugin.on(:post_edited, &sentiment_analysis_cb)
|
2023-11-08 10:50:37 -03:00
|
|
|
|
|
|
|
plugin.add_report("overall_sentiment") do |report|
|
|
|
|
report.modes = [:stacked_chart]
|
|
|
|
|
|
|
|
grouped_sentiments =
|
|
|
|
DB.query(<<~SQL, report_start: report.start_date, report_end: report.end_date)
|
|
|
|
SELECT
|
|
|
|
DATE_TRUNC('day', p.created_at)::DATE AS posted_at,
|
|
|
|
AVG((cr.classification::jsonb->'positive')::integer) AS avg_positive,
|
|
|
|
-AVG((cr.classification::jsonb->'negative')::integer) AS avg_negative
|
|
|
|
FROM
|
|
|
|
classification_results AS cr
|
|
|
|
INNER JOIN posts p ON p.id = cr.target_id AND cr.target_type = 'Post'
|
|
|
|
INNER JOIN topics t ON t.id = p.topic_id
|
|
|
|
INNER JOIN categories c ON c.id = t.category_id
|
|
|
|
WHERE
|
|
|
|
t.archetype = 'regular' AND
|
|
|
|
p.user_id > 0 AND
|
|
|
|
cr.classification_type = 'sentiment' AND
|
|
|
|
(p.created_at > :report_start AND p.created_at < :report_end)
|
|
|
|
GROUP BY DATE_TRUNC('day', p.created_at)
|
|
|
|
SQL
|
|
|
|
|
|
|
|
data_points = %w[positive negative]
|
|
|
|
|
|
|
|
report.data =
|
|
|
|
data_points.map do |point|
|
|
|
|
{
|
|
|
|
req: "sentiment_#{point}",
|
|
|
|
color: point == "positive" ? report.colors[1] : report.colors[3],
|
|
|
|
label: I18n.t("discourse_ai.sentiment.reports.overall_sentiment.#{point}"),
|
|
|
|
data:
|
|
|
|
grouped_sentiments.map do |gs|
|
|
|
|
{ x: gs.posted_at, y: gs.public_send("avg_#{point}") }
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
plugin.add_report("post_emotion") do |report|
|
|
|
|
report.modes = [:radar]
|
|
|
|
|
|
|
|
grouped_emotions =
|
|
|
|
DB.query(<<~SQL, report_start: report.start_date, report_end: report.end_date)
|
|
|
|
SELECT
|
|
|
|
u.trust_level AS trust_level,
|
|
|
|
AVG((cr.classification::jsonb->'sadness')::integer) AS avg_sadness,
|
|
|
|
AVG((cr.classification::jsonb->'surprise')::integer) AS avg_surprise,
|
|
|
|
AVG((cr.classification::jsonb->'neutral')::integer) AS avg_neutral,
|
|
|
|
AVG((cr.classification::jsonb->'fear')::integer) AS avg_fear,
|
|
|
|
AVG((cr.classification::jsonb->'anger')::integer) AS avg_anger,
|
|
|
|
AVG((cr.classification::jsonb->'joy')::integer) AS avg_joy,
|
|
|
|
AVG((cr.classification::jsonb->'disgust')::integer) AS avg_disgust
|
|
|
|
FROM
|
|
|
|
classification_results AS cr
|
|
|
|
INNER JOIN posts p ON p.id = cr.target_id AND cr.target_type = 'Post'
|
|
|
|
INNER JOIN users u ON p.user_id = u.id
|
|
|
|
INNER JOIN topics t ON t.id = p.topic_id
|
|
|
|
INNER JOIN categories c ON c.id = t.category_id
|
|
|
|
WHERE
|
|
|
|
t.archetype = 'regular' AND
|
|
|
|
p.user_id > 0 AND
|
|
|
|
cr.classification_type = 'emotion' AND
|
|
|
|
(p.created_at > :report_start AND p.created_at < :report_end)
|
|
|
|
GROUP BY u.trust_level
|
|
|
|
SQL
|
|
|
|
|
|
|
|
emotions = %w[sadness surprise neutral fear anger joy disgust]
|
|
|
|
level_groups = [[0, 1], [2, 3, 4]]
|
|
|
|
|
|
|
|
report.data =
|
|
|
|
level_groups.each_with_index.map do |lg, idx|
|
|
|
|
tl_emotion_avgs = grouped_emotions.select { |ge| lg.include?(ge.trust_level) }
|
|
|
|
|
|
|
|
{
|
|
|
|
req: "emotion_tl_#{lg.join}",
|
|
|
|
color: report.colors[idx],
|
|
|
|
label: I18n.t("discourse_ai.sentiment.reports.post_emotion.tl_#{lg.join}"),
|
|
|
|
data:
|
|
|
|
emotions.map do |e|
|
|
|
|
{
|
|
|
|
x: I18n.t("discourse_ai.sentiment.reports.post_emotion.#{e}"),
|
|
|
|
y:
|
|
|
|
tl_emotion_avgs.sum do |tl_emotion_avg|
|
|
|
|
tl_emotion_avg.public_send("avg_#{e}").to_i
|
2023-11-08 13:05:36 -03:00
|
|
|
end / [tl_emotion_avgs.size, 1].max,
|
2023-11-08 10:50:37 -03:00
|
|
|
}
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
2023-02-23 12:25:00 -03:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|