FIX: Unnecessary complex preloading accidentally filters some topics. (#945)

The `topic_query_create_list_topics` modifier we append was always meant to avoid an N+1 situation when serializing gists. However, I tried to be too smart and only preload these, which resulted in some topics with *only* regular summaries getting removed from the list. This issue became apparent now we are adding gists to other lists besides hot.

Let's simplify the preloading, which still solves the N+1 issue, and let the serializer get the needed summary.
This commit is contained in:
Roman Rizzi 2024-11-22 12:07:27 -03:00 committed by GitHub
parent 1921e4e90d
commit e54f2da1a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 41 additions and 21 deletions

View File

@ -17,20 +17,14 @@ module DiscourseAi
scope.can_see_summary?(object.topic) scope.can_see_summary?(object.topic)
end end
# plugin.register_modifier(:topic_query_create_list_topics) do |topics, options| plugin.register_modifier(:topic_query_create_list_topics) do |topics, options|
# if Discourse.filters.include?(options[:filter]) && SiteSetting.ai_summarization_enabled && if Discourse.filters.include?(options[:filter]) && SiteSetting.ai_summarization_enabled &&
# SiteSetting.ai_summarize_max_hot_topics_gists_per_batch > 0 SiteSetting.ai_summarize_max_hot_topics_gists_per_batch > 0
# topics topics.includes(:ai_summaries)
# .includes(:ai_summaries) else
# .where( topics
# "ai_summaries.id IS NULL OR ai_summaries.summary_type = ?", end
# AiSummary.summary_types[:gist], end
# )
# .references(:ai_summaries)
# else
# topics
# end
# end
plugin.add_to_serializer( plugin.add_to_serializer(
:topic_list_item, :topic_list_item,

View File

@ -4,6 +4,7 @@ RSpec.describe DiscourseAi::Summarization::EntryPoint do
before do before do
assign_fake_provider_to(:ai_summarization_model) assign_fake_provider_to(:ai_summarization_model)
SiteSetting.ai_summarization_enabled = true SiteSetting.ai_summarization_enabled = true
SiteSetting.ai_summarize_max_hot_topics_gists_per_batch = 100
end end
fab!(:user) fab!(:user)
@ -11,7 +12,6 @@ RSpec.describe DiscourseAi::Summarization::EntryPoint do
describe "#inject_into" do describe "#inject_into" do
describe "hot topics gist summarization" do describe "hot topics gist summarization" do
fab!(:topic_ai_gist) fab!(:topic_ai_gist)
fab!(:regular_summary) { Fabricate(:ai_summary, target: topic_ai_gist.target) }
before { TopicHotScore.create!(topic_id: topic_ai_gist.target_id, score: 1.0) } before { TopicHotScore.create!(topic_id: topic_ai_gist.target_id, score: 1.0) }
@ -19,13 +19,22 @@ RSpec.describe DiscourseAi::Summarization::EntryPoint do
describe "topic_query_create_list_topics modifier" do describe "topic_query_create_list_topics modifier" do
context "when hot topic summarization is enabled" do context "when hot topic summarization is enabled" do
before { SiteSetting.ai_summarize_max_hot_topics_gists_per_batch = 100 } it "doesn't duplicate records when there more than one summary type" do
Fabricate(:ai_summary, target: topic_ai_gist.target)
skip "preloads only gist summaries" do expect(topic_query.list_hot.topics.map(&:id)).to contain_exactly(
gist_topic = topic_query.list_hot.topics.find { |t| t.id == topic_ai_gist.target_id } topic_ai_gist.target_id,
)
end
expect(gist_topic.ai_summaries.size).to eq(1) it "doesn't exclude records when the topic has a single different summary" do
expect(gist_topic.ai_summaries.first).to eq(topic_ai_gist) regular_summary_2 = Fabricate(:ai_summary)
TopicHotScore.create!(topic_id: regular_summary_2.target_id, score: 1.0)
expect(topic_query.list_hot.topics.map(&:id)).to contain_exactly(
regular_summary_2.target_id,
topic_ai_gist.target_id,
)
end end
it "doesn't filter out hot topics without summaries" do it "doesn't filter out hot topics without summaries" do
@ -118,11 +127,28 @@ RSpec.describe DiscourseAi::Summarization::EntryPoint do
gist_topic, gist_topic,
scope: Guardian.new(admin), scope: Guardian.new(admin),
root: false, root: false,
filter: :hot, filter: :unread,
).as_json ).as_json
expect(serialized[:ai_topic_gist]).to be_present expect(serialized[:ai_topic_gist]).to be_present
end end
it "doesn't include the summary if it's not a gist" do
regular_summary_2 = Fabricate(:ai_summary)
TopicHotScore.create!(topic_id: regular_summary_2.target_id, score: 1.0)
hot_topic = topic_query.list_hot.topics.find { |t| t.id == regular_summary_2.target_id }
serialized =
TopicListItemSerializer.new(
hot_topic,
scope: Guardian.new(user),
root: false,
filter: :hot,
).as_json
expect(serialized[:ai_topic_gist]).to be_nil
end
end end
end end
end end