feat(articles): use Responses API for search terms
This commit is contained in:
@@ -1,6 +1,23 @@
|
||||
module Enterprise::Concerns::Article
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
SEARCH_TERMS_FEATURE = 'help_center_article_generation'
|
||||
SEARCH_TERMS_SCHEMA = {
|
||||
name: 'article_search_terms',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
search_terms: {
|
||||
type: 'array',
|
||||
items: { type: 'string' }
|
||||
}
|
||||
},
|
||||
required: %w[search_terms],
|
||||
additionalProperties: false
|
||||
},
|
||||
strict: true
|
||||
}.freeze
|
||||
|
||||
included do
|
||||
after_save :add_article_embedding, if: -> { saved_change_to_title? || saved_change_to_description? || saved_change_to_content? }
|
||||
|
||||
@@ -67,23 +84,38 @@ module Enterprise::Concerns::Article
|
||||
{ role: 'system', content: article_to_search_terms_prompt },
|
||||
{ role: 'user', content: "title: #{title} \n description: #{description} \n content: #{content}" }
|
||||
]
|
||||
headers = { 'Content-Type' => 'application/json', 'Authorization' => "Bearer #{openai_api_key}" }
|
||||
body = { model: 'gpt-4o', messages: messages, response_format: { type: 'json_object' } }.to_json
|
||||
Rails.logger.info "Requesting Chat GPT with body: #{body}"
|
||||
response = HTTParty.post(openai_api_url, headers: headers, body: body)
|
||||
Rails.logger.info "Chat GPT response: #{response.body}"
|
||||
JSON.parse(response.parsed_response['choices'][0]['message']['content'])['search_terms']
|
||||
|
||||
response = responses_client.create(
|
||||
model: search_terms_route[:model],
|
||||
messages: messages,
|
||||
schema: SEARCH_TERMS_SCHEMA,
|
||||
reasoning_effort: search_terms_route[:reasoning_effort],
|
||||
metadata: {
|
||||
account_id: account_id,
|
||||
article_id: id,
|
||||
feature: 'article_search_terms'
|
||||
}
|
||||
)
|
||||
|
||||
JSON.parse(response[:message])['search_terms']
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def search_terms_route
|
||||
@search_terms_route ||= Llm::FeatureRouter.resolve(feature: SEARCH_TERMS_FEATURE, account: account)
|
||||
end
|
||||
|
||||
def responses_client
|
||||
@responses_client ||= Llm::ResponsesClient.new(api_key: openai_api_key, api_base: openai_api_base)
|
||||
end
|
||||
|
||||
def openai_api_key
|
||||
InstallationConfig.find_by(name: 'CAPTAIN_OPEN_AI_API_KEY')&.value.presence || raise(I18n.t('captain.api_key_missing'))
|
||||
end
|
||||
|
||||
def openai_api_url
|
||||
def openai_api_base
|
||||
endpoint = InstallationConfig.find_by(name: 'CAPTAIN_OPEN_AI_ENDPOINT')&.value.presence || 'https://api.openai.com/'
|
||||
endpoint = endpoint.chomp('/')
|
||||
"#{endpoint}/v1/chat/completions"
|
||||
endpoint.chomp('/')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -208,6 +208,58 @@ RSpec.describe Article do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#generate_article_search_terms' do
|
||||
let(:responses_client) { instance_double(Llm::ResponsesClient) }
|
||||
let(:article) do
|
||||
create(
|
||||
:article,
|
||||
account: account,
|
||||
category: category_1,
|
||||
content: 'How to configure billing invoices and payment reminders',
|
||||
description: 'Billing setup guide',
|
||||
portal: portal_1,
|
||||
author: user,
|
||||
title: 'Configure billing'
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
InstallationConfig.find_or_initialize_by(name: 'CAPTAIN_OPEN_AI_API_KEY').tap do |config|
|
||||
config.value = 'sk-test'
|
||||
config.save!
|
||||
end
|
||||
InstallationConfig.find_or_initialize_by(name: 'CAPTAIN_OPEN_AI_ENDPOINT').tap do |config|
|
||||
config.value = 'https://api.openai.test/v1'
|
||||
config.save!
|
||||
end
|
||||
allow(Llm::ResponsesClient).to receive(:new).and_return(responses_client)
|
||||
allow(responses_client).to receive(:create).and_return(
|
||||
{ message: { search_terms: ['billing setup', 'invoice reminders'] }.to_json }
|
||||
)
|
||||
end
|
||||
|
||||
it 'uses Responses API with the help center article model route' do
|
||||
expect(article.generate_article_search_terms).to eq(['billing setup', 'invoice reminders'])
|
||||
|
||||
expect(Llm::ResponsesClient).to have_received(:new).with(
|
||||
api_key: 'sk-test',
|
||||
api_base: 'https://api.openai.test/v1'
|
||||
)
|
||||
expect(responses_client).to have_received(:create).with(
|
||||
hash_including(
|
||||
model: Llm::Models.default_model_for('help_center_article_generation'),
|
||||
reasoning_effort: Llm::Models.reasoning_effort_for('help_center_article_generation'),
|
||||
schema: Enterprise::Concerns::Article::SEARCH_TERMS_SCHEMA,
|
||||
metadata: hash_including(
|
||||
account_id: account.id,
|
||||
article_id: article.id,
|
||||
feature: 'article_search_terms'
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.update_positions' do
|
||||
let!(:article_a) { create(:article, portal: portal_1, category: category_1, author: user, position: 10) }
|
||||
let!(:article_b) { create(:article, portal: portal_1, category: category_1, author: user, position: 11) }
|
||||
|
||||
Reference in New Issue
Block a user