2023-11-27 09:33:31 -03:00
# frozen_string_literal: true
RSpec . describe DiscourseAi :: AiHelper :: Assistant do
2024-03-05 16:48:28 +01:00
fab! ( :user )
2024-04-22 13:55:10 -03:00
fab! ( :empty_locale_user ) { Fabricate ( :user , locale : " " ) }
2023-11-27 09:33:31 -03:00
2025-05-27 10:37:30 -03:00
before do
assign_fake_provider_to ( :ai_helper_model )
Group . refresh_automatic_groups!
end
2024-01-29 16:04:25 -03:00
2023-11-27 09:33:31 -03:00
let ( :english_text ) { << ~ STRING }
To perfect his horror , Caesar , surrounded at the base of the statue by the impatient daggers of his friends ,
discovers among the faces and blades that of Marcus Brutus , his protege , perhaps his son , and he no longer
defends himself , but instead exclaims : 'You too, my son!' Shakespeare and Quevedo capture the pathetic cry .
STRING
2024-02-28 06:31:51 +11:00
describe ( " # custom_locale_instructions " ) do
it " Properly generates the per locale system instruction " do
SiteSetting . default_locale = " ko "
2024-07-04 08:23:37 -07:00
expect ( subject . custom_locale_instructions ( user , false ) ) . to eq (
2024-02-28 06:31:51 +11:00
" 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 " )
2024-07-04 08:23:37 -07:00
expect ( subject . custom_locale_instructions ( user , false ) ) . to eq (
2024-02-28 06:31:51 +11:00
" It is imperative that you write your answer in Hebrew (עברית), you are interacting with a Hebrew (עברית) speaking user. Leave tag names in English. " ,
)
end
2024-07-04 08:23:37 -07:00
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
2024-02-28 06:31:51 +11:00
end
2024-01-02 11:24:16 -08:00
describe ( " # available_prompts " ) do
2024-02-16 10:57:14 -08:00
before do
SiteSetting . ai_helper_illustrate_post_model = " disabled "
2024-02-19 15:21:55 +11:00
DiscourseAi :: AiHelper :: Assistant . clear_prompt_cache!
2024-01-02 11:24:16 -08:00
end
2024-02-16 10:57:14 -08:00
it " returns all available prompts " do
2024-07-04 08:23:37 -07:00
prompts = subject . available_prompts ( user )
2024-02-16 10:57:14 -08:00
expect ( prompts . map { | p | p [ :name ] } ) . to contain_exactly (
" translate " ,
" generate_titles " ,
" proofread " ,
" markdown_table " ,
" explain " ,
2024-12-31 08:04:25 +11:00
" replace_dates " ,
2024-02-16 10:57:14 -08:00
)
2024-01-02 11:24:16 -08:00
end
2024-11-28 09:14:21 +09:00
it " returns all prompts to be shown in the composer " do
prompts = subject . available_prompts ( user )
filtered_prompts = prompts . select { | prompt | prompt [ :location ] . include? ( " composer " ) }
2025-05-27 10:37:30 -03:00
2024-11-28 09:14:21 +09:00
expect ( filtered_prompts . map { | p | p [ :name ] } ) . to contain_exactly (
" translate " ,
" generate_titles " ,
" proofread " ,
" markdown_table " ,
2024-12-31 08:04:25 +11:00
" replace_dates " ,
2024-11-28 09:14:21 +09:00
)
end
it " returns all prompts to be shown in the post menu " do
prompts = subject . available_prompts ( user )
filtered_prompts = prompts . select { | prompt | prompt [ :location ] . include? ( " post " ) }
2025-05-27 10:37:30 -03:00
2024-11-28 09:14:21 +09:00
expect ( filtered_prompts . map { | p | p [ :name ] } ) . to contain_exactly (
" translate " ,
" explain " ,
" proofread " ,
)
end
2024-07-05 17:16:09 +08:00
it " does not raise an error when effective_locale does not exactly match keys in LocaleSiteSetting " do
SiteSetting . default_locale = " zh_CN "
expect { subject . available_prompts ( user ) } . not_to raise_error
end
2024-01-05 09:03:23 -08:00
context " when illustrate post model is enabled " do
2024-02-16 10:57:14 -08:00
before do
SiteSetting . ai_helper_illustrate_post_model = " stable_diffusion_xl "
2024-02-19 15:21:55 +11:00
DiscourseAi :: AiHelper :: Assistant . clear_prompt_cache!
2024-02-16 10:57:14 -08:00
end
2024-01-02 11:24:16 -08:00
it " returns the illustrate_post prompt in the list of all prompts " do
2024-07-04 08:23:37 -07:00
prompts = subject . available_prompts ( user )
2024-01-02 11:24:16 -08:00
expect ( prompts . map { | p | p [ :name ] } ) . to contain_exactly (
" translate " ,
" generate_titles " ,
" proofread " ,
" markdown_table " ,
" explain " ,
" illustrate_post " ,
2024-12-31 08:04:25 +11:00
" replace_dates " ,
2024-01-02 11:24:16 -08:00
)
end
end
end
2025-05-27 10:37:30 -03:00
describe ( " # attach_user_context " ) do
2024-04-22 13:55:10 -03:00
before { SiteSetting . allow_user_locale = true }
2025-05-27 10:37:30 -03:00
let ( :context ) { DiscourseAi :: Personas :: BotContext . new ( user : user ) }
2024-02-28 06:31:51 +11:00
2025-05-27 10:37:30 -03:00
it " is able to perform %LANGUAGE% replacements " do
subject . attach_user_context ( context , user )
2024-02-28 06:31:51 +11:00
2025-05-27 10:37:30 -03:00
expect ( context . user_language ) . to eq ( " English (US) " )
2024-02-28 06:31:51 +11:00
end
2024-04-22 13:55:10 -03:00
it " handles users with empty string locales " do
2025-05-27 10:37:30 -03:00
subject . attach_user_context ( context , empty_locale_user )
2024-04-22 13:55:10 -03:00
2025-05-27 10:37:30 -03:00
expect ( context . user_language ) . to eq ( " English (US) " )
2024-04-22 13:55:10 -03:00
end
2024-12-31 08:04:25 +11:00
context " with temporal context " do
it " replaces temporal context with timezone information " do
timezone = " America/New_York "
user . user_option . update! ( timezone : timezone )
freeze_time " 2024-01-01 12:00:00 "
2025-05-27 10:37:30 -03:00
subject . attach_user_context ( context , user )
2024-12-31 08:04:25 +11:00
2025-05-27 10:37:30 -03:00
expect ( context . temporal_context ) . to include ( %( "timezone":"America/New_York" ) )
2024-12-31 08:04:25 +11:00
end
it " uses UTC as default timezone when user timezone is not set " do
user . user_option . update! ( timezone : nil )
freeze_time " 2024-01-01 12:00:00 " do
2025-05-27 10:37:30 -03:00
subject . attach_user_context ( context , user )
2024-12-31 08:04:25 +11:00
2025-05-27 10:37:30 -03:00
parsed_context = JSON . parse ( context . temporal_context )
expect ( parsed_context . dig ( " user " , " timezone " ) ) . to eq ( " UTC " )
2024-12-31 08:04:25 +11:00
end
end
it " does not replace temporal context when user is nil " do
2025-05-27 10:37:30 -03:00
subject . attach_user_context ( context , nil )
expect ( context . temporal_context ) . to be_nil
2024-12-31 08:04:25 +11:00
end
end
2024-02-28 06:31:51 +11:00
end
2023-11-27 09:33:31 -03:00
describe " # generate_and_send_prompt " do
context " when using a prompt that returns text " do
2025-05-27 10:37:30 -03:00
let ( :mode ) { described_class :: TRANSLATE }
2023-11-27 09:33:31 -03:00
let ( :text_to_translate ) { << ~ STRING }
Para que su horror sea perfecto , César , acosado al pie de la estatua por lo impacientes puñales de sus amigos ,
descubre entre las caras y los aceros la de Marco Bruto , su protegido , acaso su hijo ,
y ya no se defiende y exclama : ¡ Tú también , hijo mío! Shakespeare y Quevedo recogen el patético grito .
STRING
it " Sends the prompt to the LLM and returns the response " do
response =
2023-11-29 15:17:46 +11:00
DiscourseAi :: Completions :: Llm . with_prepared_responses ( [ english_text ] ) do
2025-05-27 10:37:30 -03:00
subject . generate_and_send_prompt ( mode , text_to_translate , user )
2023-11-27 09:33:31 -03:00
end
expect ( response [ :suggestions ] ) . to contain_exactly ( english_text )
end
2025-06-12 12:33:12 -03:00
context " when the persona is not using structured outputs " do
it " still works " do
regular_persona = Fabricate ( :ai_persona , response_format : nil )
SiteSetting . ai_helper_translator_persona = regular_persona . id
response =
DiscourseAi :: Completions :: Llm . with_prepared_responses ( [ english_text ] ) do
subject . generate_and_send_prompt ( mode , text_to_translate , user )
end
expect ( response [ :suggestions ] ) . to contain_exactly ( english_text )
end
end
2023-11-27 09:33:31 -03:00
end
context " when using a prompt that returns a list " do
2025-05-27 10:37:30 -03:00
let ( :mode ) { described_class :: GENERATE_TITLES }
2023-11-27 09:33:31 -03:00
let ( :titles ) do
2023-11-28 12:52:22 -03:00
" <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> "
2023-11-27 09:33:31 -03:00
end
it " returns an array with each title " do
2023-11-28 12:52:22 -03:00
expected = [
" The solitary horse " ,
" The horse etched in gold " ,
" A horse's infinite journey " ,
" A horse lost in time " ,
" A horse's last ride " ,
]
2023-11-27 09:33:31 -03:00
response =
2023-11-29 15:17:46 +11:00
DiscourseAi :: Completions :: Llm . with_prepared_responses ( [ titles ] ) do
2025-05-27 10:37:30 -03:00
subject . generate_and_send_prompt ( mode , english_text , user )
2023-11-27 09:33:31 -03:00
end
expect ( response [ :suggestions ] ) . to contain_exactly ( * expected )
end
end
end
end