FEATURE: AI helper support in non English languages (#489)

* FEATURE: AI helper support in non English languages

This attempts some prompt engineering to coerce AI helper to answer
in the appropriate language.

Note mileage will vary, in testing GPT-4 produces the best results
GPT-3.5 can return OKish results.

* Extend non english support for GPT-4V image caption

* Update db/fixtures/ai_helper/603_completion_prompts.rb

---------

Co-authored-by: Rafael Silva <xfalcox@gmail.com>
This commit is contained in:
Sam 2024-02-28 06:31:51 +11:00 committed by GitHub
parent aabff87501
commit d036f3fb8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 72 additions and 8 deletions

View File

@ -9,19 +9,16 @@ CompletionPrompt.seed do |cp|
cp.temperature = 0.2 cp.temperature = 0.2
cp.messages = { cp.messages = {
insts: <<~TEXT, insts: <<~TEXT,
I want you to act as an English translator, spelling corrector and improver. I will write to you I want you to act as an %LANGUAGE% translator, spelling corrector and improver. I will write to you
in any language and you will detect the language, translate it and answer in the corrected and in any language and you will detect the language, translate it and answer in the corrected and
improved version of my text, in English. I want you to replace my simplified A0-level words and improved version of my text, in %LANGUAGE%. I want you to replace my simplified A0-level words and
sentences with more beautiful and elegant, upper level English words and sentences. sentences with more beautiful and elegant, upper level %LANGUAGE% words and sentences.
Keep the meaning same, but make them more literary. I want you to only reply the correction, Keep the meaning same, but make them more literary. I want you to only reply the correction,
the improvements and nothing else, do not write explanations. the improvements and nothing else, do not write explanations.
You will find the text between <input></input> XML tags. You will find the text between <input></input> XML tags.
Include your translation between <output></output> XML tags. Include your translation between <output></output> XML tags.
TEXT TEXT
examples: [ examples: [["<input>Hello</input>", "<output>...%LANGUAGE% translation...</output>"]],
["<input>Hello world</input>", "<output>Hello world</output>"],
["<input>Bonjour le monde</input>", "<output>Hello world</output>"],
],
} }
end end

View File

@ -40,9 +40,42 @@ module DiscourseAi
end end
end end
def custom_locale_instructions(user = nil)
locale = SiteSetting.default_locale
locale = user.locale || SiteSetting.default_locale if SiteSetting.allow_user_locale && user
locale_hash = LocaleSiteSetting.language_names[locale]
if locale != "en" && locale_hash
locale_description = "#{locale_hash["name"]} (#{locale_hash["nativeName"]})"
"It is imperative that you write your answer in #{locale_description}, you are interacting with a #{locale_description} speaking user. Leave tag names in English."
else
nil
end
end
def localize_prompt!(prompt, user = nil)
locale_instructions = custom_locale_instructions(user)
if locale_instructions
prompt.messages[0][:content] = prompt.messages[0][:content] + locale_instructions
end
if prompt.messages[0][:content].include?("%LANGUAGE%")
locale = SiteSetting.default_locale
locale = user.locale || SiteSetting.default_locale if SiteSetting.allow_user_locale &&
user
locale_hash = LocaleSiteSetting.language_names[locale]
prompt.messages[0][:content] = prompt.messages[0][:content].gsub(
"%LANGUAGE%",
"#{locale_hash["name"]}",
)
end
end
def generate_prompt(completion_prompt, input, user, &block) def generate_prompt(completion_prompt, input, user, &block)
llm = DiscourseAi::Completions::Llm.proxy(SiteSetting.ai_helper_model) llm = DiscourseAi::Completions::Llm.proxy(SiteSetting.ai_helper_model)
prompt = completion_prompt.messages_with_input(input) prompt = completion_prompt.messages_with_input(input)
localize_prompt!(prompt, user)
llm.generate( llm.generate(
prompt, prompt,
@ -111,7 +144,12 @@ module DiscourseAi
{ {
type: :user, type: :user,
content: [ content: [
{ type: "text", text: "Describe this image in a single sentence" }, {
type: "text",
text:
"Describe this image in a single sentence" +
custom_locale_instructions(user),
},
{ type: "image_url", image_url: image_url }, { type: "image_url", image_url: image_url },
], ],
}, },

View File

@ -12,6 +12,22 @@ RSpec.describe DiscourseAi::AiHelper::Assistant do
defends himself, but instead exclaims: 'You too, my son!' Shakespeare and Quevedo capture the pathetic cry. defends himself, but instead exclaims: 'You too, my son!' Shakespeare and Quevedo capture the pathetic cry.
STRING STRING
describe("#custom_locale_instructions") do
it "Properly generates the per locale system instruction" do
SiteSetting.default_locale = "ko"
expect(subject.custom_locale_instructions).to eq(
"It is imperative that you write your answer in Korean (한국어), you are interacting with a Korean (한국어) speaking user. Leave tag names in English.",
)
SiteSetting.allow_user_locale = true
user.update!(locale: "he")
expect(subject.custom_locale_instructions(user)).to eq(
"It is imperative that you write your answer in Hebrew (עברית), you are interacting with a Hebrew (עברית) speaking user. Leave tag names in English.",
)
end
end
describe("#available_prompts") do describe("#available_prompts") do
before do before do
SiteSetting.ai_helper_illustrate_post_model = "disabled" SiteSetting.ai_helper_illustrate_post_model = "disabled"
@ -55,6 +71,19 @@ RSpec.describe DiscourseAi::AiHelper::Assistant do
end end
end end
describe("#localize_prompt!") do
it "is able to perform %LANGUAGE% replacements" do
prompt =
CompletionPrompt.new(messages: { insts: "This is a %LANGUAGE% test" }).messages_with_input(
"test",
)
subject.localize_prompt!(prompt, user)
expect(prompt.messages[0][:content].strip).to eq("This is a English (US) test")
end
end
describe "#generate_and_send_prompt" do describe "#generate_and_send_prompt" do
context "when using a prompt that returns text" do context "when using a prompt that returns text" do
let(:mode) { CompletionPrompt::TRANSLATE } let(:mode) { CompletionPrompt::TRANSLATE }