DEV: Use site locale for composer helper translations (#698)

This commit is contained in:
Keegan George 2024-07-04 08:23:37 -07:00 committed by GitHub
parent 38153608f8
commit eab2f74b58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 70 additions and 22 deletions

View File

@ -12,6 +12,7 @@ module DiscourseAi
def suggest def suggest
input = get_text_param! input = get_text_param!
force_default_locale = params[:force_default_locale] || false
prompt = CompletionPrompt.find_by(id: params[:mode]) prompt = CompletionPrompt.find_by(id: params[:mode])
@ -31,6 +32,7 @@ module DiscourseAi
prompt, prompt,
input, input,
current_user, current_user,
force_default_locale,
), ),
status: 200 status: 200
end end

View File

@ -8,6 +8,7 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
import { caretPosition, getCaretPosition } from "discourse/lib/utilities"; import { caretPosition, getCaretPosition } from "discourse/lib/utilities";
import { INPUT_DELAY } from "discourse-common/config/environment"; import { INPUT_DELAY } from "discourse-common/config/environment";
import { afterRender, bind, debounce } from "discourse-common/utils/decorators"; import { afterRender, bind, debounce } from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
import { showComposerAIHelper } from "../../lib/show-ai-helper"; import { showComposerAIHelper } from "../../lib/show-ai-helper";
export default class AiHelperContextMenu extends Component { export default class AiHelperContextMenu extends Component {
@ -76,7 +77,28 @@ export default class AiHelperContextMenu extends Component {
prompts = prompts prompts = prompts
.filter((p) => p.location.includes("composer")) .filter((p) => p.location.includes("composer"))
.filter((p) => p.name !== "generate_titles"); .filter((p) => p.name !== "generate_titles")
.map((p) => {
// AI helper by default returns interface locale on translations
// Since we want site default translations (and we are using: force_default_locale)
// we need to replace the translated_name with the site default locale name
const siteLocale = this.siteSettings.default_locale;
const availableLocales = JSON.parse(
this.siteSettings.available_locales
);
const locale = availableLocales.find((l) => l.value === siteLocale);
const translatedName = I18n.t(
"discourse_ai.ai_helper.context_menu.translate_prompt",
{
language: locale.name,
}
);
if (p.name === "translate") {
return { ...p, translated_name: translatedName };
}
return p;
});
// Find the custom_prompt object and move it to the beginning of the array // Find the custom_prompt object and move it to the beginning of the array
const customPromptIndex = prompts.findIndex( const customPromptIndex = prompts.findIndex(
@ -367,6 +389,7 @@ export default class AiHelperContextMenu extends Component {
mode: option.id, mode: option.id,
text: this.selectedText, text: this.selectedText,
custom_prompt: this.customPromptValue, custom_prompt: this.customPromptValue,
force_default_locale: true,
}, },
}); });

View File

@ -292,6 +292,7 @@ en:
title: "Custom Prompt" title: "Custom Prompt"
placeholder: "Enter a custom prompt..." placeholder: "Enter a custom prompt..."
submit: "Send Prompt" submit: "Send Prompt"
translate_prompt: "Translate to %{language}"
post_options_menu: post_options_menu:
trigger: "Ask AI" trigger: "Ask AI"
title: "Ask AI" title: "Ask AI"

View File

@ -158,7 +158,7 @@ en:
errors: errors:
completion_request_failed: "Something went wrong while trying to provide suggestions. Please, try again." completion_request_failed: "Something went wrong while trying to provide suggestions. Please, try again."
prompts: prompts:
translate: Translate to English translate: Translate to %{language}
generate_titles: Suggest topic titles generate_titles: Suggest topic titles
proofread: Proofread text proofread: Proofread text
markdown_table: Generate Markdown table markdown_table: Generate Markdown table

View File

@ -11,7 +11,7 @@ module DiscourseAi
prompt_cache.flush! prompt_cache.flush!
end end
def available_prompts def available_prompts(user)
key = "prompt_cache_#{I18n.locale}" key = "prompt_cache_#{I18n.locale}"
self self
.class .class
@ -27,9 +27,19 @@ module DiscourseAi
prompts = prompts =
prompts.map do |prompt| prompts.map do |prompt|
if prompt.name == "translate"
locale = user.effective_locale
locale_hash = LocaleSiteSetting.language_names[locale]
translation =
I18n.t(
"discourse_ai.ai_helper.prompts.translate",
language: locale_hash["nativeName"],
) || prompt.translated_name || prompt.name
else
translation = translation =
I18n.t("discourse_ai.ai_helper.prompts.#{prompt.name}", default: nil) || I18n.t("discourse_ai.ai_helper.prompts.#{prompt.name}", default: nil) ||
prompt.translated_name || prompt.name prompt.translated_name || prompt.name
end
{ {
id: prompt.id, id: prompt.id,
@ -44,9 +54,9 @@ module DiscourseAi
end end
end end
def custom_locale_instructions(user = nil) def custom_locale_instructions(user = nil, force_default_locale)
locale = SiteSetting.default_locale locale = SiteSetting.default_locale
locale = user.locale || SiteSetting.default_locale if SiteSetting.allow_user_locale && user locale = user.effective_locale if !force_default_locale
locale_hash = LocaleSiteSetting.language_names[locale] locale_hash = LocaleSiteSetting.language_names[locale]
if locale != "en" && locale_hash if locale != "en" && locale_hash
@ -57,15 +67,17 @@ module DiscourseAi
end end
end end
def localize_prompt!(prompt, user = nil) def localize_prompt!(prompt, user = nil, force_default_locale)
locale_instructions = custom_locale_instructions(user) locale_instructions = custom_locale_instructions(user, force_default_locale)
if locale_instructions if locale_instructions
prompt.messages[0][:content] = prompt.messages[0][:content] + locale_instructions prompt.messages[0][:content] = prompt.messages[0][:content] + locale_instructions
end end
if prompt.messages[0][:content].include?("%LANGUAGE%") if prompt.messages[0][:content].include?("%LANGUAGE%")
locale = SiteSetting.default_locale locale = SiteSetting.default_locale
locale = user.locale if SiteSetting.allow_user_locale && user&.locale.present?
locale = user.effective_locale if user && !force_default_locale
locale_hash = LocaleSiteSetting.language_names[locale] locale_hash = LocaleSiteSetting.language_names[locale]
prompt.messages[0][:content] = prompt.messages[0][:content].gsub( prompt.messages[0][:content] = prompt.messages[0][:content].gsub(
@ -75,10 +87,10 @@ module DiscourseAi
end end
end end
def generate_prompt(completion_prompt, input, user, &block) def generate_prompt(completion_prompt, input, user, force_default_locale = false, &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) localize_prompt!(prompt, user, force_default_locale)
llm.generate( llm.generate(
prompt, prompt,
@ -90,8 +102,8 @@ module DiscourseAi
) )
end end
def generate_and_send_prompt(completion_prompt, input, user) def generate_and_send_prompt(completion_prompt, input, user, force_default_locale = false)
completion_result = generate_prompt(completion_prompt, input, user) completion_result = generate_prompt(completion_prompt, input, user, force_default_locale)
result = { type: completion_prompt.prompt_type } result = { type: completion_prompt.prompt_type }
result[:suggestions] = ( result[:suggestions] = (

View File

@ -38,7 +38,7 @@ module DiscourseAi
end, end,
) do ) do
ActiveModel::ArraySerializer.new( ActiveModel::ArraySerializer.new(
DiscourseAi::AiHelper::Assistant.new.available_prompts, DiscourseAi::AiHelper::Assistant.new.available_prompts(scope.user),
root: false, root: false,
) )
end end

View File

@ -16,17 +16,27 @@ RSpec.describe DiscourseAi::AiHelper::Assistant do
describe("#custom_locale_instructions") do describe("#custom_locale_instructions") do
it "Properly generates the per locale system instruction" do it "Properly generates the per locale system instruction" do
SiteSetting.default_locale = "ko" SiteSetting.default_locale = "ko"
expect(subject.custom_locale_instructions).to eq( expect(subject.custom_locale_instructions(user, false)).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.", "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 SiteSetting.allow_user_locale = true
user.update!(locale: "he") user.update!(locale: "he")
expect(subject.custom_locale_instructions(user)).to eq( expect(subject.custom_locale_instructions(user, false)).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.", "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
it "returns sytstem instructions using Site locale if force_default_locale is true" do
SiteSetting.default_locale = "ko"
SiteSetting.allow_user_locale = true
user.update!(locale: "he")
expect(subject.custom_locale_instructions(user, true)).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.",
)
end
end end
describe("#available_prompts") do describe("#available_prompts") do
@ -36,7 +46,7 @@ RSpec.describe DiscourseAi::AiHelper::Assistant do
end end
it "returns all available prompts" do it "returns all available prompts" do
prompts = subject.available_prompts prompts = subject.available_prompts(user)
expect(prompts.length).to eq(6) expect(prompts.length).to eq(6)
expect(prompts.map { |p| p[:name] }).to contain_exactly( expect(prompts.map { |p| p[:name] }).to contain_exactly(
@ -56,7 +66,7 @@ RSpec.describe DiscourseAi::AiHelper::Assistant do
end end
it "returns the illustrate_post prompt in the list of all prompts" do it "returns the illustrate_post prompt in the list of all prompts" do
prompts = subject.available_prompts prompts = subject.available_prompts(user)
expect(prompts.length).to eq(7) expect(prompts.length).to eq(7)
expect(prompts.map { |p| p[:name] }).to contain_exactly( expect(prompts.map { |p| p[:name] }).to contain_exactly(

View File

@ -21,7 +21,7 @@ describe DiscourseAi::AiHelper::EntryPoint do
parsed["current_user"]["ai_helper_prompts"].find { |prompt| prompt["name"] == "translate" } parsed["current_user"]["ai_helper_prompts"].find { |prompt| prompt["name"] == "translate" }
expect(translate_prompt["translated_name"]).to eq( expect(translate_prompt["translated_name"]).to eq(
I18n.t("discourse_ai.ai_helper.prompts.translate"), I18n.t("discourse_ai.ai_helper.prompts.translate", language: "English (US)"),
) )
I18n.with_locale("fr") do I18n.with_locale("fr") do
@ -32,7 +32,7 @@ describe DiscourseAi::AiHelper::EntryPoint do
parsed["current_user"]["ai_helper_prompts"].find { |prompt| prompt["name"] == "translate" } parsed["current_user"]["ai_helper_prompts"].find { |prompt| prompt["name"] == "translate" }
expect(translate_prompt["translated_name"]).to eq( expect(translate_prompt["translated_name"]).to eq(
I18n.t("discourse_ai.ai_helper.prompts.translate", locale: "fr"), I18n.t("discourse_ai.ai_helper.prompts.translate", locale: "fr", language: "Français"),
) )
end end
end end