ibm_watson 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +258 -0
  3. data/bin/console +14 -0
  4. data/bin/setup +8 -0
  5. data/lib/ibm_watson.rb +16 -0
  6. data/lib/ibm_watson/assistant_v1.rb +1997 -0
  7. data/lib/ibm_watson/detailed_response.rb +21 -0
  8. data/lib/ibm_watson/discovery_v1.rb +2039 -0
  9. data/lib/ibm_watson/iam_token_manager.rb +166 -0
  10. data/lib/ibm_watson/language_translator_v3.rb +411 -0
  11. data/lib/ibm_watson/natural_language_classifier_v1.rb +309 -0
  12. data/lib/ibm_watson/natural_language_understanding_v1.rb +297 -0
  13. data/lib/ibm_watson/personality_insights_v3.rb +260 -0
  14. data/lib/ibm_watson/speech_to_text_v1.rb +2153 -0
  15. data/lib/ibm_watson/text_to_speech_v1.rb +716 -0
  16. data/lib/ibm_watson/tone_analyzer_v3.rb +287 -0
  17. data/lib/ibm_watson/version.rb +3 -0
  18. data/lib/ibm_watson/visual_recognition_v3.rb +579 -0
  19. data/lib/ibm_watson/watson_api_exception.rb +41 -0
  20. data/lib/ibm_watson/watson_service.rb +180 -0
  21. data/lib/ibm_watson/websocket/recognize_callback.rb +32 -0
  22. data/lib/ibm_watson/websocket/speech_to_text_websocket_listener.rb +162 -0
  23. data/rakefile +45 -0
  24. data/test/integration/test_assistant_v1.rb +645 -0
  25. data/test/integration/test_discovery_v1.rb +200 -0
  26. data/test/integration/test_iam_assistant_v1.rb +707 -0
  27. data/test/integration/test_language_translator_v3.rb +81 -0
  28. data/test/integration/test_natural_language_classifier_v1.rb +69 -0
  29. data/test/integration/test_natural_language_understanding_v1.rb +98 -0
  30. data/test/integration/test_personality_insights_v3.rb +95 -0
  31. data/test/integration/test_speech_to_text_v1.rb +187 -0
  32. data/test/integration/test_text_to_speech_v1.rb +81 -0
  33. data/test/integration/test_tone_analyzer_v3.rb +72 -0
  34. data/test/integration/test_visual_recognition_v3.rb +64 -0
  35. data/test/test_helper.rb +22 -0
  36. data/test/unit/test_assistant_v1.rb +1598 -0
  37. data/test/unit/test_discovery_v1.rb +1144 -0
  38. data/test/unit/test_iam_token_manager.rb +165 -0
  39. data/test/unit/test_language_translator_v3.rb +461 -0
  40. data/test/unit/test_natural_language_classifier_v1.rb +187 -0
  41. data/test/unit/test_natural_language_understanding_v1.rb +132 -0
  42. data/test/unit/test_personality_insights_v3.rb +172 -0
  43. data/test/unit/test_speech_to_text_v1.rb +755 -0
  44. data/test/unit/test_text_to_speech_v1.rb +336 -0
  45. data/test/unit/test_tone_analyzer_v3.rb +200 -0
  46. data/test/unit/test_vcap_using_personality_insights.rb +150 -0
  47. data/test/unit/test_visual_recognition_v3.rb +345 -0
  48. metadata +302 -0
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require("http")
4
+ require("json")
5
+ require("rbconfig")
6
+ require_relative("./version.rb")
7
+
8
+ DEFAULT_IAM_URL = "https://iam.bluemix.net/identity/token".freeze
9
+ CONTENT_TYPE = "application/x-www-form-urlencoded".freeze
10
+ ACCEPT = "application/json".freeze
11
+ DEFAULT_AUTHORIZATION = "Basic Yng6Yng=".freeze
12
+ REQUEST_TOKEN_GRANT_TYPE = "urn:ibm:params:oauth:grant-type:apikey".freeze
13
+ REQUEST_TOKEN_RESPONSE_TYPE = "cloud_iam".freeze
14
+ REFRESH_TOKEN_GRANT_TYPE = "refresh_token".freeze
15
+
16
+ # Class to manage IAM Token Authentication
17
+ class IAMTokenManager
18
+ attr_accessor :token_info, :user_access_token
19
+ def initialize(iam_api_key: nil, iam_access_token: nil, iam_url: nil)
20
+ @iam_api_key = iam_api_key
21
+ @user_access_token = iam_access_token
22
+ @iam_url = iam_url.nil? ? DEFAULT_IAM_URL : iam_url
23
+ @token_info = {
24
+ "access_token" => nil,
25
+ "refresh_token" => nil,
26
+ "token_type" => nil,
27
+ "expires_in" => nil,
28
+ "expiration" => nil
29
+ }
30
+ end
31
+
32
+ def request(method:, url:, headers: nil, params: nil, data: nil)
33
+ user_agent_string = "watson-apis-ruby-sdk-" + IBMWatson::VERSION
34
+ user_agent_string += " #{RbConfig::CONFIG["host"]}"
35
+ user_agent_string += " #{RbConfig::CONFIG["RUBY_BASE_NAME"]}-#{RbConfig::CONFIG["RUBY_PROGRAM_VERSION"]}"
36
+ headers["User-Agent"] = user_agent_string
37
+ response = nil
38
+ if headers.key?("Content-Type") && headers["Content-Type"] == CONTENT_TYPE
39
+ response = HTTP.request(
40
+ method,
41
+ url,
42
+ body: HTTP::URI.form_encode(data),
43
+ headers: headers,
44
+ params: params
45
+ )
46
+ else
47
+ data = data.to_json if data.respond_to?(:to_json)
48
+ response = HTTP.request(
49
+ method,
50
+ url,
51
+ headers: headers,
52
+ body: data,
53
+ params: params
54
+ )
55
+ end
56
+ return JSON.parse(response.body.to_s) if (200..299).cover?(response.code)
57
+ require_relative("./watson_api_exception.rb")
58
+ raise WatsonApiException.new(response: response)
59
+ end
60
+
61
+ # The source of the token is determined by the following logic:
62
+ # 1. If user provides their own managed access token, assume it is valid and send it
63
+ # 2. If this class is managing tokens and does not yet have one, make a request for one
64
+ # 3. If this class is managing tokens and the token has expired refresh it. In case the refresh token is expired, get a new one
65
+ # If this class is managing tokens and has a valid token stored, send it
66
+ def _token
67
+ return @user_access_token unless @user_access_token.nil? || (@user_access_token.respond_to?(:empty?) && @user_access_token.empty?)
68
+ if @token_info.all? { |_k, v| v.nil? }
69
+ token_info = _request_token
70
+ _save_token_info(
71
+ token_info: token_info
72
+ )
73
+ return @token_info["access_token"]
74
+ elsif _is_token_expired?
75
+ token_info = _is_refresh_token_expired? ? _request_token : _refresh_token
76
+ _save_token_info(
77
+ token_info: token_info
78
+ )
79
+ return @token_info["access_token"]
80
+ else
81
+ @token_info["access_token"]
82
+ end
83
+ end
84
+
85
+ # Request an IAM token using an API key
86
+ def _request_token
87
+ headers = {
88
+ "Content-Type" => CONTENT_TYPE,
89
+ "Authorization" => DEFAULT_AUTHORIZATION,
90
+ "Accept" => ACCEPT
91
+ }
92
+ data = {
93
+ "grant_type" => REQUEST_TOKEN_GRANT_TYPE,
94
+ "apikey" => @iam_api_key,
95
+ "response_type" => REQUEST_TOKEN_RESPONSE_TYPE
96
+ }
97
+ response = request(
98
+ method: "POST",
99
+ url: @iam_url,
100
+ headers: headers,
101
+ data: data
102
+ )
103
+ response
104
+ end
105
+
106
+ # Refresh an IAM token using a refresh token
107
+ def _refresh_token
108
+ headers = {
109
+ "Content-Type" => CONTENT_TYPE,
110
+ "Authorization" => DEFAULT_AUTHORIZATION,
111
+ "accept" => ACCEPT
112
+ }
113
+ data = {
114
+ "grant_type" => REFRESH_TOKEN_GRANT_TYPE,
115
+ "refresh_token" => @token_info["refresh_token"]
116
+ }
117
+ response = request(
118
+ method: "POST",
119
+ url: @iam_url,
120
+ headers: headers,
121
+ data: data
122
+ )
123
+ response
124
+ end
125
+
126
+ # Set a self-managed IAM access token.
127
+ # The access token should be valid and not yet expired.
128
+ def _access_token(iam_access_token:)
129
+ @user_access_token = iam_access_token
130
+ end
131
+
132
+ # Set the IAM api key
133
+ def _iam_api_key(iam_api_key:)
134
+ @iam_api_key = iam_api_key
135
+ end
136
+
137
+ # Check if currently stored token is expired.
138
+ # Using a buffer to prevent the edge case of the
139
+ # token expiring before the request could be made.
140
+ # The buffer will be a fraction of the total TTL. Using 80%.
141
+ def _is_token_expired?
142
+ return true if @token_info["expiration"].nil? || @token_info["expires_in"].nil?
143
+ fraction_of_ttl = 0.8
144
+ time_to_live = @token_info["expires_in"].nil? ? 0 : @token_info["expires_in"]
145
+ expire_time = @token_info["expiration"].nil? ? 0 : @token_info["expiration"]
146
+ refresh_time = expire_time - (time_to_live * (1.0 - fraction_of_ttl))
147
+ current_time = Time.now.to_i
148
+ refresh_time < current_time
149
+ end
150
+
151
+ # Used as a fail-safe to prevent the condition of a refresh token expiring,
152
+ # which could happen after around 30 days. This function will return true
153
+ # if it has been at least 7 days and 1 hour since the last token was set
154
+ def _is_refresh_token_expired?
155
+ return true if @token_info["expiration"].nil?
156
+ seven_days = 7 * 24 * 3600
157
+ current_time = Time.now.to_i
158
+ new_token_time = @token_info["expiration"] + seven_days
159
+ new_token_time < current_time
160
+ end
161
+
162
+ # Save the response from the IAM service request to the object's state
163
+ def _save_token_info(token_info:)
164
+ @token_info = token_info
165
+ end
166
+ end
@@ -0,0 +1,411 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2018 IBM All Rights Reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # IBM Watson&trade; Language Translator translates text from one language to another.
18
+ # The service offers multiple IBM provided translation models that you can customize based
19
+ # on your unique terminology and language. Use Language Translator to take news from
20
+ # across the globe and present it in your language, communicate with your customers in
21
+ # their own language, and more.
22
+
23
+ require "concurrent"
24
+ require "erb"
25
+ require "json"
26
+ require_relative "./detailed_response"
27
+
28
+ require_relative "./watson_service"
29
+
30
+ module IBMWatson
31
+ ##
32
+ # The Language Translator V3 service.
33
+ class LanguageTranslatorV3
34
+ include Concurrent::Async
35
+ ##
36
+ # @!method initialize(args)
37
+ # Construct a new client for the Language Translator service.
38
+ #
39
+ # @param args [Hash] The args to initialize with
40
+ # @option args version [String] The API version date to use with the service, in
41
+ # "YYYY-MM-DD" format. Whenever the API is changed in a backwards
42
+ # incompatible way, a new minor version of the API is released.
43
+ # The service uses the API version for the date you specify, or
44
+ # the most recent version before that date. Note that you should
45
+ # not programmatically specify the current date at runtime, in
46
+ # case the API has been updated since your application's release.
47
+ # Instead, specify a version date that is compatible with your
48
+ # application, and don't change it until your application is
49
+ # ready for a later version.
50
+ # @option args url [String] The base url to use when contacting the service (e.g.
51
+ # "https://gateway.watsonplatform.net/language-translator/api").
52
+ # The base url may differ between Bluemix regions.
53
+ # @option args username [String] The username used to authenticate with the service.
54
+ # Username and password credentials are only required to run your
55
+ # application locally or outside of Bluemix. When running on
56
+ # Bluemix, the credentials will be automatically loaded from the
57
+ # `VCAP_SERVICES` environment variable.
58
+ # @option args password [String] The password used to authenticate with the service.
59
+ # Username and password credentials are only required to run your
60
+ # application locally or outside of Bluemix. When running on
61
+ # Bluemix, the credentials will be automatically loaded from the
62
+ # `VCAP_SERVICES` environment variable.
63
+ # @option args iam_api_key [String] An API key that can be used to request IAM tokens. If
64
+ # this API key is provided, the SDK will manage the token and handle the
65
+ # refreshing.
66
+ # @option args iam_access_token [String] An IAM access token is fully managed by the application.
67
+ # Responsibility falls on the application to refresh the token, either before
68
+ # it expires or reactively upon receiving a 401 from the service as any requests
69
+ # made with an expired token will fail.
70
+ # @option args iam_url [String] An optional URL for the IAM service API. Defaults to
71
+ # 'https://iam.ng.bluemix.net/identity/token'.
72
+ def initialize(args = {})
73
+ @__async_initialized__ = false
74
+ super()
75
+ defaults = {}
76
+ defaults[:version] = nil
77
+ defaults[:url] = "https://gateway.watsonplatform.net/language-translator/api"
78
+ defaults[:username] = nil
79
+ defaults[:password] = nil
80
+ defaults[:iam_api_key] = nil
81
+ defaults[:iam_access_token] = nil
82
+ defaults[:iam_url] = nil
83
+ args = defaults.merge(args)
84
+ @watson_service = WatsonService.new(
85
+ vcap_services_name: "language_translator",
86
+ url: args[:url],
87
+ username: args[:username],
88
+ password: args[:password],
89
+ iam_api_key: args[:iam_api_key],
90
+ iam_access_token: args[:iam_access_token],
91
+ iam_url: args[:iam_url],
92
+ use_vcap_services: true
93
+ )
94
+ @version = args[:version]
95
+ end
96
+
97
+ # :nocov:
98
+ def add_default_headers(headers: {})
99
+ @watson_service.add_default_headers(headers: headers)
100
+ end
101
+
102
+ def _iam_access_token(iam_access_token:)
103
+ @watson_service._iam_access_token(iam_access_token: iam_access_token)
104
+ end
105
+
106
+ def _iam_api_key(iam_api_key:)
107
+ @watson_service._iam_api_key(iam_api_key: iam_api_key)
108
+ end
109
+
110
+ # @return [DetailedResponse]
111
+ def request(args)
112
+ @watson_service.request(args)
113
+ end
114
+
115
+ # @note Chainable
116
+ # @param headers [Hash] Custom headers to be sent with the request
117
+ # @return [self]
118
+ def headers(headers)
119
+ @watson_service.headers(headers)
120
+ self
121
+ end
122
+
123
+ def password=(password)
124
+ @watson_service.password = password
125
+ end
126
+
127
+ def password
128
+ @watson_service.password
129
+ end
130
+
131
+ def username=(username)
132
+ @watson_service.username = username
133
+ end
134
+
135
+ def username
136
+ @watson_service.username
137
+ end
138
+
139
+ def url=(url)
140
+ @watson_service.url = url
141
+ end
142
+
143
+ def url
144
+ @watson_service.url
145
+ end
146
+ # :nocov:
147
+ #########################
148
+ # Translation
149
+ #########################
150
+
151
+ ##
152
+ # @!method translate(text:, model_id: nil, source: nil, target: nil)
153
+ # Translate.
154
+ # Translates the input text from the source language to the target language.
155
+ # @param text [Array[String]] Input text in UTF-8 encoding. Multiple entries will result in multiple
156
+ # translations in the response.
157
+ # @param model_id [String] Model ID of the translation model to use. If this is specified, the **source** and
158
+ # **target** parameters will be ignored. The method requires either a model ID or
159
+ # both the **source** and **target** parameters.
160
+ # @param source [String] Language code of the source text language. Use with `target` as an alternative way
161
+ # to select a translation model. When `source` and `target` are set, and a model ID
162
+ # is not set, the system chooses a default model for the language pair (usually the
163
+ # model based on the news domain).
164
+ # @param target [String] Language code of the translation target language. Use with source as an
165
+ # alternative way to select a translation model.
166
+ # @return [DetailedResponse] A `DetailedResponse` object representing the response.
167
+ def translate(text:, model_id: nil, source: nil, target: nil)
168
+ raise ArgumentError("text must be provided") if text.nil?
169
+ headers = {
170
+ }
171
+ params = {
172
+ "version" => @version
173
+ }
174
+ data = {
175
+ "text" => text,
176
+ "model_id" => model_id,
177
+ "source" => source,
178
+ "target" => target
179
+ }
180
+ method_url = "/v3/translate"
181
+ response = request(
182
+ method: "POST",
183
+ url: method_url,
184
+ headers: headers,
185
+ params: params,
186
+ json: data,
187
+ accept_json: true
188
+ )
189
+ response
190
+ end
191
+ #########################
192
+ # Identification
193
+ #########################
194
+
195
+ ##
196
+ # @!method list_identifiable_languages
197
+ # List identifiable languages.
198
+ # Lists the languages that the service can identify. Returns the language code (for
199
+ # example, `en` for English or `es` for Spanish) and name of each language.
200
+ # @return [DetailedResponse] A `DetailedResponse` object representing the response.
201
+ def list_identifiable_languages
202
+ headers = {
203
+ }
204
+ params = {
205
+ "version" => @version
206
+ }
207
+ method_url = "/v3/identifiable_languages"
208
+ response = request(
209
+ method: "GET",
210
+ url: method_url,
211
+ headers: headers,
212
+ params: params,
213
+ accept_json: true
214
+ )
215
+ response
216
+ end
217
+
218
+ ##
219
+ # @!method identify(text:)
220
+ # Identify language.
221
+ # Identifies the language of the input text.
222
+ # @param text [String] Input text in UTF-8 format.
223
+ # @return [DetailedResponse] A `DetailedResponse` object representing the response.
224
+ def identify(text:)
225
+ raise ArgumentError("text must be provided") if text.nil?
226
+ headers = {
227
+ }
228
+ params = {
229
+ "version" => @version
230
+ }
231
+ data = text
232
+ headers["Content-Type"] = "text/plain"
233
+ method_url = "/v3/identify"
234
+ response = request(
235
+ method: "POST",
236
+ url: method_url,
237
+ headers: headers,
238
+ params: params,
239
+ data: data,
240
+ accept_json: true
241
+ )
242
+ response
243
+ end
244
+ #########################
245
+ # Models
246
+ #########################
247
+
248
+ ##
249
+ # @!method list_models(source: nil, target: nil, default_models: nil)
250
+ # List models.
251
+ # Lists available translation models.
252
+ # @param source [String] Specify a language code to filter results by source language.
253
+ # @param target [String] Specify a language code to filter results by target language.
254
+ # @param default_models [Boolean] If the default parameter isn't specified, the service will return all models
255
+ # (default and non-default) for each language pair. To return only default models,
256
+ # set this to `true`. To return only non-default models, set this to `false`. There
257
+ # is exactly one default model per language pair, the IBM provided base model.
258
+ # @return [DetailedResponse] A `DetailedResponse` object representing the response.
259
+ def list_models(source: nil, target: nil, default_models: nil)
260
+ headers = {
261
+ }
262
+ params = {
263
+ "version" => @version,
264
+ "source" => source,
265
+ "target" => target,
266
+ "default" => default_models
267
+ }
268
+ method_url = "/v3/models"
269
+ response = request(
270
+ method: "GET",
271
+ url: method_url,
272
+ headers: headers,
273
+ params: params,
274
+ accept_json: true
275
+ )
276
+ response
277
+ end
278
+
279
+ ##
280
+ # @!method create_model(base_model_id:, name: nil, forced_glossary: nil, parallel_corpus: nil, forced_glossary_filename: nil, parallel_corpus_filename: nil)
281
+ # Create model.
282
+ # Uploads Translation Memory eXchange (TMX) files to customize a translation model.
283
+ #
284
+ # You can either customize a model with a forced glossary or with a corpus that
285
+ # contains parallel sentences. To create a model that is customized with a parallel
286
+ # corpus <b>and</b> a forced glossary, proceed in two steps: customize with a
287
+ # parallel corpus first and then customize the resulting model with a glossary.
288
+ # Depending on the type of customization and the size of the uploaded corpora,
289
+ # training can range from minutes for a glossary to several hours for a large
290
+ # parallel corpus. You can upload a single forced glossary file and this file must
291
+ # be less than <b>10 MB</b>. You can upload multiple parallel corpora tmx files. The
292
+ # cumulative file size of all uploaded files is limited to <b>250 MB</b>. To
293
+ # successfully train with a parallel corpus you must have at least <b>5,000 parallel
294
+ # sentences</b> in your corpus.
295
+ #
296
+ # You can have a <b>maxium of 10 custom models per language pair</b>.
297
+ # @param base_model_id [String] The model ID of the model to use as the base for customization. To see available
298
+ # models, use the `List models` method. Usually all IBM provided models are
299
+ # customizable. In addition, all your models that have been created via parallel
300
+ # corpus customization, can be further customized with a forced glossary.
301
+ # @param name [String] An optional model name that you can use to identify the model. Valid characters
302
+ # are letters, numbers, dashes, underscores, spaces and apostrophes. The maximum
303
+ # length is 32 characters.
304
+ # @param forced_glossary [File] A TMX file with your customizations. The customizations in the file completely
305
+ # overwrite the domain translaton data, including high frequency or high confidence
306
+ # phrase translations. You can upload only one glossary with a file size less than
307
+ # 10 MB per call. A forced glossary should contain single words or short phrases.
308
+ # @param parallel_corpus [File] A TMX file with parallel sentences for source and target language. You can upload
309
+ # multiple parallel_corpus files in one request. All uploaded parallel_corpus files
310
+ # combined, your parallel corpus must contain at least 5,000 parallel sentences to
311
+ # train successfully.
312
+ # @param forced_glossary_filename [String] The filename for forced_glossary.
313
+ # @param parallel_corpus_filename [String] The filename for parallel_corpus.
314
+ # @return [DetailedResponse] A `DetailedResponse` object representing the response.
315
+ def create_model(base_model_id:, name: nil, forced_glossary: nil, parallel_corpus: nil, forced_glossary_filename: nil, parallel_corpus_filename: nil)
316
+ raise ArgumentError("base_model_id must be provided") if base_model_id.nil?
317
+ headers = {
318
+ }
319
+ params = {
320
+ "version" => @version,
321
+ "base_model_id" => base_model_id,
322
+ "name" => name
323
+ }
324
+ unless forced_glossary.nil?
325
+ mime_type = "application/octet-stream"
326
+ unless forced_glossary.instance_of?(StringIO) || forced_glossary.instance_of?(File)
327
+ forced_glossary = forced_glossary.respond_to?(:to_json) ? StringIO.new(forced_glossary.to_json) : StringIO.new(forced_glossary)
328
+ end
329
+ if forced_glossary_filename
330
+ forced_glossary = forced_glossary.instance_of?(StringIO) ? HTTP::FormData::File.new(forced_glossary, content_type: mime_type, filename: forced_glossary_filename) : HTTP::FormData::File.new(forced_glossary.path, content_type: mime_type, filename: forced_glossary_filename)
331
+ else
332
+ forced_glossary = forced_glossary.instance_of?(StringIO) ? HTTP::FormData::File.new(forced_glossary, content_type: mime_type) : HTTP::FormData::File.new(forced_glossary.path, content_type: mime_type)
333
+ end
334
+ end
335
+ unless parallel_corpus.nil?
336
+ mime_type = "application/octet-stream"
337
+ unless parallel_corpus.instance_of?(StringIO) || parallel_corpus.instance_of?(File)
338
+ parallel_corpus = parallel_corpus.respond_to?(:to_json) ? StringIO.new(parallel_corpus.to_json) : StringIO.new(parallel_corpus)
339
+ end
340
+ if parallel_corpus_filename
341
+ parallel_corpus = parallel_corpus.instance_of?(StringIO) ? HTTP::FormData::File.new(parallel_corpus, content_type: mime_type, filename: parallel_corpus_filename) : HTTP::FormData::File.new(parallel_corpus.path, content_type: mime_type, filename: parallel_corpus_filename)
342
+ else
343
+ parallel_corpus = parallel_corpus.instance_of?(StringIO) ? HTTP::FormData::File.new(parallel_corpus, content_type: mime_type) : HTTP::FormData::File.new(parallel_corpus.path, content_type: mime_type)
344
+ end
345
+ end
346
+ method_url = "/v3/models"
347
+ response = request(
348
+ method: "POST",
349
+ url: method_url,
350
+ headers: headers,
351
+ params: params,
352
+ form: {
353
+ forced_glossary: forced_glossary,
354
+ parallel_corpus: parallel_corpus
355
+ },
356
+ accept_json: true
357
+ )
358
+ response
359
+ end
360
+
361
+ ##
362
+ # @!method delete_model(model_id:)
363
+ # Delete model.
364
+ # Deletes a custom translation model.
365
+ # @param model_id [String] Model ID of the model to delete.
366
+ # @return [DetailedResponse] A `DetailedResponse` object representing the response.
367
+ def delete_model(model_id:)
368
+ raise ArgumentError("model_id must be provided") if model_id.nil?
369
+ headers = {
370
+ }
371
+ params = {
372
+ "version" => @version
373
+ }
374
+ method_url = "/v3/models/%s" % [ERB::Util.url_encode(model_id)]
375
+ response = request(
376
+ method: "DELETE",
377
+ url: method_url,
378
+ headers: headers,
379
+ params: params,
380
+ accept_json: true
381
+ )
382
+ response
383
+ end
384
+
385
+ ##
386
+ # @!method get_model(model_id:)
387
+ # Get model details.
388
+ # Gets information about a translation model, including training status for custom
389
+ # models. Use this API call to poll the status of your customization request. A
390
+ # successfully completed training will have a status of `available`.
391
+ # @param model_id [String] Model ID of the model to get.
392
+ # @return [DetailedResponse] A `DetailedResponse` object representing the response.
393
+ def get_model(model_id:)
394
+ raise ArgumentError("model_id must be provided") if model_id.nil?
395
+ headers = {
396
+ }
397
+ params = {
398
+ "version" => @version
399
+ }
400
+ method_url = "/v3/models/%s" % [ERB::Util.url_encode(model_id)]
401
+ response = request(
402
+ method: "GET",
403
+ url: method_url,
404
+ headers: headers,
405
+ params: params,
406
+ accept_json: true
407
+ )
408
+ response
409
+ end
410
+ end
411
+ end