Class: Boxcars::Openai
Overview
A engine that uses OpenAI’s API.
Constant Summary collapse
- DEFAULT_PARAMS =
The default parameters to use when asking the engine.
{ model: "gpt-4o-mini", temperature: 0.1, max_tokens: 4096 }.freeze
- DEFAULT_NAME =
the default name of the engine
"OpenAI engine"
- DEFAULT_DESCRIPTION =
the default description of the engine
"useful for when you need to use AI to answer questions. " \ "You should ask targeted questions"
Instance Attribute Summary collapse
-
#batch_size ⇒ Object
readonly
Returns the value of attribute batch_size.
-
#model_kwargs ⇒ Object
readonly
Returns the value of attribute model_kwargs.
-
#open_ai_params ⇒ Object
readonly
Returns the value of attribute open_ai_params.
-
#prompts ⇒ Object
readonly
Returns the value of attribute prompts.
Class Method Summary collapse
-
.open_ai_client(openai_access_token: nil) ⇒ OpenAI::Client
Get the OpenAI API client.
Instance Method Summary collapse
-
#check_response(response, must_haves: %w[choices])) ⇒ Object
make sure we got a valid response.
-
#client(prompt:, inputs: {}, openai_access_token: nil, **kwargs) ⇒ Object
Get an answer from the engine.
- #conversation_model?(model) ⇒ Boolean
-
#default_params ⇒ Object
Get the default parameters for the engine.
-
#initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs) ⇒ Openai
constructor
A engine is a container for a single tool to run.
-
#run(question, **kwargs) ⇒ Object
get an answer from the engine for a question.
Methods inherited from Engine
#generate, #generation_info, #get_num_tokens
Constructor Details
#initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs) ⇒ Openai
A engine is a container for a single tool to run.
29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/boxcars/engine/openai.rb', line 29 def initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs) @open_ai_params = DEFAULT_PARAMS.merge(kwargs) if @open_ai_params[:model] =~ /^o/ && @open_ai_params[:max_tokens].present? @open_ai_params[:max_completion_tokens] = @open_ai_params.delete(:max_tokens) @open_ai_params.delete(:temperature) end @prompts = prompts @batch_size = batch_size super(description: description, name: name) end |
Instance Attribute Details
#batch_size ⇒ Object (readonly)
Returns the value of attribute batch_size.
8 9 10 |
# File 'lib/boxcars/engine/openai.rb', line 8 def batch_size @batch_size end |
#model_kwargs ⇒ Object (readonly)
Returns the value of attribute model_kwargs.
8 9 10 |
# File 'lib/boxcars/engine/openai.rb', line 8 def model_kwargs @model_kwargs end |
#open_ai_params ⇒ Object (readonly)
Returns the value of attribute open_ai_params.
8 9 10 |
# File 'lib/boxcars/engine/openai.rb', line 8 def open_ai_params @open_ai_params end |
#prompts ⇒ Object (readonly)
Returns the value of attribute prompts.
8 9 10 |
# File 'lib/boxcars/engine/openai.rb', line 8 def prompts @prompts end |
Class Method Details
.open_ai_client(openai_access_token: nil) ⇒ OpenAI::Client
Get the OpenAI API client
45 46 47 48 49 |
# File 'lib/boxcars/engine/openai.rb', line 45 def self.open_ai_client(openai_access_token: nil) access_token = Boxcars.configuration.openai_access_token(openai_access_token: openai_access_token) organization_id = Boxcars.configuration.organization_id ::OpenAI::Client.new(access_token: access_token, organization_id: organization_id) end |
Instance Method Details
#check_response(response, must_haves: %w[choices])) ⇒ Object
make sure we got a valid response
105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/boxcars/engine/openai.rb', line 105 def check_response(response, must_haves: %w[choices]) if response['error'] code = response.dig('error', 'code') msg = response.dig('error', 'message') || 'unknown error' raise KeyError, "OPENAI_ACCESS_TOKEN not valid" if code == 'invalid_api_key' raise ValueError, "OpenAI error: #{msg}" end must_haves.each do |key| raise ValueError, "Expecting key #{key} in response" unless response.key?(key) end end |
#client(prompt:, inputs: {}, openai_access_token: nil, **kwargs) ⇒ Object
Get an answer from the engine.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/boxcars/engine/openai.rb', line 60 def client(prompt:, inputs: {}, openai_access_token: nil, **kwargs) clnt = Openai.open_ai_client(openai_access_token: openai_access_token) params = open_ai_params.merge(kwargs) if conversation_model?(params[:model]) prompt = prompt.first if prompt.is_a?(Array) if params[:model] =~ /^o/ params.delete(:response_format) params.delete(:stop) end params = prompt.(inputs).merge(params) if Boxcars.configuration.log_prompts Boxcars.debug(params[:messages].last(2).map { |p| ">>>>>> Role: #{p[:role]} <<<<<<\n#{p[:content]}" }.join("\n"), :cyan) end clnt.chat(parameters: params) else params = prompt.as_prompt(inputs: inputs).merge(params) Boxcars.debug("Prompt after formatting:\n#{params[:prompt]}", :cyan) if Boxcars.configuration.log_prompts clnt.completions(parameters: params) end end |
#conversation_model?(model) ⇒ Boolean
51 52 53 |
# File 'lib/boxcars/engine/openai.rb', line 51 def conversation_model?(model) !!(model =~ /(^gpt-4)|(-turbo\b)|(^o\d)/) end |
#default_params ⇒ Object
Get the default parameters for the engine.
96 97 98 |
# File 'lib/boxcars/engine/openai.rb', line 96 def default_params open_ai_params end |
#run(question, **kwargs) ⇒ Object
get an answer from the engine for a question.
84 85 86 87 88 89 90 91 92 93 |
# File 'lib/boxcars/engine/openai.rb', line 84 def run(question, **kwargs) prompt = Prompt.new(template: question) response = client(prompt: prompt, **kwargs) raise Error, "OpenAI: No response from API" unless response raise Error, "OpenAI: #{response['error']}" if response["error"] answer = response["choices"].map { |c| c.dig("message", "content") || c["text"] }.join("\n").strip puts answer answer end |