diff --git a/app/controllers/discourse_ai/ai_helper/assistant_controller.rb b/app/controllers/discourse_ai/ai_helper/assistant_controller.rb index 32da7b81..0d0f85ee 100644 --- a/app/controllers/discourse_ai/ai_helper/assistant_controller.rb +++ b/app/controllers/discourse_ai/ai_helper/assistant_controller.rb @@ -53,7 +53,12 @@ module DiscourseAi end def suggest_title - input = get_text_param! + if params[:topic_id] + topic = Topic.find_by(id: params[:topic_id]) + input = DiscourseAi::Summarization::Strategies::TopicSummary.new(topic).targets_data + else + input = get_text_param! + end prompt = CompletionPrompt.enabled_by_name("generate_titles") raise Discourse::InvalidParameters.new(:mode) if !prompt diff --git a/assets/javascripts/discourse/components/suggestion-menus/ai-title-suggester.gjs b/assets/javascripts/discourse/components/suggestion-menus/ai-title-suggester.gjs index 5142a8ed..7bee7637 100644 --- a/assets/javascripts/discourse/components/suggestion-menus/ai-title-suggester.gjs +++ b/assets/javascripts/discourse/components/suggestion-menus/ai-title-suggester.gjs @@ -17,30 +17,15 @@ export default class AiTitleSuggester extends Component { @tracked untriggers = []; @tracked triggerIcon = "discourse-sparkles"; @tracked content = null; - @tracked topicContent = null; - - constructor() { - super(...arguments); - - if (!this.topicContent && this.args.composer?.reply === undefined) { - this.fetchTopicContent(); - } - } - - async fetchTopicContent() { - await ajax(`/t/${this.args.buffered.content.id}.json`).then( - ({ post_stream }) => { - this.topicContent = post_stream.posts[0].cooked; - } - ); - } get showSuggestionButton() { const composerFields = document.querySelector(".composer-fields"); const editTopicTitleField = document.querySelector(".edit-topic-title"); - this.content = this.args.composer?.reply || this.topicContent; - const showTrigger = this.content?.length > MIN_CHARACTER_COUNT; + this.content = this.args.composer?.reply; + const showTrigger = + this.content?.length > MIN_CHARACTER_COUNT || + this.args.topicState === "edit"; if (composerFields) { if (showTrigger) { @@ -69,13 +54,20 @@ export default class AiTitleSuggester extends Component { this.loading = true; this.triggerIcon = "spinner"; + const data = {}; + + if (this.content) { + data.text = this.content; + } else { + data.topic_id = this.args.buffered.content.id; + } try { const { suggestions } = await ajax( "/discourse-ai/ai-helper/suggest_title", { method: "POST", - data: { text: this.content }, + data, } ); this.suggestions = suggestions; diff --git a/assets/javascripts/discourse/connectors/after-composer-title-input/ai-title-suggestion.gjs b/assets/javascripts/discourse/connectors/after-composer-title-input/ai-title-suggestion.gjs index 691f210d..74ce20e2 100644 --- a/assets/javascripts/discourse/connectors/after-composer-title-input/ai-title-suggestion.gjs +++ b/assets/javascripts/discourse/connectors/after-composer-title-input/ai-title-suggestion.gjs @@ -13,6 +13,6 @@ export default class AiTitleSuggestion extends Component { } } diff --git a/assets/javascripts/discourse/connectors/edit-topic-title__after/ai-title-suggestion.gjs b/assets/javascripts/discourse/connectors/edit-topic-title__after/ai-title-suggestion.gjs index d3449e8f..c17f5a4d 100644 --- a/assets/javascripts/discourse/connectors/edit-topic-title__after/ai-title-suggestion.gjs +++ b/assets/javascripts/discourse/connectors/edit-topic-title__after/ai-title-suggestion.gjs @@ -13,6 +13,6 @@ export default class AiTitleSuggestion extends Component { } } diff --git a/spec/requests/ai_helper/assistant_controller_spec.rb b/spec/requests/ai_helper/assistant_controller_spec.rb index 24a3b73a..87b29578 100644 --- a/spec/requests/ai_helper/assistant_controller_spec.rb +++ b/spec/requests/ai_helper/assistant_controller_spec.rb @@ -134,6 +134,70 @@ RSpec.describe DiscourseAi::AiHelper::AssistantController do end end + describe "#suggest_title" do + fab!(:topic) + fab!(:post_1) { Fabricate(:post, topic: topic, raw: "I love apples") } + fab!(:post_3) { Fabricate(:post, topic: topic, raw: "I love mangos") } + fab!(:post_2) { Fabricate(:post, topic: topic, raw: "I love bananas") } + + context "when logged in as an allowed user" do + fab!(:user) + + before do + sign_in(user) + user.group_ids = [Group::AUTO_GROUPS[:trust_level_1]] + SiteSetting.composer_ai_helper_allowed_groups = Group::AUTO_GROUPS[:trust_level_1] + end + + context "when suggesting titles with a topic_id" do + let(:title_suggestions) do + "What are your favourite fruits?Love for fruitsFruits are amazingFavourite fruit listFruit share topic" + end + let(:title_suggestions_array) do + [ + "What are your favourite fruits?", + "Love for fruits", + "Fruits are amazing", + "Favourite fruit list", + "Fruit share topic", + ] + end + + it "returns title suggestions based on all topic post context" do + DiscourseAi::Completions::Llm.with_prepared_responses([title_suggestions]) do + post "/discourse-ai/ai-helper/suggest_title", params: { topic_id: topic.id } + + expect(response.status).to eq(200) + expect(response.parsed_body["suggestions"]).to eq(title_suggestions_array) + end + end + end + + context "when suggesting titles with input text" do + let(:title_suggestions) do + "Apples - the best fruitWhy apples are greatApples are the best fruitMy love for applesI love apples" + end + let(:title_suggestions_array) do + [ + "Apples - the best fruit", + "Why apples are great", + "Apples are the best fruit", + "My love for apples", + "I love apples", + ] + end + it "returns title suggestions based on the input text" do + DiscourseAi::Completions::Llm.with_prepared_responses([title_suggestions]) do + post "/discourse-ai/ai-helper/suggest_title", params: { text: post_1.raw } + + expect(response.status).to eq(200) + expect(response.parsed_body["suggestions"]).to eq(title_suggestions_array) + end + end + end + end + end + describe "#caption_image" do let(:image) { plugin_file_from_fixtures("100x100.jpg") } let(:upload) { UploadCreator.new(image, "image.jpg").create_for(Discourse.system_user.id) }