# frozen_string_literal: true require_relative "../../../support/sentiment_inference_stubs" RSpec.describe DiscourseAi::Sentiment::EntryPoint do fab!(:user) { Fabricate(:user, refresh_auto_groups: true) } 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 describe "custom reports" do 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 fab!(:pm) { Fabricate(:private_message_post) } fab!(:post_1) { Fabricate(:post) } fab!(:post_2) { Fabricate(:post) } describe "overall_sentiment report" do let(:positive_classification) { { negative: 0.2, neutral: 0.3, positive: 0.7 } } let(:negative_classification) { { negative: 0.65, neutral: 0.2, positive: 0.1 } } 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 expect(positive_data_point).to eq(1) expect(negative_data_point).to eq(-1) end end describe "post_emotion report" do let(:emotion_1) do { love: 0.9444406, admiration: 0.013724019, surprise: 0.010188869, excitement: 0.007888741, curiosity: 0.006301749, joy: 0.004060776, confusion: 0.0028238264, approval: 0.0018160914, realization: 0.001174849, neutral: 0.0008561869, amusement: 0.00075853954, disapproval: 0.0006987994, disappointment: 0.0006166883, anger: 0.0006000542, annoyance: 0.0005615011, desire: 0.00046368592, fear: 0.00045117878, sadness: 0.00041727215, gratitude: 0.00041727215, optimism: 0.00037112957, disgust: 0.00035552034, nervousness: 0.00022954118, embarrassment: 0.0002049572, caring: 0.00017737568, remorse: 0.00011407586, grief: 0.0001006716, pride: 0.00009681493, relief: 0.00008919009, } end let(:emotion_2) do { love: 0.8444406, admiration: 0.113724019, surprise: 0.010188869, excitement: 0.007888741, curiosity: 0.006301749, joy: 0.004060776, confusion: 0.0028238264, approval: 0.0018160914, realization: 0.001174849, neutral: 0.0008561869, amusement: 0.00075853954, disapproval: 0.0006987994, disappointment: 0.0006166883, anger: 0.0006000542, annoyance: 0.0005615011, desire: 0.00046368592, fear: 0.00045117878, sadness: 0.00041727215, gratitude: 0.00041727215, optimism: 0.00037112957, disgust: 0.00035552034, nervousness: 0.00022954118, embarrassment: 0.0002049572, caring: 0.00017737568, remorse: 0.00011407586, grief: 0.0001006716, pride: 0.00009681493, relief: 0.00008919009, } end let(:model_used) { "SamLowe/roberta-base-go_emotions" } def emotion_classification(post, classification) Fabricate( :sentiment_classification, target: post, model_used: model_used, classification: classification, ) end def strip_emoji_and_downcase(str) stripped_str = str.gsub(/[^\p{L}\p{N}]+/, "") # remove any non-alphanumeric characters stripped_str.downcase end it "calculate averages using only public posts" do threshold = 0.10 emotion_classification(post_1, emotion_1) emotion_classification(post_2, emotion_2) emotion_classification(pm, emotion_2) report = Report.find("emotion_love") data_point = report.data data_point.each do |point| expected = (emotion_1[:love] > threshold ? 1 : 0) + (emotion_2[:love] > threshold ? 1 : 0) expect(point[:y]).to eq(expected) end end end end end