FIX: Use a dedicated prompt for thread titles (#464)
This commit is contained in:
parent
0ff5c0c2c4
commit
bccb7efdd6
|
@ -8,26 +8,38 @@ module DiscourseAi
|
||||||
end
|
end
|
||||||
|
|
||||||
def suggested_title
|
def suggested_title
|
||||||
return nil if thread_content.blank?
|
@thread.then { thread_content(_1) }.then { call_llm(_1) }.then { cleanup(_1) }
|
||||||
|
|
||||||
prompt = CompletionPrompt.enabled_by_name("generate_titles")
|
|
||||||
raise Discourse::InvalidParameters.new(:mode) if !prompt
|
|
||||||
|
|
||||||
response =
|
|
||||||
DiscourseAi::AiHelper::Assistant.new.generate_and_send_prompt(
|
|
||||||
prompt,
|
|
||||||
thread_content,
|
|
||||||
thread.original_message_user,
|
|
||||||
)
|
|
||||||
response.dig(:suggestions)&.first
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def call_llm(thread_content)
|
||||||
|
return nil if thread_content.blank?
|
||||||
|
|
||||||
attr_reader :thread
|
chat = "<input>\n#{thread_content}\n</input>"
|
||||||
|
|
||||||
def thread_content
|
prompt =
|
||||||
# Replace me by a proper API call
|
DiscourseAi::Completions::Prompt.new(
|
||||||
|
<<~TEXT.strip,
|
||||||
|
I want you to act as a title generator for chat between users. I will provide you with the chat transcription,
|
||||||
|
and you will generate a single attention-grabbing title. Please keep the title concise and under 15 words
|
||||||
|
and ensure that the meaning is maintained. The title will utilize the same language type of the chat.
|
||||||
|
I want you to only reply the suggested title and nothing else, do not write explanations.
|
||||||
|
You will find the chat between <input></input> XML tags.
|
||||||
|
TEXT
|
||||||
|
messages: [{ type: :user, content: chat, id: "User" }],
|
||||||
|
)
|
||||||
|
|
||||||
|
DiscourseAi::Completions::Llm.proxy(SiteSetting.ai_helper_model).generate(
|
||||||
|
prompt,
|
||||||
|
user: Discourse.system_user,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def cleanup(title)
|
||||||
|
title.split("\n").first.then { _1.match?(/^("|')(.*)("|')$/) ? title[1..-2] : _1 }
|
||||||
|
end
|
||||||
|
|
||||||
|
def thread_content(thread)
|
||||||
|
# TODO: Replace me by a proper API call
|
||||||
thread
|
thread
|
||||||
.chat_messages
|
.chat_messages
|
||||||
.joins(:user)
|
.joins(:user)
|
||||||
|
@ -35,6 +47,8 @@ module DiscourseAi
|
||||||
.map { |username, message| "#{username}: #{message}" }
|
.map { |username, message| "#{username}: #{message}" }
|
||||||
.join("\n")
|
.join("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
attr_reader :thread
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,17 +6,51 @@ RSpec.describe DiscourseAi::AiHelper::ChatThreadTitler do
|
||||||
before { SiteSetting.ai_helper_model = "fake:fake" }
|
before { SiteSetting.ai_helper_model = "fake:fake" }
|
||||||
|
|
||||||
fab!(:thread) { Fabricate(:chat_thread) }
|
fab!(:thread) { Fabricate(:chat_thread) }
|
||||||
|
fab!(:chat_message) { Fabricate(:chat_message, thread: thread) }
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
describe "#suggested_title" do
|
describe "#cleanup" do
|
||||||
it "suggest the first option from the generate_titles prompt" do
|
it "picks the first when there are multiple" do
|
||||||
titles =
|
titles = "The solitary horse\nThe horse etched in gold"
|
||||||
"<item>The solitary horse</item><item>The horse etched in gold</item><item>A horse's infinite journey</item><item>A horse lost in time</item><item>A horse's last ride</item>"
|
|
||||||
expected_title = "The solitary horse"
|
expected_title = "The solitary horse"
|
||||||
result =
|
|
||||||
DiscourseAi::Completions::Llm.with_prepared_responses([titles]) { titler.suggested_title }
|
result = titler.cleanup(titles)
|
||||||
|
|
||||||
|
expect(result).to eq(expected_title)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "cleans up double quotes enclosing the whole title" do
|
||||||
|
titles = '"The solitary horse"'
|
||||||
|
expected_title = "The solitary horse"
|
||||||
|
|
||||||
|
result = titler.cleanup(titles)
|
||||||
|
|
||||||
|
expect(result).to eq(expected_title)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "cleans up single quotes enclosing the whole title" do
|
||||||
|
titles = "'The solitary horse'"
|
||||||
|
expected_title = "The solitary horse"
|
||||||
|
|
||||||
|
result = titler.cleanup(titles)
|
||||||
|
|
||||||
|
expect(result).to eq(expected_title)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "leaves quotes in the middle of title" do
|
||||||
|
titles = "The 'solitary' horse"
|
||||||
|
expected_title = "The 'solitary' horse"
|
||||||
|
|
||||||
|
result = titler.cleanup(titles)
|
||||||
|
|
||||||
expect(result).to eq(expected_title)
|
expect(result).to eq(expected_title)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#thread_content" do
|
||||||
|
it "returns the chat message and user" do
|
||||||
|
expect(titler.thread_content(thread)).to include(chat_message.message)
|
||||||
|
expect(titler.thread_content(thread)).to include(chat_message.user.username)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue