From 64ad45e28d139de1641f8d0c659ed153f9df4455 Mon Sep 17 00:00:00 2001 From: rngus2344 Date: Wed, 5 Mar 2025 11:27:39 -0600 Subject: [PATCH 1/6] DEV: Add Ai summary persona siteSettings --- config/settings.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/config/settings.yml b/config/settings.yml index d2e212fb7..a0c3e7ec5 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -358,3 +358,12 @@ discourse_ai: ai_rag_images_enabled: default: false hidden: true + + ai_summary_persona_id: + default: "" + client: true + hidden: true + ai_summary_consolidator_persona_id: + default: "" + client: true + hidden: true From 1aa727743dc195b74615662940c8c7b98bc5a2ee Mon Sep 17 00:00:00 2001 From: rngus2344 Date: Wed, 5 Mar 2025 13:00:06 -0600 Subject: [PATCH 2/6] topic summary with ai persona siteSettings --- lib/summarization/strategies/topic_summary.rb | 74 +++++++++++-------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/lib/summarization/strategies/topic_summary.rb b/lib/summarization/strategies/topic_summary.rb index 4dfca68c5..743e7e14c 100644 --- a/lib/summarization/strategies/topic_summary.rb +++ b/lib/summarization/strategies/topic_summary.rb @@ -38,21 +38,29 @@ def summary_extension_prompt(summary, contents) input = contents.map { |item| "(#{item[:id]} #{item[:poster]} said: #{item[:text]})" }.join - prompt = DiscourseAi::Completions::Prompt.new(<<~TEXT, topic_id: target.id) - You are an advanced summarization bot tasked with enhancing an existing summary by incorporating additional posts. - - ### Guidelines: - - Only include the enhanced summary, without any additional commentary. - - Understand and generate Discourse forum Markdown; including links, _italics_, **bold**. - - Maintain the original language of the text being summarized. - - Aim for summaries to be 400 words or less. - - Each new post is formatted as ") " - - Cite specific noteworthy posts using the format [DESCRIPTION](#{resource_path}/POST_NUMBER) - - Example: links to the 3rd and 6th posts by sam: sam ([#3](#{resource_path}/3), [#6](#{resource_path}/6)) - - Example: link to the 6th post by jane: [agreed with](#{resource_path}/6) - - Example: link to the 13th post by joe: [joe](#{resource_path}/13) - - When formatting usernames either use @USERNAME or [USERNAME](#{resource_path}/POST_NUMBER) - TEXT + if SiteSetting.ai_summary_consolidator_persona_id + prompt = + DiscourseAi::Completions::Prompt.new( + AiPersona.find_by(id: SiteSetting.ai_summary_consolidator_persona_id).system_prompt, + topic_id: target.id, + ) + else + prompt = DiscourseAi::Completions::Prompt.new(<<~TEXT, topic_id: target.id) # summary extension prompt + You are an advanced summarization bot tasked with enhancing an existing summary by incorporating additional posts. + + ### Guidelines: + - Only include the enhanced summary, without any additional commentary. + - Understand and generate Discourse forum Markdown; including links, _italics_, **bold**. + - Maintain the original language of the text being summarized. + - Aim for summaries to be 400 words or less. + - Each new post is formatted as ") " + - Cite specific noteworthy posts using the format [DESCRIPTION](#{resource_path}/POST_NUMBER) + - Example: links to the 3rd and 6th posts by sam: sam ([#3](#{resource_path}/3), [#6](#{resource_path}/6)) + - Example: link to the 6th post by jane: [agreed with](#{resource_path}/6) + - Example: link to the 13th post by joe: [joe](#{resource_path}/13) + - When formatting usernames either use @USERNAME or [USERNAME](#{resource_path}/POST_NUMBER) + TEXT + end prompt.push(type: :user, content: <<~TEXT.strip) ### Context: @@ -81,20 +89,28 @@ def first_summary_prompt(contents) input = contents.map { |item| "(#{item[:id]} #{item[:poster]} said: #{item[:text]} " }.join - prompt = DiscourseAi::Completions::Prompt.new(<<~TEXT.strip, topic_id: target.id) - You are an advanced summarization bot that generates concise, coherent summaries of provided text. - - - Only include the summary, without any additional commentary. - - You understand and generate Discourse forum Markdown; including links, _italics_, **bold**. - - Maintain the original language of the text being summarized. - - Aim for summaries to be 400 words or less. - - Each post is formatted as ") " - - Cite specific noteworthy posts using the format [DESCRIPTION](#{resource_path}/POST_NUMBER) - - Example: links to the 3rd and 6th posts by sam: sam ([#3](#{resource_path}/3), [#6](#{resource_path}/6)) - - Example: link to the 6th post by jane: [agreed with](#{resource_path}/6) - - Example: link to the 13th post by joe: [joe](#{resource_path}/13) - - When formatting usernames either use @USERNMAE OR [USERNAME](#{resource_path}/POST_NUMBER) - TEXT + if SiteSetting.ai_summary_persona_id.present? + prompt = + DiscourseAi::Completions::Prompt.new( + AiPersona.find_by(id: SiteSetting.ai_summary_consolidator_persona_id).system_prompt, + topic_id: target.id, + ) + else + prompt = DiscourseAi::Completions::Prompt.new(<<~TEXT.strip, topic_id: target.id) + You are an advanced summarization bot that generates concise, coherent summaries of provided text. + + - Only include the summary, without any additional commentary. + - You understand and generate Discourse forum Markdown; including links, _italics_, **bold**. + - Maintain the original language of the text being summarized. + - Aim for summaries to be 400 words or less. + - Each post is formatted as ") " + - Cite specific noteworthy posts using the format [DESCRIPTION](#{resource_path}/POST_NUMBER) + - Example: links to the 3rd and 6th posts by sam: sam ([#3](#{resource_path}/3), [#6](#{resource_path}/6)) + - Example: link to the 6th post by jane: [agreed with](#{resource_path}/6) + - Example: link to the 13th post by joe: [joe](#{resource_path}/13) + - When formatting usernames either use @USERNMAE OR [USERNAME](#{resource_path}/POST_NUMBER) + TEXT + end prompt.push( type: :user, From 8ce7331870132d7e2aa69122561df7849c57720f Mon Sep 17 00:00:00 2001 From: rngus2344 Date: Wed, 5 Mar 2025 13:55:10 -0600 Subject: [PATCH 3/6] settings update --- config/settings.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/config/settings.yml b/config/settings.yml index a0c3e7ec5..86e6a35a4 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -361,9 +361,7 @@ discourse_ai: ai_summary_persona_id: default: "" - client: true hidden: true ai_summary_consolidator_persona_id: default: "" - client: true hidden: true From 20701cb48a0f662ed46cbcc70605df26d8406291 Mon Sep 17 00:00:00 2001 From: rngus2344 Date: Wed, 5 Mar 2025 14:18:17 -0600 Subject: [PATCH 4/6] abstract logic into separate method --- lib/summarization/strategies/topic_summary.rb | 93 ++++++++++--------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/lib/summarization/strategies/topic_summary.rb b/lib/summarization/strategies/topic_summary.rb index 743e7e14c..08b7cdaf0 100644 --- a/lib/summarization/strategies/topic_summary.rb +++ b/lib/summarization/strategies/topic_summary.rb @@ -32,35 +32,41 @@ def targets_data end end + def summary_prompt(topic_id:, persona_id:, default_prompt:) + prompt_text = default_prompt + if persona_id + persona = AiPersona.find_by(id: persona_id) + prompt_text = persona.system_prompt if persona + end + DiscourseAi::Completions::Prompt.new(prompt_text, topic_id: topic_id) + end + def summary_extension_prompt(summary, contents) resource_path = "#{Discourse.base_path}/t/-/#{target.id}" content_title = target.title input = contents.map { |item| "(#{item[:id]} #{item[:poster]} said: #{item[:text]})" }.join - if SiteSetting.ai_summary_consolidator_persona_id - prompt = - DiscourseAi::Completions::Prompt.new( - AiPersona.find_by(id: SiteSetting.ai_summary_consolidator_persona_id).system_prompt, - topic_id: target.id, - ) - else - prompt = DiscourseAi::Completions::Prompt.new(<<~TEXT, topic_id: target.id) # summary extension prompt - You are an advanced summarization bot tasked with enhancing an existing summary by incorporating additional posts. - - ### Guidelines: - - Only include the enhanced summary, without any additional commentary. - - Understand and generate Discourse forum Markdown; including links, _italics_, **bold**. - - Maintain the original language of the text being summarized. - - Aim for summaries to be 400 words or less. - - Each new post is formatted as ") " - - Cite specific noteworthy posts using the format [DESCRIPTION](#{resource_path}/POST_NUMBER) - - Example: links to the 3rd and 6th posts by sam: sam ([#3](#{resource_path}/3), [#6](#{resource_path}/6)) - - Example: link to the 6th post by jane: [agreed with](#{resource_path}/6) - - Example: link to the 13th post by joe: [joe](#{resource_path}/13) - - When formatting usernames either use @USERNAME or [USERNAME](#{resource_path}/POST_NUMBER) - TEXT - end + prompt = + summary_prompt( + topic_id: target.id, + persona_id: SiteSetting.ai_summary_consolidator_persona_id, + default_prompt: <<~TEXT, + You are an advanced summarization bot tasked with enhancing an existing summary by incorporating additional posts. + + ### Guidelines: + - Only include the enhanced summary, without any additional commentary. + - Understand and generate Discourse forum Markdown; including links, _italics_, **bold**. + - Maintain the original language of the text being summarized. + - Aim for summaries to be 400 words or less. + - Each new post is formatted as ") " + - Cite specific noteworthy posts using the format [DESCRIPTION](#{resource_path}/POST_NUMBER) + - Example: links to the 3rd and 6th posts by sam: sam ([#3](#{resource_path}/3), [#6](#{resource_path}/6)) + - Example: link to the 6th post by jane: [agreed with](#{resource_path}/6) + - Example: link to the 13th post by joe: [joe](#{resource_path}/13) + - When formatting usernames either use @USERNAME or [USERNAME](#{resource_path}/POST_NUMBER) + TEXT + ) prompt.push(type: :user, content: <<~TEXT.strip) ### Context: @@ -89,28 +95,25 @@ def first_summary_prompt(contents) input = contents.map { |item| "(#{item[:id]} #{item[:poster]} said: #{item[:text]} " }.join - if SiteSetting.ai_summary_persona_id.present? - prompt = - DiscourseAi::Completions::Prompt.new( - AiPersona.find_by(id: SiteSetting.ai_summary_consolidator_persona_id).system_prompt, - topic_id: target.id, - ) - else - prompt = DiscourseAi::Completions::Prompt.new(<<~TEXT.strip, topic_id: target.id) - You are an advanced summarization bot that generates concise, coherent summaries of provided text. - - - Only include the summary, without any additional commentary. - - You understand and generate Discourse forum Markdown; including links, _italics_, **bold**. - - Maintain the original language of the text being summarized. - - Aim for summaries to be 400 words or less. - - Each post is formatted as ") " - - Cite specific noteworthy posts using the format [DESCRIPTION](#{resource_path}/POST_NUMBER) - - Example: links to the 3rd and 6th posts by sam: sam ([#3](#{resource_path}/3), [#6](#{resource_path}/6)) - - Example: link to the 6th post by jane: [agreed with](#{resource_path}/6) - - Example: link to the 13th post by joe: [joe](#{resource_path}/13) - - When formatting usernames either use @USERNMAE OR [USERNAME](#{resource_path}/POST_NUMBER) - TEXT - end + prompt = + summary_prompt( + topic_id: target.id, + persona_id: SiteSetting.ai_summary_persona_id, + default_prompt: <<~TEXT, + You are an advanced summarization bot that generates concise, coherent summaries of provided text. + + - Only include the summary, without any additional commentary. + - You understand and generate Discourse forum Markdown; including links, _italics_, **bold**. + - Maintain the original language of the text being summarized. + - Aim for summaries to be 400 words or less. + - Each post is formatted as ") " + - Cite specific noteworthy posts using the format [DESCRIPTION](#{resource_path}/POST_NUMBER) + - Example: links to the 3rd and 6th posts by sam: sam ([#3](#{resource_path}/3), [#6](#{resource_path}/6)) + - Example: link to the 6th post by jane: [agreed with](#{resource_path}/6) + - Example: link to the 13th post by joe: [joe](#{resource_path}/13) + - When formatting usernames either use @USERNMAE OR [USERNAME](#{resource_path}/POST_NUMBER) + TEXT + ) prompt.push( type: :user, From e94385927b172f4a381328c6758f6bfa9689ee1d Mon Sep 17 00:00:00 2001 From: rngus2344 Date: Wed, 5 Mar 2025 16:21:51 -0600 Subject: [PATCH 5/6] spec added --- .../strategies/topic_summary_spec.rb | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/spec/lib/modules/summarization/strategies/topic_summary_spec.rb b/spec/lib/modules/summarization/strategies/topic_summary_spec.rb index 93f2c4c2c..6769bb63d 100644 --- a/spec/lib/modules/summarization/strategies/topic_summary_spec.rb +++ b/spec/lib/modules/summarization/strategies/topic_summary_spec.rb @@ -6,6 +6,7 @@ fab!(:topic) { Fabricate(:topic, highest_post_number: 25) } fab!(:post_1) { Fabricate(:post, topic: topic, post_number: 1) } fab!(:post_2) { Fabricate(:post, topic: topic, post_number: 2) } + fab!(:admin) describe "#targets_data" do shared_examples "includes only public-visible topics" do @@ -62,4 +63,54 @@ end end end + + describe "#summary_extension_prompt" do + context "when ai_summary_consolidator_persona_id siteSetting is set" do + it "returns a prompt with the correct text" do + AiPersona.create!( + name: "TestPersona", + system_prompt: "test prompt", + description: "test", + allowed_group_ids: [Group::AUTO_GROUPS[:trust_level_0]], + ) + personaClass = + DiscourseAi::AiBot::Personas::Persona.find_by(user: admin, name: "TestPersona") + SiteSetting.ai_summary_consolidator_persona_id = personaClass.id + + expect( + topic_summary + .summary_extension_prompt(nil, [{ id: 1, poster: "test", text: "hello" }]) + .messages + .first[ + :content + ], + ).to include("test prompt") + end + end + end + + describe "#first_summary_prompt" do + context "when ai_summary_persona_id siteSetting is set" do + it "returns a prompt with the correct text" do + AiPersona.create!( + name: "TestPersona", + system_prompt: "test prompt", + description: "test", + allowed_group_ids: [Group::AUTO_GROUPS[:trust_level_0]], + ) + personaClass = + DiscourseAi::AiBot::Personas::Persona.find_by(user: admin, name: "TestPersona") + SiteSetting.ai_summary_persona_id = personaClass.id + + expect( + topic_summary + .first_summary_prompt([{ id: 1, poster: "test", text: "hello" }]) + .messages + .first[ + :content + ], + ).to include("test prompt") + end + end + end end From 3dfa16ad0f903b1f477e53be8d5ab89f6b45f2c6 Mon Sep 17 00:00:00 2001 From: rngus2344 Date: Wed, 5 Mar 2025 16:39:54 -0600 Subject: [PATCH 6/6] spec updated --- .../strategies/topic_summary_spec.rb | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/spec/lib/modules/summarization/strategies/topic_summary_spec.rb b/spec/lib/modules/summarization/strategies/topic_summary_spec.rb index 6769bb63d..cc41cab82 100644 --- a/spec/lib/modules/summarization/strategies/topic_summary_spec.rb +++ b/spec/lib/modules/summarization/strategies/topic_summary_spec.rb @@ -64,18 +64,23 @@ end end - describe "#summary_extension_prompt" do + describe "Summary prompt" do + let!(:ai_persona) do + AiPersona.create!( + name: "TestPersona", + system_prompt: "test prompt", + description: "test", + allowed_group_ids: [Group::AUTO_GROUPS[:trust_level_0]], + ) + end + + let!(:persona_class) do + DiscourseAi::AiBot::Personas::Persona.find_by(user: admin, name: "TestPersona") + end + context "when ai_summary_consolidator_persona_id siteSetting is set" do - it "returns a prompt with the correct text" do - AiPersona.create!( - name: "TestPersona", - system_prompt: "test prompt", - description: "test", - allowed_group_ids: [Group::AUTO_GROUPS[:trust_level_0]], - ) - personaClass = - DiscourseAi::AiBot::Personas::Persona.find_by(user: admin, name: "TestPersona") - SiteSetting.ai_summary_consolidator_persona_id = personaClass.id + it "returns a summary extension prompt with the correct text" do + SiteSetting.ai_summary_consolidator_persona_id = persona_class.id expect( topic_summary @@ -87,20 +92,10 @@ ).to include("test prompt") end end - end - describe "#first_summary_prompt" do context "when ai_summary_persona_id siteSetting is set" do - it "returns a prompt with the correct text" do - AiPersona.create!( - name: "TestPersona", - system_prompt: "test prompt", - description: "test", - allowed_group_ids: [Group::AUTO_GROUPS[:trust_level_0]], - ) - personaClass = - DiscourseAi::AiBot::Personas::Persona.find_by(user: admin, name: "TestPersona") - SiteSetting.ai_summary_persona_id = personaClass.id + it "returns a first summary prompt with the correct text" do + SiteSetting.ai_summary_persona_id = persona_class.id expect( topic_summary