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

Commit 3f6cbd7

Browse files
committed
Display gists in the hot topics list
1 parent decf1bb commit 3f6cbd7

File tree

10 files changed

+151
-2
lines changed

10 files changed

+151
-2
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Component from "@glimmer/component";
2+
import icon from "discourse-common/helpers/d-icon";
3+
4+
export default class AiTopicGist extends Component {
5+
static shouldRender(outletArgs, helper) {
6+
return outletArgs?.topic?.ai_topic_gist && !outletArgs.topic.excerpt;
7+
}
8+
9+
<template>
10+
<div class="ai-topic-gist">
11+
<div class="ai-topic-gist__text">
12+
{{@outletArgs.topic.ai_topic_gist}}
13+
</div>
14+
</div>
15+
</template>
16+
}

assets/stylesheets/modules/summarization/common/ai-summary.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,11 @@
215215
opacity: 1;
216216
}
217217
}
218+
219+
.ai-topic-gist {
220+
margin-top: .5em;
221+
222+
&__text {
223+
font-size: var(--font-down-2);
224+
}
225+
}

config/locales/server.en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ en:
8484
ai_summarization_model: "Model to use for summarization."
8585
ai_custom_summarization_allowed_groups: "Groups allowed to use create new summaries."
8686
ai_pm_summarization_allowed_groups: "Groups allowed to create and view summaries in PMs."
87+
ai_summarize_hot_topics_list: "Display a brief summary for each topic in the hot topics list (if available)."
8788

8889
ai_bot_enabled: "Enable the AI Bot module."
8990
ai_bot_enable_chat_warning: "Display a warning when PM chat is initiated. Can be overriden by editing the translation string: discourse_ai.ai_bot.pm_warning"

config/settings.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,9 @@ discourse_ai:
376376
type: group_list
377377
list_type: compact
378378
default: "3|13" # 3: @staff, 13: @trust_level_3
379+
ai_summarize_hot_topics_list:
380+
client: true
381+
default: false
379382
ai_summarization_strategy: # TODO(roman): Deprecated. Remove by Sept 2024
380383
type: enum
381384
default: ""

lib/summarization/entry_point.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,26 @@ def inject_into(plugin)
1616
plugin.add_to_serializer(:web_hook_topic_view, :summarizable) do
1717
scope.can_see_summary?(object.topic, AiSummary.summary_types[:complete])
1818
end
19+
20+
plugin.register_modifier(:topic_query_create_list_topics) do |topics, options|
21+
if options[:filter] == :hot && SiteSetting.ai_summarization_enabled &&
22+
SiteSetting.ai_summarize_hot_topics_list
23+
topics.includes(:ai_summaries).where(
24+
"ai_summaries.id IS NULL OR ai_summaries.summary_type = ?",
25+
AiSummary.summary_types[:gist],
26+
)
27+
else
28+
topics
29+
end
30+
end
31+
32+
plugin.add_to_serializer(
33+
:topic_list_item,
34+
:ai_topic_gist,
35+
include_condition: -> do
36+
SiteSetting.ai_summarization_enabled && SiteSetting.ai_summarize_hot_topics_list
37+
end,
38+
) { object.ai_summaries.to_a.first&.summarized_text }
1939
end
2040
end
2141
end

lib/summarization/strategies/topic_gist.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ def concatenation_prompt(texts_to_summarize)
4747
prompt = DiscourseAi::Completions::Prompt.new(<<~TEXT.strip)
4848
You are a summarization bot tasked with creating a single, concise sentence by merging disjointed summaries into a cohesive statement.
4949
Your response should strictly be this single, comprehensive sentence, without any additional text or comments.
50+
51+
- Focus on the central theme or issue being addressed, while maintaining an objective and neutral tone.
52+
- Avoid including extraneous details or subjective opinions.
53+
- Maintain the original language of the text being summarized.
54+
- Try to use no more than 20 words.
55+
- Begin the summary directly with the main topic or issue, using clear and direct language without introductory phrases like "The discussion is about..."
5056
TEXT
5157

5258
prompt.push(type: :user, content: <<~TEXT.strip)
@@ -63,11 +69,14 @@ def concatenation_prompt(texts_to_summarize)
6369
def summarize_single_prompt(input, opts)
6470
prompt = DiscourseAi::Completions::Prompt.new(<<~TEXT.strip)
6571
You are an advanced summarization bot. Your task is to analyze a given conversation and generate a single,
66-
concise sentence that clearly conveys the main topic and purpose of the discussion to someone with no prior context.
72+
concise sentence that clearly conveys the main topic and purpose of the discussion to someone with no prior context.
6773
6874
- Focus on the central theme or issue being addressed, while maintaining an objective and neutral tone.
6975
- Avoid including extraneous details or subjective opinions.
7076
- Maintain the original language of the text being summarized.
77+
- Begin the summary directly with the main topic or issue, using clear and direct language without introductory phrases like "The discussion is about...".
78+
- The sentence doesn't have to mention the discussion title.
79+
- Aim to use no more than 20 words.
7180
TEXT
7281

7382
prompt.push(type: :user, content: <<~TEXT.strip)

lib/topic_extensions.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# frozen_string_literal: true
2+
3+
module DiscourseAi
4+
module TopicExtensions
5+
extend ActiveSupport::Concern
6+
7+
prepended { has_many :ai_summaries, as: :target }
8+
end
9+
end

plugin.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,10 @@ module ::DiscourseAi
7676
require_relative "spec/support/stable_diffusion_stubs"
7777
end
7878

79-
reloadable_patch { |plugin| Guardian.prepend DiscourseAi::GuardianExtensions }
79+
reloadable_patch do |plugin|
80+
Guardian.prepend DiscourseAi::GuardianExtensions
81+
Topic.prepend DiscourseAi::TopicExtensions
82+
end
8083

8184
register_modifier(:post_should_secure_uploads?) do |_, _, topic|
8285
if topic.private_message? && SharedAiConversation.exists?(target: topic)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# frozen_string_literal: true
2+
3+
Fabricator(:ai_summary) do
4+
summarized_text "complete summary"
5+
original_content_sha "123"
6+
algorithm "test"
7+
target { Fabricate(:topic) }
8+
summary_type AiSummary.summary_types[:complete]
9+
end
10+
11+
Fabricator(:topic_ai_gist, from: :ai_summary) do
12+
summarized_text "gist"
13+
summary_type AiSummary.summary_types[:gist]
14+
end
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe DiscourseAi::Summarization::EntryPoint do
4+
before do
5+
assign_fake_provider_to(:ai_summarization_model)
6+
SiteSetting.ai_summarization_enabled = true
7+
end
8+
9+
fab!(:user)
10+
11+
describe "#inject_into" do
12+
describe "hot topics gist summarization" do
13+
fab!(:topic_ai_gist)
14+
fab!(:regular_summary) { Fabricate(:ai_summary, target: topic_ai_gist.target) }
15+
16+
before { TopicHotScore.create!(topic_id: topic_ai_gist.target_id, score: 1.0) }
17+
18+
let(:topic_query) { TopicQuery.new(user) }
19+
20+
describe "topic_query_create_list_topics modifier" do
21+
context "when hot topic summarization is enabled" do
22+
before { SiteSetting.ai_summarize_hot_topics_list = true }
23+
24+
it "preloads only gist summaries" do
25+
gist_topic = topic_query.list_hot.topics.find { |t| t.id == topic_ai_gist.target_id }
26+
27+
expect(gist_topic.ai_summaries.size).to eq(1)
28+
expect(gist_topic.ai_summaries.first).to eq(topic_ai_gist)
29+
end
30+
31+
it "doesn't filter out hot topics without summaries" do
32+
TopicHotScore.create!(topic_id: Fabricate(:topic).id, score: 1.0)
33+
34+
expect(topic_query.list_hot.topics.size).to eq(2)
35+
end
36+
end
37+
end
38+
39+
describe "topic_list_item serializer's ai_summary" do
40+
context "when hot topic summarization is disabled" do
41+
it "doesn't include summaries" do
42+
gist_topic = topic_query.list_hot.topics.find { |t| t.id == topic_ai_gist.target_id }
43+
44+
serialized =
45+
TopicListItemSerializer.new(gist_topic, scope: Guardian.new, root: false).as_json
46+
47+
expect(serialized.has_key?(:ai_topic_gist)).to eq(false)
48+
end
49+
end
50+
51+
context "when hot topics summarization is enabled" do
52+
before { SiteSetting.ai_summarize_hot_topics_list = true }
53+
54+
it "includes the summary" do
55+
gist_topic = topic_query.list_hot.topics.find { |t| t.id == topic_ai_gist.target_id }
56+
57+
serialized =
58+
TopicListItemSerializer.new(gist_topic, scope: Guardian.new, root: false).as_json
59+
60+
expect(serialized[:ai_topic_gist]).to be_present
61+
end
62+
end
63+
end
64+
end
65+
end
66+
end

0 commit comments

Comments
 (0)