asimov 0.1.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -1
- data/Gemfile +12 -1
- data/README.md +1 -0
- data/lib/asimov/api_v1/api_error_translator.rb +70 -28
- data/lib/asimov/api_v1/audio.rb +52 -0
- data/lib/asimov/api_v1/base.rb +71 -18
- data/lib/asimov/api_v1/chat.rb +29 -0
- data/lib/asimov/api_v1/completions.rb +11 -3
- data/lib/asimov/api_v1/edits.rb +11 -4
- data/lib/asimov/api_v1/embeddings.rb +15 -4
- data/lib/asimov/api_v1/files.rb +37 -12
- data/lib/asimov/api_v1/finetunes.rb +35 -9
- data/lib/asimov/api_v1/images.rb +37 -10
- data/lib/asimov/api_v1/models.rb +21 -4
- data/lib/asimov/api_v1/moderations.rb +10 -3
- data/lib/asimov/client.rb +35 -2
- data/lib/asimov/configuration.rb +22 -1
- data/lib/asimov/error.rb +95 -1
- data/lib/asimov/utils/chat_messages_validator.rb +63 -0
- data/lib/asimov/utils/classifications_file_validator.rb +8 -0
- data/lib/asimov/utils/file_manager.rb +15 -3
- data/lib/asimov/utils/jsonl_validator.rb +12 -2
- data/lib/asimov/utils/request_options_validator.rb +13 -0
- data/lib/asimov/utils/text_entry_file_validator.rb +2 -0
- data/lib/asimov/utils/training_file_validator.rb +2 -0
- data/lib/asimov/version.rb +2 -1
- data/lib/asimov.rb +1 -1
- metadata +10 -103
@@ -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
|
-
|
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
|
-
|
14
|
+
rest_index(resource: RESOURCE)
|
11
15
|
end
|
12
16
|
|
13
|
-
|
14
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
45
|
+
rest_create_w_multipart_params(resource: [RESOURCE, fine_tune_id, "cancel"])
|
25
46
|
end
|
26
47
|
|
27
|
-
|
28
|
-
|
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
|
data/lib/asimov/api_v1/images.rb
CHANGED
@@ -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
|
-
|
9
|
+
RESOURCE = "images".freeze
|
10
|
+
private_constant :RESOURCE
|
10
11
|
|
11
|
-
|
12
|
-
|
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
|
-
|
21
|
+
rest_create_w_json_params(resource: [RESOURCE, "generations"],
|
22
|
+
parameters: parameters.merge({ prompt: prompt }))
|
15
23
|
end
|
16
24
|
|
17
|
-
|
18
|
-
|
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
|
-
|
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
|
-
|
24
|
-
|
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
|
60
|
+
parameters[:mask] = Utils::FileManager.open(parameters[:mask]) if parameters[:mask]
|
34
61
|
parameters
|
35
62
|
end
|
36
63
|
end
|
data/lib/asimov/api_v1/models.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
8
|
-
|
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
|
-
|
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
|
data/lib/asimov/configuration.rb
CHANGED
@@ -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
|
-
|
12
|
-
|
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(
|
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
|
-
|
11
|
-
|
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
|
data/lib/asimov/version.rb
CHANGED