2023-02-23 13:50:10 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2023-11-08 08:50:37 -05:00
|
|
|
require_relative "../../../support/sentiment_inference_stubs"
|
2023-02-23 13:50:10 -05:00
|
|
|
|
2023-11-08 08:50:37 -05:00
|
|
|
RSpec.describe DiscourseAi::Sentiment::EntryPoint do
|
2023-12-13 22:07:28 -05:00
|
|
|
fab!(:user) { Fabricate(:user, refresh_auto_groups: true) }
|
2023-02-23 13:50:10 -05:00
|
|
|
|
|
|
|
describe "registering event callbacks" do
|
|
|
|
context "when creating a post" do
|
|
|
|
let(:creator) do
|
|
|
|
PostCreator.new(
|
|
|
|
user,
|
|
|
|
raw: "this is the new content for my topic",
|
|
|
|
title: "this is my new topic title",
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "queues a job on create if sentiment analysis is enabled" do
|
|
|
|
SiteSetting.ai_sentiment_enabled = true
|
|
|
|
|
|
|
|
expect { creator.create }.to change(Jobs::PostSentimentAnalysis.jobs, :size).by(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does nothing if sentiment analysis is disabled" do
|
|
|
|
SiteSetting.ai_sentiment_enabled = false
|
|
|
|
|
|
|
|
expect { creator.create }.not_to change(Jobs::PostSentimentAnalysis.jobs, :size)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when editing a post" do
|
|
|
|
fab!(:post) { Fabricate(:post, user: user) }
|
|
|
|
let(:revisor) { PostRevisor.new(post) }
|
|
|
|
|
|
|
|
it "queues a job on update if sentiment analysis is enabled" do
|
|
|
|
SiteSetting.ai_sentiment_enabled = true
|
|
|
|
|
|
|
|
expect { revisor.revise!(user, raw: "This is my new test") }.to change(
|
|
|
|
Jobs::PostSentimentAnalysis.jobs,
|
|
|
|
:size,
|
|
|
|
).by(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does nothing if sentiment analysis is disabled" do
|
|
|
|
SiteSetting.ai_sentiment_enabled = false
|
|
|
|
|
|
|
|
expect { revisor.revise!(user, raw: "This is my new test") }.not_to change(
|
|
|
|
Jobs::PostSentimentAnalysis.jobs,
|
|
|
|
:size,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2023-11-08 08:50:37 -05:00
|
|
|
|
|
|
|
describe "custom reports" do
|
2024-11-04 07:14:34 -05:00
|
|
|
before do
|
|
|
|
SiteSetting.ai_sentiment_model_configs =
|
|
|
|
"[{\"model_name\":\"SamLowe/roberta-base-go_emotions\",\"endpoint\":\"http://samlowe-emotion.com\",\"api_key\":\"123\"},{\"model_name\":\"j-hartmann/emotion-english-distilroberta-base\",\"endpoint\":\"http://jhartmann-emotion.com\",\"api_key\":\"123\"},{\"model_name\":\"cardiffnlp/twitter-roberta-base-sentiment-latest\",\"endpoint\":\"http://cardiffnlp-sentiment.com\",\"api_key\":\"123\"}]"
|
|
|
|
end
|
2023-11-08 08:50:37 -05:00
|
|
|
|
|
|
|
fab!(:pm) { Fabricate(:private_message_post) }
|
|
|
|
|
|
|
|
fab!(:post_1) { Fabricate(:post) }
|
|
|
|
fab!(:post_2) { Fabricate(:post) }
|
|
|
|
|
|
|
|
describe "overall_sentiment report" do
|
2024-11-04 07:14:34 -05:00
|
|
|
let(:positive_classification) { { negative: 0.2, neutral: 0.3, positive: 0.7 } }
|
|
|
|
let(:negative_classification) { { negative: 0.65, neutral: 0.2, positive: 0.1 } }
|
2023-11-08 08:50:37 -05:00
|
|
|
|
|
|
|
def sentiment_classification(post, classification)
|
|
|
|
Fabricate(:sentiment_classification, target: post, classification: classification)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "calculate averages using only public posts" do
|
|
|
|
sentiment_classification(post_1, positive_classification)
|
|
|
|
sentiment_classification(post_2, negative_classification)
|
|
|
|
sentiment_classification(pm, positive_classification)
|
|
|
|
|
|
|
|
report = Report.find("overall_sentiment")
|
|
|
|
positive_data_point = report.data[0][:data].first[:y].to_i
|
|
|
|
negative_data_point = report.data[1][:data].first[:y].to_i
|
|
|
|
|
2023-11-09 15:23:25 -05:00
|
|
|
expect(positive_data_point).to eq(1)
|
|
|
|
expect(negative_data_point).to eq(-1)
|
2023-11-08 08:50:37 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "post_emotion report" do
|
|
|
|
let(:emotion_1) do
|
2024-11-04 07:14:34 -05:00
|
|
|
{
|
|
|
|
sadness: 0.49,
|
|
|
|
surprise: 0.23,
|
|
|
|
neutral: 0.6,
|
|
|
|
fear: 0.34,
|
|
|
|
anger: 0.87,
|
|
|
|
joy: 0.22,
|
|
|
|
disgust: 0.70,
|
|
|
|
}
|
2023-11-08 08:50:37 -05:00
|
|
|
end
|
|
|
|
let(:emotion_2) do
|
2024-11-04 07:14:34 -05:00
|
|
|
{
|
|
|
|
sadness: 0.19,
|
|
|
|
surprise: 0.63,
|
|
|
|
neutral: 0.45,
|
|
|
|
fear: 0.44,
|
|
|
|
anger: 0.27,
|
|
|
|
joy: 0.62,
|
|
|
|
disgust: 0.30,
|
|
|
|
}
|
2023-11-08 08:50:37 -05:00
|
|
|
end
|
2024-11-04 07:14:34 -05:00
|
|
|
let(:model_used) { "j-hartmann/emotion-english-distilroberta-base" }
|
2023-11-08 08:50:37 -05:00
|
|
|
|
|
|
|
def emotion_classification(post, classification)
|
|
|
|
Fabricate(
|
|
|
|
:sentiment_classification,
|
|
|
|
target: post,
|
2023-11-08 12:58:35 -05:00
|
|
|
model_used: model_used,
|
2023-11-08 08:50:37 -05:00
|
|
|
classification: classification,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2024-08-02 17:23:29 -04:00
|
|
|
def strip_emoji_and_downcase(str)
|
|
|
|
stripped_str = str.gsub(/[^\p{L}\p{N}]+/, "") # remove any non-alphanumeric characters
|
|
|
|
stripped_str.downcase
|
|
|
|
end
|
|
|
|
|
2023-11-08 08:50:37 -05:00
|
|
|
it "calculate averages using only public posts" do
|
2024-11-04 07:14:34 -05:00
|
|
|
threshold = 0.30
|
2023-11-08 08:50:37 -05:00
|
|
|
|
|
|
|
emotion_classification(post_1, emotion_1)
|
|
|
|
emotion_classification(post_2, emotion_2)
|
|
|
|
emotion_classification(pm, emotion_2)
|
|
|
|
|
|
|
|
report = Report.find("post_emotion")
|
2023-11-09 15:23:25 -05:00
|
|
|
|
2024-08-02 17:23:29 -04:00
|
|
|
data_point = report.data
|
2023-11-09 15:23:25 -05:00
|
|
|
|
2024-08-02 17:23:29 -04:00
|
|
|
data_point.each do |point|
|
|
|
|
emotion = strip_emoji_and_downcase(point[:label])
|
|
|
|
expected =
|
|
|
|
(emotion_1[emotion.to_sym] > threshold ? 1 : 0) +
|
|
|
|
(emotion_2[emotion.to_sym] > threshold ? 1 : 0)
|
|
|
|
expect(point[:data][0][:y]).to eq(expected)
|
2023-11-09 15:23:25 -05:00
|
|
|
end
|
2023-11-08 08:50:37 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2023-02-23 13:50:10 -05:00
|
|
|
end
|