Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ def suggest
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ export default class AiTitleSuggestion extends Component {
}

<template>
<AiTitleSuggester @composer={{@outletArgs.composer}} />
<AiTitleSuggester @composer={{@outletArgs.composer}} @topicState="new" />
</template>
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ export default class AiTitleSuggestion extends Component {
}

<template>
<AiTitleSuggester @buffered={{@outletArgs.buffered}} />
<AiTitleSuggester @buffered={{@outletArgs.buffered}} @topicState="edit" />
</template>
}
64 changes: 64 additions & 0 deletions spec/requests/ai_helper/assistant_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,70 @@
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
let(:image) { plugin_file_from_fixtures("100x100.jpg") }
let(:upload) { UploadCreator.new(image, "image.jpg").create_for(Discourse.system_user.id) }
Expand Down