DEV: Improve title suggester suggestions when editing topic (#1182)

This update ensures topic title suggestions when suggesting from edit topic take into account the whole topic for more accurate title suggestions.
This commit is contained in:
Keegan George 2025-03-11 11:16:06 -07:00 committed by GitHub
parent e59184b65c
commit b17c688162
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 84 additions and 23 deletions

View File

@ -53,7 +53,12 @@ module DiscourseAi
end end
def suggest_title 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") prompt = CompletionPrompt.enabled_by_name("generate_titles")
raise Discourse::InvalidParameters.new(:mode) if !prompt raise Discourse::InvalidParameters.new(:mode) if !prompt

View File

@ -17,30 +17,15 @@ export default class AiTitleSuggester extends Component {
@tracked untriggers = []; @tracked untriggers = [];
@tracked triggerIcon = "discourse-sparkles"; @tracked triggerIcon = "discourse-sparkles";
@tracked content = null; @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() { get showSuggestionButton() {
const composerFields = document.querySelector(".composer-fields"); const composerFields = document.querySelector(".composer-fields");
const editTopicTitleField = document.querySelector(".edit-topic-title"); const editTopicTitleField = document.querySelector(".edit-topic-title");
this.content = this.args.composer?.reply || this.topicContent; this.content = this.args.composer?.reply;
const showTrigger = this.content?.length > MIN_CHARACTER_COUNT; const showTrigger =
this.content?.length > MIN_CHARACTER_COUNT ||
this.args.topicState === "edit";
if (composerFields) { if (composerFields) {
if (showTrigger) { if (showTrigger) {
@ -69,13 +54,20 @@ export default class AiTitleSuggester extends Component {
this.loading = true; this.loading = true;
this.triggerIcon = "spinner"; this.triggerIcon = "spinner";
const data = {};
if (this.content) {
data.text = this.content;
} else {
data.topic_id = this.args.buffered.content.id;
}
try { try {
const { suggestions } = await ajax( const { suggestions } = await ajax(
"/discourse-ai/ai-helper/suggest_title", "/discourse-ai/ai-helper/suggest_title",
{ {
method: "POST", method: "POST",
data: { text: this.content }, data,
} }
); );
this.suggestions = suggestions; this.suggestions = suggestions;

View File

@ -13,6 +13,6 @@ export default class AiTitleSuggestion extends Component {
} }
<template> <template>
<AiTitleSuggester @composer={{@outletArgs.composer}} /> <AiTitleSuggester @composer={{@outletArgs.composer}} @topicState="new" />
</template> </template>
} }

View File

@ -13,6 +13,6 @@ export default class AiTitleSuggestion extends Component {
} }
<template> <template>
<AiTitleSuggester @buffered={{@outletArgs.buffered}} /> <AiTitleSuggester @buffered={{@outletArgs.buffered}} @topicState="edit" />
</template> </template>
} }

View File

@ -134,6 +134,70 @@ RSpec.describe DiscourseAi::AiHelper::AssistantController do
end end
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
"<item>What are your favourite fruits?</item><item>Love for fruits</item><item>Fruits are amazing</item><item>Favourite fruit list</item><item>Fruit share topic</item>"
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
"<item>Apples - the best fruit</item><item>Why apples are great</item><item>Apples are the best fruit</item><item>My love for apples</item><item>I love apples</item>"
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 describe "#caption_image" do
let(:image) { plugin_file_from_fixtures("100x100.jpg") } let(:image) { plugin_file_from_fixtures("100x100.jpg") }
let(:upload) { UploadCreator.new(image, "image.jpg").create_for(Discourse.system_user.id) } let(:upload) { UploadCreator.new(image, "image.jpg").create_for(Discourse.system_user.id) }