From 93e43b687b4d5f2d35c215f8dfafc45483956fab Mon Sep 17 00:00:00 2001 From: Sergio Bayona Date: Wed, 15 May 2024 12:27:25 -0500 Subject: [PATCH] make the function name and description easier to customize --- lib/instructor/openai/patch.rb | 14 ++++++++-- spec/openai/patch_spec.rb | 51 ++++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/lib/instructor/openai/patch.rb b/lib/instructor/openai/patch.rb index 927a624..72b892f 100644 --- a/lib/instructor/openai/patch.rb +++ b/lib/instructor/openai/patch.rb @@ -118,19 +118,29 @@ def build_function(model) { type: 'function', function: { - name: model.name.humanize.titleize, + name: generate_function_name(model), description: generate_description(model), parameters: model.json_schema } } end + def generate_function_name(model) + model.schema.fetch(:title, model.name) + end + # Generates the description for the function. # # @param model [Class] The response model class. # @return [String] The generated description. def generate_description(model) - "Correctly extracted `#{model.name}` with all the required parameters with correct types" + if model.respond_to?(:instructions) + raise Instructor::Error, 'The instructions must be a string' unless model.instructions.is_a?(String) + + model.instructions + else + "Correctly extracted `#{model.name}` with all the required parameters with correct types" + end end # Checks if the response is iterable. diff --git a/spec/openai/patch_spec.rb b/spec/openai/patch_spec.rb index c9a099f..e27f30d 100644 --- a/spec/openai/patch_spec.rb +++ b/spec/openai/patch_spec.rb @@ -13,7 +13,12 @@ def self.name 'User' end + def self.instructions + "Extract the user's name and age." + end + define_schema do + title 'SomeUser' property :name, String property :age, Integer end @@ -24,19 +29,39 @@ def self.name expect(patched_client).to eq(OpenAI::Client) end + context 'when generating description' do + let(:client) { patched_client.new } + + it "returns the model's instructions" do + expect(client.generate_description(user_model)).to eq("Extract the user's name and age.") + end + + it 'returns the default description when the model does not have instructions' do + model = Class.new do + include EasyTalk::Model + + def self.name + 'User' + end + + define_schema {} + end + + expect(client.generate_description(model)).to eq('Correctly extracted `User` with all the required parameters with correct types') + end + end + context 'with a new instance of the patched client' do it 'returns an instance of the patched client' do expect(patched_client.new).to be_an_instance_of(OpenAI::Client) end pending 'receives the chat method with the expected arguments' do - client = patched_client.new client.chat(parameters: {}, response_model: nil) expect(client).to have_received(:chat).with(parameters: {}, response_model: nil) end it 'does not require the response model argument' do - client = patched_client.new expect { client.chat(parameters: {}) }.not_to raise_error(ArgumentError) end @@ -45,6 +70,28 @@ def self.name expect { client.chat }.to raise_error(ArgumentError, 'missing keyword: :parameters') end + describe 'when setting the function_name' do + it 'returns the function_name based on the schema title' do + client = patched_client.new + expect(client.generate_function_name(user_model)).to eq('SomeUser') + end + + it 'returns the class name when the schema title is not defined' do + model = Class.new do + include EasyTalk::Model + + def self.name + 'User' + end + + define_schema {} + end + + client = patched_client.new + expect(client.generate_function_name(model)).to eq('User') + end + end + it 'returns an object with the expected valid attribute values', vcr: 'patching_spec/valid_response' do client = patched_client.new