98 lines
3.1 KiB
Ruby
98 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module DiscourseAi
|
|
module Sentiment
|
|
class SentimentController < ::Admin::StaffController
|
|
include Constants
|
|
requires_plugin ::DiscourseAi::PLUGIN_NAME
|
|
|
|
DEFAULT_POSTS_LIMIT = 50
|
|
MAX_POSTS_LIMIT = 100
|
|
|
|
def posts
|
|
group_by = params.required(:group_by)&.to_sym
|
|
group_value = params.required(:group_value).presence
|
|
start_date = params[:start_date].presence
|
|
end_date = params[:end_date]
|
|
threshold = SENTIMENT_THRESHOLD
|
|
|
|
raise Discourse::InvalidParameters if %i[category tag].exclude?(group_by)
|
|
|
|
limit = fetch_limit_from_params(default: DEFAULT_POSTS_LIMIT, max: MAX_POSTS_LIMIT)
|
|
offset = params[:offset].to_i || 0
|
|
|
|
case group_by
|
|
when :category
|
|
grouping_clause = "c.name"
|
|
grouping_join = "" # categories already joined
|
|
when :tag
|
|
grouping_clause = "tags.name"
|
|
grouping_join =
|
|
"INNER JOIN topic_tags tt ON tt.topic_id = p.topic_id INNER JOIN tags ON tags.id = tt.tag_id"
|
|
end
|
|
|
|
posts =
|
|
DB.query(
|
|
<<~SQL,
|
|
SELECT
|
|
p.id AS post_id,
|
|
p.topic_id,
|
|
t.fancy_title AS topic_title,
|
|
p.cooked as post_cooked,
|
|
p.user_id,
|
|
p.post_number,
|
|
p.created_at AS created_at,
|
|
u.username,
|
|
u.name,
|
|
u.uploaded_avatar_id,
|
|
c.id AS category_id,
|
|
(CASE
|
|
WHEN (cr.classification::jsonb->'positive')::float > :threshold THEN 'positive'
|
|
WHEN (cr.classification::jsonb->'negative')::float > :threshold THEN 'negative'
|
|
ELSE 'neutral'
|
|
END) AS sentiment
|
|
FROM posts p
|
|
INNER JOIN topics t ON t.id = p.topic_id
|
|
INNER JOIN classification_results cr ON cr.target_id = p.id AND cr.target_type = 'Post'
|
|
LEFT JOIN users u ON u.id = p.user_id
|
|
LEFT JOIN categories c ON c.id = t.category_id
|
|
#{grouping_join}
|
|
WHERE
|
|
#{grouping_clause} = :group_value AND
|
|
t.archetype = 'regular' AND
|
|
p.user_id > 0 AND
|
|
cr.model_used = 'cardiffnlp/twitter-roberta-base-sentiment-latest' AND
|
|
((:start_date IS NULL OR p.created_at > :start_date) AND (:end_date IS NULL OR p.created_at < :end_date))
|
|
AND p.deleted_at IS NULL
|
|
ORDER BY p.created_at DESC
|
|
LIMIT :limit OFFSET :offset
|
|
SQL
|
|
group_value: group_value,
|
|
start_date: start_date,
|
|
end_date: end_date,
|
|
threshold: threshold,
|
|
limit: limit + 1,
|
|
offset: offset,
|
|
)
|
|
|
|
has_more = posts.length > limit
|
|
posts.pop if has_more
|
|
|
|
render_json_dump(
|
|
posts:
|
|
serialize_data(
|
|
posts,
|
|
AiSentimentPostSerializer,
|
|
scope: guardian,
|
|
add_raw: true,
|
|
add_excerpt: true,
|
|
add_title: true,
|
|
),
|
|
has_more: has_more,
|
|
next_offset: has_more ? offset + limit : nil,
|
|
)
|
|
end
|
|
end
|
|
end
|
|
end
|