mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-26 03:01:14 +08:00
Cached topic summaries that became outdated after post edits could remain visible longer than intended, and the 1-hour throttle could delay corrective regeneration. This update makes edit-driven staleness a special case: users who can regenerate summaries now bypass the throttle and refresh immediately, while users who cannot regenerate are not served edit-outdated cached content at all. In practice, stale summaries from edited content are no longer a fallback path, but normal throttle behavior is preserved for non-edit staleness such as newly added posts. --- **Security Advisory:** https://github.com/discourse/discourse/security/advisories/GHSA-pr9m-5hpq-wc57
123 lines
4.6 KiB
Ruby
Vendored
123 lines
4.6 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
module DiscourseAi
|
|
module Summarization
|
|
class EntryPoint
|
|
def inject_into(plugin)
|
|
plugin.add_to_serializer(:current_user, :can_request_gists) { scope.can_request_gists? }
|
|
|
|
plugin.add_to_serializer(:current_user, :can_summarize) do
|
|
return false if !SiteSetting.ai_summarization_enabled
|
|
|
|
if (ai_agent = AiAgent.find_by_id_from_cache(SiteSetting.ai_summarization_agent)).blank?
|
|
return false
|
|
end
|
|
scope.user.in_any_groups?(ai_agent.allowed_group_ids.to_a)
|
|
end
|
|
|
|
plugin.add_to_serializer(:topic_view, :summarizable) do
|
|
scope.can_see_summary?(object.topic, cached_summary: ai_summary_record)
|
|
end
|
|
|
|
plugin.add_to_serializer(:topic_view, :has_cached_summary) { ai_summary_record.present? }
|
|
|
|
plugin.add_to_serializer(:web_hook_topic_view, :summarizable) do
|
|
cached_summary =
|
|
DiscourseAi::TopicSummarization.for(object.topic, scope.user).cached_summary
|
|
scope.can_see_summary?(object.topic, cached_summary: cached_summary)
|
|
end
|
|
|
|
plugin.add_to_serializer(
|
|
:topic_view,
|
|
:ai_summary_record,
|
|
include_condition: -> { false },
|
|
) do
|
|
return @ai_summary_record if defined?(@ai_summary_record)
|
|
@ai_summary_record =
|
|
DiscourseAi::TopicSummarization.for(object.topic, scope.user).cached_summary
|
|
end
|
|
|
|
plugin.add_to_serializer(
|
|
:topic_view,
|
|
:ai_summary,
|
|
include_condition: -> do
|
|
next false if !DiscoursePluginRegistry.apply_modifier(:serialize_ai_summary, false)
|
|
|
|
summary_record = ai_summary_record
|
|
scope.can_see_summary?(object.topic, cached_summary: summary_record) &&
|
|
summary_record.present?
|
|
end,
|
|
) do
|
|
{
|
|
id: ai_summary_record.id,
|
|
summarized_text: ai_summary_record.summarized_text,
|
|
algorithm: ai_summary_record.algorithm,
|
|
outdated: ai_summary_record.outdated,
|
|
created_at: ai_summary_record.created_at,
|
|
updated_at: ai_summary_record.updated_at,
|
|
}
|
|
end
|
|
|
|
plugin.register_modifier(:topic_query_create_list_topics) do |topics, options|
|
|
unless SiteSetting.ai_summarization_enabled && SiteSetting.ai_summary_gists_enabled
|
|
next topics
|
|
end
|
|
|
|
if topics.respond_to?(:includes)
|
|
# For ActiveRecord relations, use includes to preload gists
|
|
topics.includes(:ai_gist_summary)
|
|
elsif topics.is_a?(Array) && topics.present?
|
|
# For Arrays (like suggested topics), preload associations manually
|
|
ActiveRecord::Associations::Preloader.new(
|
|
records: topics,
|
|
associations: :ai_gist_summary,
|
|
).call
|
|
topics
|
|
else
|
|
topics
|
|
end
|
|
end
|
|
|
|
plugin.add_to_serializer(
|
|
:topic_list_item,
|
|
:ai_topic_gist,
|
|
include_condition: -> { scope.can_see_gists? },
|
|
) { object.ai_gist_summary&.summarized_text }
|
|
|
|
plugin.add_to_serializer(
|
|
:suggested_topic,
|
|
:ai_topic_gist,
|
|
include_condition: -> { scope.can_see_gists? },
|
|
) { object.ai_gist_summary&.summarized_text }
|
|
|
|
# As this event can be triggered quite often, let's be overly cautious enqueueing
|
|
# jobs if the feature is disabled.
|
|
plugin.on(:post_created) do |post|
|
|
if SiteSetting.discourse_ai_enabled && SiteSetting.ai_summarization_enabled &&
|
|
SiteSetting.ai_summary_gists_enabled && post.topic
|
|
Jobs.enqueue(:fast_track_topic_gist, topic_id: post&.topic_id)
|
|
end
|
|
end
|
|
|
|
plugin.on(:posts_moved) do |args|
|
|
if SiteSetting.discourse_ai_enabled && SiteSetting.ai_summarization_enabled &&
|
|
!SiteSetting.ai_summary_backfill_maximum_topics_per_hour.zero?
|
|
topic_ids = [args[:original_topic_id], args[:destination_topic_id]].compact.uniq
|
|
|
|
# Mark existing summaries for regeneration by resetting highest_target_number
|
|
AiSummary.where(target_type: "Topic", target_id: topic_ids).update_all(
|
|
highest_target_number: 0,
|
|
)
|
|
|
|
# Fast-track gist regeneration since they appear in topic lists
|
|
if SiteSetting.ai_summary_gists_enabled
|
|
topic_ids.each do |topic_id|
|
|
Jobs.enqueue(:fast_track_topic_gist, topic_id: topic_id, force_regenerate: true)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|