Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit 78589b0

Browse files
committed
FEATURE: Fast-track gist regeneration when a hot topic gets a new post
1 parent 657d103 commit 78589b0

File tree

4 files changed

+101
-1
lines changed

4 files changed

+101
-1
lines changed

app/jobs/regular/hot_topics_gist_batch.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
module ::Jobs
44
class HotTopicsGistBatch < ::Jobs::Base
5-
def execute(args)
5+
def execute(_args)
66
return if !SiteSetting.discourse_ai_enabled
77
return if !SiteSetting.ai_summarization_enabled
88
return if SiteSetting.ai_summarize_max_hot_topics_gists_per_batch.zero?
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
module ::Jobs
4+
class UpdateHotTopicGist < ::Jobs::Base
5+
sidekiq_options retry: false
6+
7+
def execute(args)
8+
return if !SiteSetting.discourse_ai_enabled
9+
return if !SiteSetting.ai_summarization_enabled
10+
return if SiteSetting.ai_summarize_max_hot_topics_gists_per_batch.zero?
11+
12+
topic = Topic.find_by(id: args[:topic_id])
13+
return if topic.blank?
14+
15+
return if !TopicHotScore.where(topic: topic).exists?
16+
17+
summarizer = DiscourseAi::Summarization.topic_gist(topic)
18+
gist = summarizer.existing_summary
19+
return if gist.blank?
20+
return if !gist.outdated
21+
22+
summarizer.delete_cached_summaries!
23+
summarizer.summarize(Discourse.system_user)
24+
end
25+
end
26+
end

lib/summarization/entry_point.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ def inject_into(plugin)
4747
# To make sure hot topic gists are inmediately up to date, we rely on this event
4848
# instead of using a scheduled job.
4949
plugin.on(:topic_hot_scores_updated) { Jobs.enqueue(:hot_topics_gist_batch) }
50+
51+
plugin.on(:post_created) do |post|
52+
Jobs.enqueue(:update_hot_topic_gist, topic_id: post&.topic_id)
53+
end
5054
end
5155
end
5256
end
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe Jobs::UpdateHotTopicGist do
4+
describe "#execute" do
5+
fab!(:topic_1) { Fabricate(:topic) }
6+
fab!(:post_1) { Fabricate(:post, topic: topic_1, post_number: 1) }
7+
fab!(:post_2) { Fabricate(:post, topic: topic_1, post_number: 2) }
8+
9+
before do
10+
assign_fake_provider_to(:ai_summarization_model)
11+
SiteSetting.ai_summarization_enabled = true
12+
SiteSetting.ai_summarize_max_hot_topics_gists_per_batch = 100
13+
end
14+
15+
context "when the hot topic has a gist" do
16+
before { TopicHotScore.create!(topic_id: topic_1.id, score: 0.1) }
17+
fab!(:ai_gist) do
18+
Fabricate(:topic_ai_gist, target: topic_1, original_content_sha: AiSummary.build_sha("12"))
19+
end
20+
let(:updated_gist) { "They updated me :(" }
21+
22+
context "when it's up to date" do
23+
it "does nothing" do
24+
DiscourseAi::Completions::Llm.with_prepared_responses([updated_gist]) do
25+
subject.execute(topic_id: topic_1.id)
26+
end
27+
28+
gist = AiSummary.gist.find_by(target: topic_1)
29+
expect(AiSummary.gist.where(target: topic_1).count).to eq(1)
30+
expect(gist.summarized_text).not_to eq(updated_gist)
31+
end
32+
end
33+
34+
context "when it's outdated" do
35+
it "regenerates the gist using the latest data" do
36+
Fabricate(:post, topic: topic_1, post_number: 3)
37+
38+
DiscourseAi::Completions::Llm.with_prepared_responses([updated_gist]) do
39+
subject.execute(topic_id: topic_1.id)
40+
end
41+
42+
gist = AiSummary.gist.find_by(target: topic_1)
43+
expect(AiSummary.gist.where(target: topic_1).count).to eq(1)
44+
expect(gist.summarized_text).to eq(updated_gist)
45+
expect(gist.original_content_sha).to eq(AiSummary.build_sha("123"))
46+
end
47+
end
48+
end
49+
50+
context "when the topic doesn't have a hot topic score" do
51+
it "does nothing" do
52+
subject.execute({})
53+
54+
gist = AiSummary.gist.find_by(target: topic_1)
55+
expect(gist).to be_nil
56+
end
57+
end
58+
59+
context "when the topic has a hot topic score but no gist" do
60+
before { TopicHotScore.create!(topic_id: topic_1.id, score: 0.1) }
61+
62+
it "does nothing" do
63+
subject.execute({})
64+
65+
gist = AiSummary.gist.find_by(target: topic_1)
66+
expect(gist).to be_nil
67+
end
68+
end
69+
end
70+
end

0 commit comments

Comments
 (0)