asimov 0.1.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,28 +4,54 @@ module Asimov
4
4
  # Class interface for API methods in the "/fine-tunes" URI subspace.
5
5
  ##
6
6
  class Finetunes < Base
7
- URI_PREFIX = "/fine-tunes".freeze
7
+ RESOURCE = "fine-tunes".freeze
8
+ private_constant :RESOURCE
8
9
 
10
+ ##
11
+ # Lists the set of fine-tuning jobs for this API key and (optionally) organization.
12
+ ##
9
13
  def list
10
- http_get(path: URI_PREFIX)
14
+ rest_index(resource: RESOURCE)
11
15
  end
12
16
 
13
- def create(parameters:)
14
- raise MissingRequiredParameterError.new(:training_file) unless parameters[:training_file]
17
+ ##
18
+ # Creates a new fine-tuning job with the specified parameters.
19
+ #
20
+ # @param [String] training_file the id of the training file to use for fine tuning
21
+ # @param [Hash] parameters the parameters passed with the fine tuning job
22
+ ##
23
+ def create(training_file:, parameters: {})
24
+ raise MissingRequiredParameterError.new(:training_file) unless training_file
15
25
 
16
- json_post(path: URI_PREFIX, parameters: parameters)
26
+ rest_create_w_json_params(resource: RESOURCE,
27
+ parameters: parameters.merge(training_file: training_file))
17
28
  end
18
29
 
30
+ ##
31
+ # Retrieves the details of a fine-tuning job with the specified id.
32
+ #
33
+ # @param [String] fine_tune_id the id of fine tuning job
34
+ ##
19
35
  def retrieve(fine_tune_id:)
20
- http_get(path: "#{URI_PREFIX}/#{fine_tune_id}")
36
+ rest_get(resource: RESOURCE, id: fine_tune_id)
21
37
  end
22
38
 
39
+ ##
40
+ # Cancels the details of a fine-tuning job with the specified id.
41
+ #
42
+ # @param [String] fine_tune_id the id of fine tuning job
43
+ ##
23
44
  def cancel(fine_tune_id:)
24
- multipart_post(path: "#{URI_PREFIX}/#{fine_tune_id}/cancel")
45
+ rest_create_w_multipart_params(resource: [RESOURCE, fine_tune_id, "cancel"])
25
46
  end
26
47
 
27
- def events(fine_tune_id:)
28
- http_get(path: "#{URI_PREFIX}/#{fine_tune_id}/events")
48
+ ##
49
+ # Lists the events associated with a fine-tuning job with the specified id.
50
+ #
51
+ # @param [String] fine_tune_id the id of fine tuning job
52
+ ##
53
+ def list_events(fine_tune_id:)
54
+ rest_index(resource: [RESOURCE, fine_tune_id, "events"])
29
55
  end
30
56
  end
31
57
  end
@@ -6,22 +6,49 @@ module Asimov
6
6
  # Class interface for API methods in the "/images" URI subspace.
7
7
  ##
8
8
  class Images < Base
9
- URI_PREFIX = "/images".freeze
9
+ RESOURCE = "images".freeze
10
+ private_constant :RESOURCE
10
11
 
11
- def create(parameters:)
12
- raise MissingRequiredParameterError.new(:prompt) unless parameters[:prompt]
12
+ ##
13
+ # Creates an image using the specified prompt.
14
+ #
15
+ # @param [String] prompt the prompt used to create the image
16
+ # @param [Hash] parameters additional parameters passed to the API
17
+ ##
18
+ def create(prompt:, parameters: {})
19
+ raise MissingRequiredParameterError.new(:prompt) unless prompt
13
20
 
14
- json_post(path: "#{URI_PREFIX}/generations", parameters: parameters)
21
+ rest_create_w_json_params(resource: [RESOURCE, "generations"],
22
+ parameters: parameters.merge({ prompt: prompt }))
15
23
  end
16
24
 
17
- def create_edit(parameters:)
18
- raise MissingRequiredParameterError.new(:prompt) unless parameters[:prompt]
25
+ ##
26
+ # Creates edits of the specified image based on the prompt.
27
+ #
28
+ # @param [String] image file name or a File-like object of the base image
29
+ # @param [String] prompt the prompt used to guide the edit
30
+ # @param [Hash] parameters additional parameters passed to the API
31
+ ##
32
+ def create_edit(image:, prompt:, parameters: {})
33
+ raise MissingRequiredParameterError.new(:prompt) unless prompt
19
34
 
20
- multipart_post(path: "#{URI_PREFIX}/edits", parameters: open_files(parameters))
35
+ rest_create_w_multipart_params(resource: [RESOURCE, "edits"],
36
+ parameters: open_files(parameters.merge({
37
+ image: image,
38
+ prompt: prompt
39
+ })))
21
40
  end
22
41
 
23
- def create_variation(parameters:)
24
- multipart_post(path: "#{URI_PREFIX}/variations", parameters: open_files(parameters))
42
+ ##
43
+ # Creates variations of the specified image.
44
+ #
45
+ # @param [String] image file name or a File-like object of the base image
46
+ # @param [Hash] parameters additional parameters passed to the API
47
+ # @option parameters [String] :mask mask file name or a File-like object
48
+ ##
49
+ def create_variation(image:, parameters: {})
50
+ rest_create_w_multipart_params(resource: [RESOURCE, "variations"],
51
+ parameters: open_files(parameters.merge({ image: image })))
25
52
  end
26
53
 
27
54
  private
@@ -30,7 +57,7 @@ module Asimov
30
57
  raise MissingRequiredParameterError.new(:image) unless parameters[:image]
31
58
 
32
59
  parameters = parameters.merge(image: Utils::FileManager.open(parameters[:image]))
33
- parameters.merge!(mask: Utils::FileManager.open(parameters[:mask])) if parameters[:mask]
60
+ parameters[:mask] = Utils::FileManager.open(parameters[:mask]) if parameters[:mask]
34
61
  parameters
35
62
  end
36
63
  end
@@ -4,18 +4,35 @@ module Asimov
4
4
  # Class interface for API methods in the "/models" URI subspace.
5
5
  ##
6
6
  class Models < Base
7
- URI_PREFIX = "/models".freeze
7
+ RESOURCE = "models".freeze
8
+ private_constant :RESOURCE
8
9
 
10
+ ##
11
+ # Lists the models accessible to this combination of OpenAI API
12
+ # key and organization id.
13
+ ##
9
14
  def list
10
- http_get(path: URI_PREFIX)
15
+ rest_index(resource: RESOURCE)
11
16
  end
12
17
 
18
+ ##
19
+ # Retrieve information about the model with the specified
20
+ # model_id.
21
+ #
22
+ # @param [String] model_id the id of the model to be retrieved
23
+ ##
13
24
  def retrieve(model_id:)
14
- http_get(path: "#{URI_PREFIX}/#{model_id}")
25
+ rest_get(resource: RESOURCE, id: model_id)
15
26
  end
16
27
 
28
+ ##
29
+ # Deletes the model with the specified model_id. Only
30
+ # works on models created via fine tuning.
31
+ #
32
+ # @param [String] model_id the id of the model to be deleted
33
+ ##
17
34
  def delete(model_id:)
18
- http_delete(path: "#{URI_PREFIX}/#{model_id}")
35
+ rest_delete(resource: RESOURCE, id: model_id)
19
36
  end
20
37
  end
21
38
  end
@@ -4,10 +4,17 @@ module Asimov
4
4
  # Class interface for API methods in the "/moderations" URI subspace.
5
5
  ##
6
6
  class Moderations < Base
7
- def create(parameters:)
8
- raise MissingRequiredParameterError.new(:input) unless parameters[:input]
7
+ ##
8
+ # Calls the /moderations POST endpoint with the specified parameters.
9
+ #
10
+ # @param [String] input the text being evaluated by the API
11
+ # @param [Hash] parameters the set of parameters being passed to the API
12
+ ##
13
+ def create(input:, parameters: {})
14
+ raise MissingRequiredParameterError.new(:input) unless input
9
15
 
10
- json_post(path: "/moderations", parameters: parameters)
16
+ rest_create_w_json_params(resource: "moderations",
17
+ parameters: parameters.merge({ input: input }))
11
18
  end
12
19
  end
13
20
  end
data/lib/asimov/client.rb CHANGED
@@ -3,6 +3,8 @@ require "httparty"
3
3
  require_relative "headers_factory"
4
4
  require_relative "utils/request_options_validator"
5
5
  require_relative "api_v1/base"
6
+ require_relative "api_v1/audio"
7
+ require_relative "api_v1/chat"
6
8
  require_relative "api_v1/completions"
7
9
  require_relative "api_v1/edits"
8
10
  require_relative "api_v1/embeddings"
@@ -20,7 +22,7 @@ module Asimov
20
22
  class Client
21
23
  extend Forwardable
22
24
 
23
- attr_reader :api_key, :organization_id, :api_version, :request_options
25
+ attr_reader :api_key, :organization_id, :api_version, :request_options, :openai_api_base
24
26
 
25
27
  ##
26
28
  # Creates a new Asimov::Client. Includes several optional named parameters:
@@ -29,17 +31,36 @@ module Asimov
29
31
  # defaults to the application-wide configuration
30
32
  # organization_id - The OpenAI organization identifier that this Asimov::Client instance
31
33
  # will use. If unspecified, defaults to the application-wide configuration.
34
+ # request_options - HTTParty request options that will be passed to the underlying network
35
+ # client. Merges (and overrides) global configuration value.
36
+ # openai_api_base - Custom base URI for the API calls made by this client. Defaults to global
37
+ # configuration value.
32
38
  ##
33
39
  def initialize(api_key: nil, organization_id: HeadersFactory::NULL_ORGANIZATION_ID,
34
- request_options: {})
40
+ request_options: {}, openai_api_base: nil)
35
41
  @headers_factory = HeadersFactory.new(api_key,
36
42
  organization_id)
37
43
  @request_options = Asimov.configuration.request_options
38
44
  .merge(Utils::RequestOptionsValidator.validate(request_options))
39
45
  .freeze
46
+ initialize_openai_api_base(openai_api_base)
40
47
  end
41
48
  def_delegators :@headers_factory, :api_key, :organization_id, :headers
42
49
 
50
+ ##
51
+ # Use the audio method to access API calls in the /audio URI space.
52
+ ##
53
+ def audio
54
+ @audio ||= Asimov::ApiV1::Audio.new(client: self)
55
+ end
56
+
57
+ ##
58
+ # Use the chat method to access API calls in the /chat URI space.
59
+ ##
60
+ def chat
61
+ @chat ||= Asimov::ApiV1::Chat.new(client: self)
62
+ end
63
+
43
64
  ##
44
65
  # Use the completions method to access API calls in the /completions URI space.
45
66
  ##
@@ -95,5 +116,17 @@ module Asimov
95
116
  def moderations
96
117
  @moderations ||= Asimov::ApiV1::Moderations.new(client: self)
97
118
  end
119
+
120
+ private
121
+
122
+ def initialize_openai_api_base(openai_api_base)
123
+ @openai_api_base = openai_api_base || Asimov.configuration.openai_api_base
124
+ if @openai_api_base
125
+ @openai_api_base = HTTParty.normalize_base_uri(@openai_api_base)
126
+ else
127
+ raise Asimov::MissingBaseUriError,
128
+ "No API Base URI was provided for this client."
129
+ end
130
+ end
98
131
  end
99
132
  end
@@ -9,18 +9,39 @@ module Asimov
9
9
  class Configuration
10
10
  attr_accessor :api_key, :organization_id
11
11
 
12
- attr_reader :request_options
12
+ attr_reader :request_options, :openai_api_base
13
13
 
14
+ DEFAULT_OPENAI_BASE_URI = "https://api.openai.com/v1".freeze
15
+
16
+ ##
17
+ # Initializes the Configuration object and resets it to default values.
18
+ ##
14
19
  def initialize
15
20
  reset
16
21
  end
17
22
 
23
+ ##
24
+ # Reset the configuration to default values. Mostly used for testing.
25
+ ##
18
26
  def reset
19
27
  @api_key = nil
20
28
  @organization_id = nil
21
29
  @request_options = {}
30
+ @openai_api_base = DEFAULT_OPENAI_BASE_URI
31
+ end
32
+
33
+ ##
34
+ # Sets the openai_api_base on the Configuration. Typically not invoked
35
+ # directly, but rather through use of `Asimov.configure`.
36
+ ##
37
+ def openai_api_base=(val)
38
+ @openai_api_base = val ? HTTParty.normalize_base_uri(val) : nil
22
39
  end
23
40
 
41
+ ##
42
+ # Sets the request_options on the Configuration. Typically not invoked
43
+ # directly, but rather through use of `Asimov.configure`.
44
+ ##
24
45
  def request_options=(val)
25
46
  @request_options = Utils::RequestOptionsValidator.validate(val)
26
47
  end
data/lib/asimov/error.rb CHANGED
@@ -9,8 +9,18 @@ module Asimov
9
9
  ##
10
10
  class ConfigurationError < Error; end
11
11
 
12
+ ##
13
+ # Error that occurs when there is no configured
14
+ # API key for a newly created Asimov::Client.
15
+ ##
12
16
  class MissingApiKeyError < ConfigurationError; end
13
17
 
18
+ ##
19
+ # Error that occurs when there is no configured
20
+ # base URI for a newly created Asimov::Client.
21
+ ##
22
+ class MissingBaseUriError < ConfigurationError; end
23
+
14
24
  ##
15
25
  # Errors that occur when making an API request. They
16
26
  # can occur either through local validation or
@@ -56,6 +66,18 @@ module Asimov
56
66
  ##
57
67
  class AuthorizationError < RequestError; end
58
68
 
69
+ ##
70
+ # Error that occurs because the provided API key is not
71
+ # valid.
72
+ ##
73
+ class InvalidApiKeyError < AuthorizationError; end
74
+
75
+ ##
76
+ # Error that occurs because the provided API key is not
77
+ # valid.
78
+ ##
79
+ class InvalidOrganizationError < AuthorizationError; end
80
+
59
81
  ##
60
82
  # Errors that occur because of issues with the
61
83
  # parameters of a request. Typically these correspond
@@ -87,26 +109,60 @@ module Asimov
87
109
  @system_message = system_message
88
110
  end
89
111
 
112
+ ##
113
+ # Returns the error message based on the file name and the wrapped error.
114
+ ##
90
115
  def message
91
116
  "The file #{@file_name} could not be opened for upload because of the " \
92
117
  "following error - #{@system_message}."
93
118
  end
94
119
  end
95
120
 
121
+ ##
122
+ # Error that occurs when a JSONL file is expected
123
+ # and it cannot be parsed.
124
+ ##
96
125
  class JsonlFileCannotBeParsedError < FileDataError; end
97
126
 
127
+ ##
128
+ # Error that occurs when an invalid training example
129
+ # is found in a training file.
130
+ ##
98
131
  class InvalidTrainingExampleError < FileDataError; end
99
132
 
133
+ ##
134
+ # Error that occurs when an invalid text entry
135
+ # is found in a text entry file.
136
+ ##
100
137
  class InvalidTextEntryError < FileDataError; end
101
138
 
139
+ ##
140
+ # Error that occurs when an invalid classification
141
+ # is found in a classifications file.
142
+ ##
102
143
  class InvalidClassificationError < FileDataError; end
103
144
 
145
+ ##
146
+ # Error that occurs when the provided chat messages
147
+ # parameter is not valid.
148
+ ##
149
+ class InvalidChatMessagesError < RequestError; end
150
+
151
+ ##
152
+ # Error that occurs when an invalid value is provided
153
+ # for an expected parameter in a request.
154
+ ##
104
155
  class InvalidParameterValueError < RequestError; end
105
156
 
157
+ ##
158
+ # Error that occurs when an unexpected parameter is
159
+ # provided in a request.
160
+ ##
106
161
  class UnsupportedParameterError < RequestError; end
107
162
 
108
163
  ##
109
- #
164
+ # Error raised when a required parameter is not included
165
+ # in the request.
110
166
  ##
111
167
  class MissingRequiredParameterError < RequestError
112
168
  def initialize(parameter_name)
@@ -114,6 +170,9 @@ module Asimov
114
170
  @parameter_name = parameter_name
115
171
  end
116
172
 
173
+ ##
174
+ # Returns the error message based on the missing parameter name.
175
+ ##
117
176
  def message
118
177
  "The parameter #{@parameter_name} is required."
119
178
  end
@@ -126,4 +185,39 @@ module Asimov
126
185
  # an object in the OpenAI system.
127
186
  ##
128
187
  class NotFoundError < RequestError; end
188
+
189
+ ##
190
+ # Errors that occur because the OpenAI API returned
191
+ # an HTTP code 429. This typically occurs because
192
+ # you have hit a rate limit or quota limit, or
193
+ # because the engine is overloaded.
194
+ ##
195
+ class TooManyRequestsError < RequestError; end
196
+
197
+ ##
198
+ # Error that occurs when the quota for an API key
199
+ # is exceeded.
200
+ ##
201
+ class QuotaExceededError < TooManyRequestsError; end
202
+
203
+ ##
204
+ # Error that occurs when the rate limit for requests
205
+ # is exceeded.
206
+ ##
207
+ class RateLimitError < TooManyRequestsError; end
208
+
209
+ ##
210
+ # Error that occurs when the API itself is
211
+ # overloaded and temporarily cannot accept additional
212
+ # requests.
213
+ ##
214
+ class ApiOverloadedError < TooManyRequestsError; end
215
+
216
+ ##
217
+ # Raised when a non-false stream parameter is passed
218
+ # to certain API methods. Processing of server-side
219
+ # events using the stream parameter is currently not
220
+ # supported.
221
+ ##
222
+ class StreamingResponseNotSupportedError < RequestError; end
129
223
  end
@@ -0,0 +1,63 @@
1
+ module Asimov
2
+ module Utils
3
+ ##
4
+ # Validator for OpenAI's chat message format
5
+ ##
6
+ class ChatMessagesValidator
7
+ def self.validate_and_normalize(messages)
8
+ new.validate(messages)
9
+ end
10
+
11
+ def validate(messages)
12
+ raise InvalidChatMessagesError, "Chat messages cannot be nil." if messages.nil?
13
+
14
+ unless messages.is_a?(Array)
15
+ raise InvalidChatMessagesError,
16
+ "Chat messages must be an array."
17
+ end
18
+
19
+ messages.map do |message|
20
+ validate_message(normalize_parsed(message))
21
+ end
22
+ rescue JSON::ParserError
23
+ raise InvalidChatMessagesError, "Chat messages must be valid JSON."
24
+ end
25
+
26
+ def validate_message(message)
27
+ raise InvalidChatMessagesError, "Chat messages must be hashes." unless message.is_a?(Hash)
28
+
29
+ validate_role(message["role"])
30
+
31
+ content = message["content"]
32
+ raise InvalidChatMessagesError, "Chat messages must have content." if content.nil?
33
+
34
+ validate_keys(message)
35
+ message
36
+ end
37
+
38
+ def validate_keys(json)
39
+ additional_keys = json.keys - %w[role content]
40
+ return if additional_keys.empty?
41
+
42
+ raise InvalidChatMessagesError,
43
+ "Chat messages must not have additional keys - #{additional_keys.join(', ')}."
44
+ end
45
+
46
+ ALLOWED_ROLES = %w[assistant system user].freeze
47
+ def validate_role(role)
48
+ raise InvalidChatMessagesError, "Chat messages must have a role." if role.nil?
49
+
50
+ return true if ALLOWED_ROLES.include?(role)
51
+
52
+ raise InvalidChatMessagesError,
53
+ "The value '#{role}' is not a valid role for a chat message."
54
+ end
55
+
56
+ def normalize_parsed(message)
57
+ return message if message.is_a?(String)
58
+
59
+ JSON.parse(message.respond_to?(:to_json) ? message.to_json : message)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,6 +1,9 @@
1
1
  require "json"
2
2
 
3
3
  module Asimov
4
+ ##
5
+ # Set of utilities, primarily intended for internal library use.
6
+ ##
4
7
  module Utils
5
8
  ##
6
9
  # Validates that a file is in the "classifications" format
@@ -8,8 +11,13 @@ module Asimov
8
11
  # "text" and "label" keys for each line that have string
9
12
  # values and an optional "metadata" key that can have
10
13
  # any value. No other keys are permitted.
14
+ #
15
+ # The only method that clients should call on instances
16
+ # of this class is `validate`
11
17
  ##
12
18
  class ClassificationsFileValidator < JsonlValidator
19
+ private
20
+
13
21
  def validate_line(line, idx)
14
22
  parsed = JSON.parse(line)
15
23
  validate_classification(parsed, idx)
@@ -8,11 +8,23 @@ module Asimov
8
8
  # Not intended for client use.
9
9
  ##
10
10
  class FileManager
11
- def self.open(filename)
12
- File.open(filename)
11
+ ##
12
+ # Returns the file corresponding to the file_or_path. If the argument is a
13
+ # file, then just returns the argument. Otherwise calls File.open with the
14
+ # argument. Raises an error if the file cannot be opened.
15
+ #
16
+ # @param [File/String] file_or_path the path to the file to be opened
17
+ ##
18
+ def self.open(file_or_path)
19
+ file?(file_or_path) ? file_or_path : File.open(file_or_path)
13
20
  rescue SystemCallError => e
14
- raise Asimov::FileCannotBeOpenedError.new(filename, e.message)
21
+ raise Asimov::FileCannotBeOpenedError.new(file_or_path, e.message)
15
22
  end
23
+
24
+ def self.file?(object)
25
+ object.respond_to?(:path) && object.respond_to?(:read)
26
+ end
27
+ private_class_method :file?
16
28
  end
17
29
  end
18
30
  end
@@ -7,13 +7,23 @@ module Asimov
7
7
  # more specific file validators.
8
8
  ##
9
9
  class JsonlValidator
10
- def validate(file)
11
- file.each_line.with_index { |line, idx| validate_line(line, idx) }
10
+ ##
11
+ # Validate that the IO object (typically a File) is properly
12
+ # formatted. Entry method for this class and its subclasses.
13
+ # Required format will depend on the class.
14
+ #
15
+ # @param [IO] io IO object, typically a file, whose contents
16
+ # are to be format checked.
17
+ ##
18
+ def validate(io)
19
+ io.each_line.with_index { |line, idx| validate_line(line, idx) }
12
20
  true
13
21
  rescue JSON::ParserError
14
22
  raise JsonlFileCannotBeParsedError, "Expected file to have the JSONL format."
15
23
  end
16
24
 
25
+ private
26
+
17
27
  def validate_line(line, idx)
18
28
  JSON.parse(line)
19
29
  rescue JSON::ParserError
@@ -14,6 +14,16 @@ module Asimov
14
14
  ALLOWED_OPTIONS = %i[timeout open_timeout read_timeout write_timeout local_host local_port
15
15
  verify verify_peer ssl_ca_file ssl_ca_path ssl_version ciphers
16
16
  http_proxyaddr http_proxyport http_proxyuser http_proxypass].freeze
17
+
18
+ ##
19
+ # Validates that the options are allowed request
20
+ # options. Currently checks the keys - both that they are symbols and that
21
+ # they are allowed options. Does not validate values.
22
+ #
23
+ # Only entry point for this class.
24
+ #
25
+ # @param [Hash] options the set of request options to validate
26
+ ##
17
27
  def self.validate(options)
18
28
  unless options.is_a?(Hash)
19
29
  raise Asimov::ConfigurationError,
@@ -32,6 +42,7 @@ module Asimov
32
42
  end
33
43
  unsupported_options
34
44
  end
45
+ private_class_method :generate_unsupported_options
35
46
 
36
47
  def self.check_unsupported_options(unsupported_options)
37
48
  return if unsupported_options.empty?
@@ -40,6 +51,7 @@ module Asimov
40
51
  raise Asimov::ConfigurationError,
41
52
  "The options #{quoted_keys.join(',')} are not supported."
42
53
  end
54
+ private_class_method :check_unsupported_options
43
55
 
44
56
  def self.supported_option?(key)
45
57
  ALLOWED_OPTIONS.include?(key)
@@ -51,6 +63,7 @@ module Asimov
51
63
  raise Asimov::ConfigurationError,
52
64
  "Request options keys must be symbols. The key '#{key}' is not a symbol."
53
65
  end
66
+ private_class_method :check_symbol
54
67
  end
55
68
  end
56
69
  end
@@ -10,6 +10,8 @@ module Asimov
10
10
  # any value. No other keys are permitted.
11
11
  ##
12
12
  class TextEntryFileValidator < JsonlValidator
13
+ private
14
+
13
15
  def validate_line(line, idx)
14
16
  parsed = JSON.parse(line)
15
17
  validate_text_entry(parsed, idx)
@@ -9,6 +9,8 @@ module Asimov
9
9
  # values. No other keys are permitted.
10
10
  ##
11
11
  class TrainingFileValidator < JsonlValidator
12
+ private
13
+
12
14
  def validate_line(line, idx)
13
15
  parsed = JSON.parse(line)
14
16
  validate_training_example(parsed, idx)
@@ -1,3 +1,4 @@
1
1
  module Asimov
2
- VERSION = "0.1.0".freeze
2
+ # Current gem version
3
+ VERSION = "1.1.0".freeze
3
4
  end
data/lib/asimov.rb CHANGED
@@ -4,7 +4,7 @@ require_relative "asimov/error"
4
4
  require_relative "asimov/client"
5
5
 
6
6
  ##
7
- # Client library for using the OpenAI API.
7
+ # Top level module for the Asimov client library for using the OpenAI API.
8
8
  ##
9
9
  module Asimov
10
10
  ##