From a5d240991f20406378781739db9985d3e99f5bb2 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 22 Dec 2023 11:46:23 +1100 Subject: [PATCH] FEATURE: allow sending AI based report to a topic (#377) This makes the reporting far more flexible cause it can target a far wider audience by pointing it at a topic in a secure category or an existing PM --- config/locales/client.en.yml | 5 ++- discourse_automation/llm_report.rb | 7 ++- lib/automation/report_runner.rb | 45 ++++++++++++------- .../discourse_automation/llm_report_spec.rb | 17 ++++++- 4 files changed, 54 insertions(+), 20 deletions(-) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 85851d1b..f93fd686 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -20,7 +20,10 @@ en: description: "The user that will send the report" receivers: label: "Receivers" - description: "The users that will receive the report (can be email or usernames)" + description: "The users that will receive the report (emails will be sent direct emails, usernames will be sent a PM)" + topic_id: + label: "Topic ID" + description: "The topic id to post the report to" title: label: "Title" description: "The title of the report" diff --git a/discourse_automation/llm_report.rb b/discourse_automation/llm_report.rb index e17ab7d7..a4ca5b5e 100644 --- a/discourse_automation/llm_report.rb +++ b/discourse_automation/llm_report.rb @@ -11,8 +11,9 @@ if defined?(DiscourseAutomation) triggerables %i[recurring] field :sender, component: :user, required: true - field :receivers, component: :users, required: true - field :title, component: :text, required: true + field :receivers, component: :users + field :topic_id, component: :text + field :title, component: :text field :days, component: :text, required: true, default_value: 7 field :offset, component: :text, required: true, default_value: 0 field :instructions, @@ -40,6 +41,7 @@ if defined?(DiscourseAutomation) begin sender = fields.dig("sender", "value") receivers = fields.dig("receivers", "value") + topic_id = fields.dig("topic_id", "value") title = fields.dig("title", "value") model = fields.dig("model", "value") category_ids = fields.dig("categories", "value") @@ -56,6 +58,7 @@ if defined?(DiscourseAutomation) DiscourseAi::Automation::ReportRunner.run!( sender_username: sender, receivers: receivers, + topic_id: topic_id, title: title, model: model, category_ids: category_ids, diff --git a/lib/automation/report_runner.rb b/lib/automation/report_runner.rb index b412c936..08a4548e 100644 --- a/lib/automation/report_runner.rb +++ b/lib/automation/report_runner.rb @@ -35,25 +35,30 @@ module DiscourseAi def initialize( sender_username:, - receivers:, - title:, model:, - category_ids:, - tags:, - allow_secure_categories:, - debug_mode:, sample_size:, instructions:, + tokens_per_post:, days:, offset:, - priority_group_id:, - tokens_per_post: + receivers: nil, + topic_id: nil, + title: nil, + category_ids: nil, + tags: nil, + priority_group_id: nil, + allow_secure_categories: false, + debug_mode: false ) @sender = User.find_by(username: sender_username) @receivers = User.where(username: receivers) - @email_receivers = receivers.filter { |r| r.include? "@" } - @title = title - + @email_receivers = receivers&.filter { |r| r.include? "@" } + @title = + if title.present? + title + else + I18n.t("discourse_automation.llm_report.title") + end @model = model @llm = DiscourseAi::Completions::Llm.proxy(model) @category_ids = category_ids @@ -66,13 +71,18 @@ module DiscourseAi @offset = offset.to_i @priority_group_id = priority_group_id @tokens_per_post = tokens_per_post.to_i + @topic_id = topic_id.presence&.to_i + + if !@topic_id && !@receivers.present? && !@email_receivers.present? + raise ArgumentError, "Must specify topic_id or receivers" + end end def run! start_date = (@offset + @days).days.ago end_date = start_date + @days.days - @title = + title = @title.gsub( "%DATE%", start_date.strftime("%Y-%m-%d") + " - " + end_date.strftime("%Y-%m-%d"), @@ -102,7 +112,7 @@ module DiscourseAi INPUT prompt = { - insts: "You are a helpful bot specializing in summarizing activity Discourse sites", + insts: "You are a helpful bot specializing in summarizing activity on Discourse sites", input: input, final_insts: "Here is the report I generated for you", params: { @@ -123,12 +133,17 @@ module DiscourseAi receiver_usernames = @receivers.map(&:username).join(",") + if @topic_id + PostCreator.create!(@sender, raw: result, topic_id: @topic_id, skip_validations: true) + # no debug mode for topics, it is too noisy + end + if receiver_usernames.present? post = PostCreator.create!( @sender, raw: result, - title: @title, + title: title, archetype: Archetype.private_message, target_usernames: receiver_usernames, skip_validations: true, @@ -157,7 +172,7 @@ module DiscourseAi if @email_receivers.present? @email_receivers.each do |to_address| Email::Sender.new( - ::AiReportMailer.send_report(to_address, subject: @title, body: result), + ::AiReportMailer.send_report(to_address, subject: title, body: result), :ai_report, ).send end diff --git a/spec/lib/discourse_automation/llm_report_spec.rb b/spec/lib/discourse_automation/llm_report_spec.rb index cae9d6f2..d5df458d 100644 --- a/spec/lib/discourse_automation/llm_report_spec.rb +++ b/spec/lib/discourse_automation/llm_report_spec.rb @@ -5,6 +5,9 @@ return if !defined?(DiscourseAutomation) describe DiscourseAutomation do let(:automation) { Fabricate(:automation, script: "llm_report", enabled: true) } + fab!(:user) + fab!(:post) + def add_automation_field(name, value, type: "text") automation.fields.create!( component: type, @@ -17,8 +20,6 @@ describe DiscourseAutomation do end it "can trigger via automation" do - user = Fabricate(:user) - add_automation_field("sender", user.username, type: "user") add_automation_field("receivers", [user.username], type: "users") add_automation_field("model", "gpt-4-turbo") @@ -31,4 +32,16 @@ describe DiscourseAutomation do pm = Topic.where(title: "Weekly report").first expect(pm.posts.first.raw).to eq("An Amazing Report!!!") end + + it "can target a topic" do + add_automation_field("sender", user.username, type: "user") + add_automation_field("topic_id", "#{post.topic_id}") + add_automation_field("model", "gpt-4-turbo") + + DiscourseAi::Completions::Llm.with_prepared_responses(["An Amazing Report!!!"]) do + automation.trigger! + end + + expect(post.topic.reload.ordered_posts.last.raw).to eq("An Amazing Report!!!") + end end