mindee 3.5.0 → 3.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +39 -4
  4. data/bin/mindee.rb +6 -0
  5. data/docs/bank_account_details_v2.md +1 -1
  6. data/docs/bank_check_v1.md +1 -1
  7. data/docs/bank_statement_fr_v1.md +1 -1
  8. data/docs/barcode_reader_v1.md +1 -1
  9. data/docs/carte_grise_v1.md +1 -1
  10. data/docs/carte_vitale_v1.md +1 -1
  11. data/docs/code_samples/resume_v1_async.txt +19 -0
  12. data/docs/cropper_v1.md +1 -1
  13. data/docs/custom_v1.md +1 -1
  14. data/docs/eu_driver_license_v1.md +5 -5
  15. data/docs/expense_receipts_v5.md +1 -1
  16. data/docs/financial_document_v1.md +1 -1
  17. data/docs/generated_v1.md +1 -1
  18. data/docs/getting_started.md +1 -1
  19. data/docs/idcard_fr_v2.md +1 -1
  20. data/docs/international_id_v2.md +226 -0
  21. data/docs/invoice_splitter_v1.md +1 -1
  22. data/docs/invoices_v4.md +1 -1
  23. data/docs/license_plates_v1.md +1 -1
  24. data/docs/multi_receipts_detector_v1.md +1 -1
  25. data/docs/passport_v1.md +1 -1
  26. data/docs/proof_of_address_v1.md +1 -1
  27. data/docs/resume_v1.md +334 -0
  28. data/docs/us_driver_license_v1.md +1 -1
  29. data/docs/us_w9_v1.md +1 -1
  30. data/lib/mindee/http/endpoint.rb +24 -17
  31. data/lib/mindee/http/error.rb +11 -4
  32. data/lib/mindee/http/response_validation.rb +56 -0
  33. data/lib/mindee/parsing/common/api_response.rb +6 -1
  34. data/lib/mindee/parsing/standard/base_field.rb +1 -1
  35. data/lib/mindee/product/.rubocop.yml +7 -2
  36. data/lib/mindee/product/eu/driver_license/driver_license_v1.rb +2 -2
  37. data/lib/mindee/product/eu/driver_license/driver_license_v1_document.rb +1 -1
  38. data/lib/mindee/product/eu/driver_license/driver_license_v1_page.rb +2 -2
  39. data/lib/mindee/product/fr/carte_grise/carte_grise_v1_document.rb +0 -2
  40. data/lib/mindee/product/resume/resume_v1.rb +39 -0
  41. data/lib/mindee/product/resume/resume_v1_certificate.rb +69 -0
  42. data/lib/mindee/product/resume/resume_v1_document.rb +322 -0
  43. data/lib/mindee/product/resume/resume_v1_education.rb +90 -0
  44. data/lib/mindee/product/resume/resume_v1_language.rb +55 -0
  45. data/lib/mindee/product/resume/resume_v1_page.rb +32 -0
  46. data/lib/mindee/product/resume/resume_v1_professional_experience.rb +97 -0
  47. data/lib/mindee/product/resume/resume_v1_social_networks_url.rb +55 -0
  48. data/lib/mindee/product.rb +1 -0
  49. data/lib/mindee/version.rb +1 -1
  50. metadata +14 -2
data/docs/resume_v1.md ADDED
@@ -0,0 +1,334 @@
1
+ ---
2
+ title: Resume OCR Ruby
3
+ ---
4
+ The Ruby OCR SDK supports the [Resume API](https://platform.mindee.com/mindee/resume).
5
+
6
+ Using the [sample below](https://github.com/mindee/client-lib-test-data/blob/main/products/resume/default_sample.jpg), we are going to illustrate how to extract the data that we want using the OCR SDK.
7
+ ![Resume sample](https://github.com/mindee/client-lib-test-data/blob/main/products/resume/default_sample.jpg?raw=true)
8
+
9
+ # Quick-Start
10
+ ```rb
11
+ require 'mindee'
12
+
13
+ # Init a new client
14
+ mindee_client = Mindee::Client.new(api_key: 'my-api-key')
15
+
16
+ # Load a file from disk
17
+ input_source = mindee_client.source_from_path('/path/to/the/file.ext')
18
+
19
+ # Parse the file
20
+ result = mindee_client.enqueue_and_parse(
21
+ input_source,
22
+ Mindee::Product::Resume::ResumeV1
23
+ )
24
+
25
+ # Print a full summary of the parsed data in RST format
26
+ puts result.document
27
+
28
+ # Print the document-level parsed data
29
+ # puts result.document.inference.prediction
30
+ ```
31
+
32
+ **Output (RST):**
33
+ ```rst
34
+ ########
35
+ Document
36
+ ########
37
+ :Mindee ID: bc80bae0-af75-4464-95a9-2419403c75bf
38
+ :Filename: default_sample.jpg
39
+
40
+ Inference
41
+ #########
42
+ :Product: mindee/resume v1.0
43
+ :Rotation applied: No
44
+
45
+ Prediction
46
+ ==========
47
+ :Document Language: ENG
48
+ :Document Type: RESUME
49
+ :Given Names: Christopher
50
+ :Surnames: Morgan
51
+ :Nationality:
52
+ :Email Address: christoper.m@gmail.com
53
+ :Phone Number: +44 (0) 20 7666 8555
54
+ :Address: 177 Great Portland Street, London W5W 6PQ
55
+ :Social Networks:
56
+ +----------------------+----------------------------------------------------+
57
+ | Name | URL |
58
+ +======================+====================================================+
59
+ | LinkedIn | linkedin.com/christopher.morgan |
60
+ +----------------------+----------------------------------------------------+
61
+ :Profession: Senior Web Developer
62
+ :Job Applied:
63
+ :Languages:
64
+ +----------+----------------------+
65
+ | Language | Level |
66
+ +==========+======================+
67
+ | SPA | Fluent |
68
+ +----------+----------------------+
69
+ | ZHO | Beginner |
70
+ +----------+----------------------+
71
+ | DEU | Intermediate |
72
+ +----------+----------------------+
73
+ :Hard Skills: HTML5
74
+ PHP OOP
75
+ JavaScript
76
+ CSS
77
+ MySQL
78
+ :Soft Skills: Project management
79
+ Strong decision maker
80
+ Innovative
81
+ Complex problem solver
82
+ Creative design
83
+ Service-focused
84
+ :Education:
85
+ +-----------------+---------------------------+-----------+----------+---------------------------+-------------+------------+
86
+ | Domain | Degree | End Month | End Year | School | Start Month | Start Year |
87
+ +=================+===========================+===========+==========+===========================+=============+============+
88
+ | Computer Inf... | Bachelor | | | Columbia University, NY | | 2014 |
89
+ +-----------------+---------------------------+-----------+----------+---------------------------+-------------+------------+
90
+ :Professional Experiences:
91
+ +-----------------+------------+---------------------------+-----------+----------+----------------------+-------------+------------+
92
+ | Contract Type | Department | Employer | End Month | End Year | Role | Start Month | Start Year |
93
+ +=================+============+===========================+===========+==========+======================+=============+============+
94
+ | Full-Time | | Luna Web Design, New York | 05 | 2019 | Web Developer | 09 | 2015 |
95
+ +-----------------+------------+---------------------------+-----------+----------+----------------------+-------------+------------+
96
+ :Certificates:
97
+ +------------+--------------------------------+---------------------------+------+
98
+ | Grade | Name | Provider | Year |
99
+ +============+================================+===========================+======+
100
+ | | PHP Framework (certificate)... | | 2014 |
101
+ +------------+--------------------------------+---------------------------+------+
102
+ | | Programming Languages: Java... | | |
103
+ +------------+--------------------------------+---------------------------+------+
104
+ ```
105
+
106
+ # Field Types
107
+ ## Standard Fields
108
+ These fields are generic and used in several products.
109
+
110
+ ### Basic Field
111
+ Each prediction object contains a set of fields that inherit from the generic `Field` class.
112
+ A typical `Field` object will have the following attributes:
113
+
114
+ * **value** (`String`, `Float`, `Integer`, `Boolean`): corresponds to the field value. Can be `nil` if no value was extracted.
115
+ * **confidence** (Float, nil): the confidence score of the field prediction.
116
+ * **bounding_box** (`Mindee::Geometry::Quadrilateral`, `nil`): contains exactly 4 relative vertices (points) coordinates of a right rectangle containing the field in the document.
117
+ * **polygon** (`Mindee::Geometry::Polygon`, `nil`): contains the relative vertices coordinates (`Point`) of a polygon containing the field in the image.
118
+ * **page_id** (`Integer`, `nil`): the ID of the page, is `nil` when at document-level.
119
+ * **reconstructed** (`Boolean`): indicates whether an object was reconstructed (not extracted as the API gave it).
120
+
121
+
122
+ Aside from the previous attributes, all basic fields have access to a `to_s` method that can be used to print their value as a string.
123
+
124
+
125
+ ### Classification Field
126
+ The classification field `ClassificationField` does not implement all the basic `Field` attributes. It only implements **value**, **confidence** and **page_id**.
127
+
128
+ > Note: a classification field's `value is always a `String`.
129
+
130
+ ### String Field
131
+ The text field `StringField` only has one constraint: it's **value** is a `String` (or `nil`).
132
+
133
+ ## Specific Fields
134
+ Fields which are specific to this product; they are not used in any other product.
135
+
136
+ ### Certificates Field
137
+ The list of certificates obtained by the candidate.
138
+
139
+ A `ResumeV1Certificate` implements the following attributes:
140
+
141
+ * `grade` (String): The grade obtained for the certificate.
142
+ * `name` (String): The name of certification.
143
+ * `provider` (String): The organization or institution that issued the certificate.
144
+ * `year` (String): The year when a certificate was issued or received.
145
+ Fields which are specific to this product; they are not used in any other product.
146
+
147
+ ### Education Field
148
+ The list of the candidate's educational background.
149
+
150
+ A `ResumeV1Education` implements the following attributes:
151
+
152
+ * `degree_domain` (String): The area of study or specialization.
153
+ * `degree_type` (String): The type of degree obtained, such as Bachelor's, Master's, or Doctorate.
154
+ * `end_month` (String): The month when the education program or course was completed.
155
+ * `end_year` (String): The year when the education program or course was completed.
156
+ * `school` (String): The name of the school.
157
+ * `start_month` (String): The month when the education program or course began.
158
+ * `start_year` (String): The year when the education program or course began.
159
+ Fields which are specific to this product; they are not used in any other product.
160
+
161
+ ### Languages Field
162
+ The list of languages that the candidate is proficient in.
163
+
164
+ A `ResumeV1Language` implements the following attributes:
165
+
166
+ * `language` (String): The language's ISO 639 code.
167
+ * `level` (String): The candidate's level for the language.
168
+ Fields which are specific to this product; they are not used in any other product.
169
+
170
+ ### Professional Experiences Field
171
+ The list of the candidate's professional experiences.
172
+
173
+ A `ResumeV1ProfessionalExperience` implements the following attributes:
174
+
175
+ * `contract_type` (String): The type of contract for the professional experience.
176
+ * `department` (String): The specific department or division within the company.
177
+ * `employer` (String): The name of the company or organization.
178
+ * `end_month` (String): The month when the professional experience ended.
179
+ * `end_year` (String): The year when the professional experience ended.
180
+ * `role` (String): The position or job title held by the candidate.
181
+ * `start_month` (String): The month when the professional experience began.
182
+ * `start_year` (String): The year when the professional experience began.
183
+ Fields which are specific to this product; they are not used in any other product.
184
+
185
+ ### Social Networks Field
186
+ The list of social network profiles of the candidate.
187
+
188
+ A `ResumeV1SocialNetworksUrl` implements the following attributes:
189
+
190
+ * `name` (String): The name of the social network.
191
+ * `url` (String): The URL of the social network.
192
+
193
+ # Attributes
194
+ The following fields are extracted for Resume V1:
195
+
196
+ ## Address
197
+ **address** ([StringField](#string-field)): The location information of the candidate, including city, state, and country.
198
+
199
+ ```rb
200
+ puts result.document.inference.prediction.address.value
201
+ ```
202
+
203
+ ## Certificates
204
+ **certificates** (Array<[ResumeV1Certificate](#certificates-field)>): The list of certificates obtained by the candidate.
205
+
206
+ ```rb
207
+ for certificates_elem in result.document.inference.prediction.certificates do
208
+ puts certificates_elem.value
209
+ end
210
+ ```
211
+
212
+ ## Document Language
213
+ **document_language** ([StringField](#string-field)): The ISO 639 code of the language in which the document is written.
214
+
215
+ ```rb
216
+ puts result.document.inference.prediction.document_language.value
217
+ ```
218
+
219
+ ## Document Type
220
+ **document_type** ([ClassificationField](#classification-field)): The type of the document sent.
221
+
222
+ ```rb
223
+ puts result.document.inference.prediction.document_type.value
224
+ ```
225
+
226
+ ## Education
227
+ **education** (Array<[ResumeV1Education](#education-field)>): The list of the candidate's educational background.
228
+
229
+ ```rb
230
+ for education_elem in result.document.inference.prediction.education do
231
+ puts education_elem.value
232
+ end
233
+ ```
234
+
235
+ ## Email Address
236
+ **email_address** ([StringField](#string-field)): The email address of the candidate.
237
+
238
+ ```rb
239
+ puts result.document.inference.prediction.email_address.value
240
+ ```
241
+
242
+ ## Given Names
243
+ **given_names** (Array<[StringField](#string-field)>): The candidate's first or given names.
244
+
245
+ ```rb
246
+ for given_names_elem in result.document.inference.prediction.given_names do
247
+ puts given_names_elem.value
248
+ end
249
+ ```
250
+
251
+ ## Hard Skills
252
+ **hard_skills** (Array<[StringField](#string-field)>): The list of the candidate's technical abilities and knowledge.
253
+
254
+ ```rb
255
+ for hard_skills_elem in result.document.inference.prediction.hard_skills do
256
+ puts hard_skills_elem.value
257
+ end
258
+ ```
259
+
260
+ ## Job Applied
261
+ **job_applied** ([StringField](#string-field)): The position that the candidate is applying for.
262
+
263
+ ```rb
264
+ puts result.document.inference.prediction.job_applied.value
265
+ ```
266
+
267
+ ## Languages
268
+ **languages** (Array<[ResumeV1Language](#languages-field)>): The list of languages that the candidate is proficient in.
269
+
270
+ ```rb
271
+ for languages_elem in result.document.inference.prediction.languages do
272
+ puts languages_elem.value
273
+ end
274
+ ```
275
+
276
+ ## Nationality
277
+ **nationality** ([StringField](#string-field)): The ISO 3166 code for the country of citizenship of the candidate.
278
+
279
+ ```rb
280
+ puts result.document.inference.prediction.nationality.value
281
+ ```
282
+
283
+ ## Phone Number
284
+ **phone_number** ([StringField](#string-field)): The phone number of the candidate.
285
+
286
+ ```rb
287
+ puts result.document.inference.prediction.phone_number.value
288
+ ```
289
+
290
+ ## Profession
291
+ **profession** ([StringField](#string-field)): The candidate's current profession.
292
+
293
+ ```rb
294
+ puts result.document.inference.prediction.profession.value
295
+ ```
296
+
297
+ ## Professional Experiences
298
+ **professional_experiences** (Array<[ResumeV1ProfessionalExperience](#professional-experiences-field)>): The list of the candidate's professional experiences.
299
+
300
+ ```rb
301
+ for professional_experiences_elem in result.document.inference.prediction.professional_experiences do
302
+ puts professional_experiences_elem.value
303
+ end
304
+ ```
305
+
306
+ ## Social Networks
307
+ **social_networks_urls** (Array<[ResumeV1SocialNetworksUrl](#social-networks-field)>): The list of social network profiles of the candidate.
308
+
309
+ ```rb
310
+ for social_networks_urls_elem in result.document.inference.prediction.social_networks_urls do
311
+ puts social_networks_urls_elem.value
312
+ end
313
+ ```
314
+
315
+ ## Soft Skills
316
+ **soft_skills** (Array<[StringField](#string-field)>): The list of the candidate's interpersonal and communication abilities.
317
+
318
+ ```rb
319
+ for soft_skills_elem in result.document.inference.prediction.soft_skills do
320
+ puts soft_skills_elem.value
321
+ end
322
+ ```
323
+
324
+ ## Surnames
325
+ **surnames** (Array<[StringField](#string-field)>): The candidate's last names.
326
+
327
+ ```rb
328
+ for surnames_elem in result.document.inference.prediction.surnames do
329
+ puts surnames_elem.value
330
+ end
331
+ ```
332
+
333
+ # Questions?
334
+ [Join our Slack](https://join.slack.com/t/mindee-community/shared_invite/zt-2d0ds7dtz-DPAF81ZqTy20chsYpQBW5g)
@@ -265,4 +265,4 @@ puts result.document.inference.prediction.weight.value
265
265
  ```
266
266
 
267
267
  # Questions?
268
- [Join our Slack](https://join.slack.com/t/mindee-community/shared_invite/zt-1jv6nawjq-FDgFcF2T5CmMmRpl9LLptw)
268
+ [Join our Slack](https://join.slack.com/t/mindee-community/shared_invite/zt-2d0ds7dtz-DPAF81ZqTy20chsYpQBW5g)
data/docs/us_w9_v1.md CHANGED
@@ -204,4 +204,4 @@ end
204
204
  ```
205
205
 
206
206
  # Questions?
207
- [Join our Slack](https://join.slack.com/t/mindee-community/shared_invite/zt-1jv6nawjq-FDgFcF2T5CmMmRpl9LLptw)
207
+ [Join our Slack](https://join.slack.com/t/mindee-community/shared_invite/zt-2d0ds7dtz-DPAF81ZqTy20chsYpQBW5g)
@@ -4,6 +4,7 @@ require 'json'
4
4
  require 'net/http'
5
5
  require_relative 'error'
6
6
  require_relative '../version'
7
+ require_relative 'response_validation'
7
8
 
8
9
  module Mindee
9
10
  module HTTP
@@ -49,14 +50,15 @@ module Mindee
49
50
  # @param all_words [Boolean] Whether the full word extraction needs to be performed
50
51
  # @param close_file [Boolean] Whether the file will be closed after reading
51
52
  # @param cropper [Boolean] Whether a cropping operation will be applied
52
- # @return [Hash]
53
+ # @return [Array]
53
54
  def predict(input_source, all_words, close_file, cropper)
54
55
  check_api_key
55
56
  response = predict_req_post(input_source, all_words: all_words, close_file: close_file, cropper: cropper)
56
57
  hashed_response = JSON.parse(response.body, object_class: Hash)
57
- return [hashed_response, response.body] if (200..299).include?(response.code.to_i)
58
+ return [hashed_response, response.body] if ResponseValidation.valid_sync_response?(response)
58
59
 
59
- error = Error.handle_error!(@url_name, hashed_response, response.code.to_i)
60
+ ResponseValidation.clean_request!(response)
61
+ error = Error.handle_error(@url_name, response)
60
62
  raise error
61
63
  end
62
64
 
@@ -65,27 +67,29 @@ module Mindee
65
67
  # @param all_words [Boolean] Whether the full word extraction needs to be performed
66
68
  # @param close_file [Boolean] Whether the file will be closed after reading
67
69
  # @param cropper [Boolean] Whether a cropping operation will be applied
68
- # @return [Hash]
70
+ # @return [Array]
69
71
  def predict_async(input_source, all_words, close_file, cropper)
70
72
  check_api_key
71
73
  response = document_queue_req_get(input_source, all_words, close_file, cropper)
72
74
  hashed_response = JSON.parse(response.body, object_class: Hash)
73
- return [hashed_response, response.body] if (200..299).include?(response.code.to_i)
75
+ return [hashed_response, response.body] if ResponseValidation.valid_async_response?(response)
74
76
 
75
- error = Error.handle_error!(@url_name, hashed_response, response.code.to_i)
77
+ ResponseValidation.clean_request!(response)
78
+ error = Error.handle_error(@url_name, response)
76
79
  raise error
77
80
  end
78
81
 
79
82
  # Calls the parsed async doc.
80
83
  # @param job_id [String]
81
- # @return [Hash]
84
+ # @return [Array]
82
85
  def parse_async(job_id)
83
86
  check_api_key
84
87
  response = document_queue_req(job_id)
85
88
  hashed_response = JSON.parse(response.body, object_class: Hash)
86
- return [hashed_response, response.body] if (200..299).include?(response.code.to_i)
89
+ return [hashed_response, response.body] if ResponseValidation.valid_async_response?(response)
87
90
 
88
- error = Error.handle_error!(@url_name, hashed_response, response.code.to_i)
91
+ ResponseValidation.clean_request!(response)
92
+ error = Error.handle_error(@url_name, response)
89
93
  raise error
90
94
  end
91
95
 
@@ -95,7 +99,7 @@ module Mindee
95
99
  # @param all_words [Boolean] Whether the full word extraction needs to be performed
96
100
  # @param close_file [Boolean] Whether the file will be closed after reading
97
101
  # @param cropper [Boolean] Whether a cropping operation will be applied
98
- # @return [Net::HTTP, nil]
102
+ # @return [Net::HTTPResponse, nil]
99
103
  def predict_req_post(input_source, all_words: false, close_file: true, cropper: false)
100
104
  uri = URI("#{@url_root}/predict")
101
105
 
@@ -116,17 +120,18 @@ module Mindee
116
120
  form_data.push ['include_mvision', 'true'] if all_words
117
121
 
118
122
  req.set_form(form_data, 'multipart/form-data')
119
-
123
+ response = nil
120
124
  Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: @request_timeout) do |http|
121
- http.request(req)
125
+ response = http.request(req)
122
126
  end
127
+ response
123
128
  end
124
129
 
125
130
  # @param input_source [Mindee::Input::Source::LocalInputSource, Mindee::Input::Source::UrlInputSource]
126
131
  # @param all_words [Boolean] Whether the full word extraction needs to be performed
127
132
  # @param close_file [Boolean] Whether the file will be closed after reading
128
133
  # @param cropper [Boolean] Whether a cropping operation will be applied
129
- # @return [Net::HTTPResponse]
134
+ # @return [Net::HTTPResponse, nil]
130
135
  def document_queue_req_get(input_source, all_words, close_file, cropper)
131
136
  uri = URI("#{@url_root}/predict_async")
132
137
 
@@ -148,13 +153,15 @@ module Mindee
148
153
 
149
154
  req.set_form(form_data, 'multipart/form-data')
150
155
 
156
+ response = nil
151
157
  Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: @request_timeout) do |http|
152
- http.request(req)
158
+ response = http.request(req)
153
159
  end
160
+ response
154
161
  end
155
162
 
156
163
  # @param job_id [String]
157
- # @return [Net::HTTPResponse]
164
+ # @return [Net::HTTPResponse, nil]
158
165
  def document_queue_req(job_id)
159
166
  uri = URI("#{@url_root}/documents/queue/#{job_id}")
160
167
 
@@ -171,8 +178,8 @@ module Mindee
171
178
 
172
179
  if response.code.to_i > 299 && response.code.to_i < 400
173
180
  req = Net::HTTP::Get.new(response['location'], headers)
174
- response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: @request_timeout) do |http|
175
- http.request(req)
181
+ Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: @request_timeout) do |http|
182
+ response = http.request(req)
176
183
  end
177
184
  end
178
185
  response
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+
3
5
  module Mindee
4
6
  module HTTP
5
7
  # Mindee HTTP error module.
@@ -50,15 +52,20 @@ module Mindee
50
52
  end
51
53
 
52
54
  end
53
- error_obj
55
+ error_obj.nil? ? {} : error_obj
54
56
  end
55
57
 
56
58
  # Creates an appropriate HTTP error exception, based on retrieved http error code
57
59
  # @param url [String] the url of the product
58
60
  # @param response [Hash] dictionary response retrieved by the server
59
- # @param code [Integer] http error code of the response
60
- def handle_error!(url, response, code)
61
- error_obj = create_error_obj(response)
61
+ def handle_error(url, response)
62
+ code = response.code.to_i
63
+ begin
64
+ parsed_hash = JSON.parse(response.body, object_class: Hash)
65
+ rescue JSON::ParserError
66
+ parsed_hash = response.body.to_s
67
+ end
68
+ error_obj = create_error_obj(parsed_hash)
62
69
  case code
63
70
  when 400..499
64
71
  MindeeHttpClientError.new(error_obj, url, code)
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'net/http'
5
+
6
+ module Mindee
7
+ module HTTP
8
+ # Module dedicated to the validation & sanitizing of HTTP responses.
9
+ module ResponseValidation
10
+ # Checks if the synchronous response is valid. Returns True if the response is valid.
11
+ # @param [Net::HTTPResponse] response
12
+ # @return [Boolean]
13
+ def self.valid_sync_response?(response)
14
+ return false unless (200..399).cover?(response.code.to_i)
15
+
16
+ begin
17
+ JSON.parse(response.body, object_class: Hash)
18
+ rescue StandardError
19
+ return false
20
+ end
21
+ true
22
+ end
23
+
24
+ # Checks if the asynchronous response is valid. Also checks if it is a valid synchronous response.
25
+ # Returns true if the response is valid.
26
+ # @param [Net::HTTPResponse] response
27
+ # @return [Boolean]
28
+ def self.valid_async_response?(response)
29
+ return false unless valid_sync_response?(response)
30
+
31
+ return false unless (200..302).cover?(response.code.to_i)
32
+
33
+ hashed_response = JSON.parse(response.body, object_class: Hash)
34
+ return false if hashed_response.dig('job', 'error') && !hashed_response.dig('job', 'error').empty?
35
+
36
+ true
37
+ end
38
+
39
+ # Checks and correct the response object depending on the possible kinds of returns.
40
+ # @param response [Net::HTTPResponse]
41
+ def self.clean_request!(response)
42
+ return response if (response.code.to_i < 200) || (response.code.to_i > 302)
43
+
44
+ return response unless response.body.empty?
45
+
46
+ hashed_response = JSON.parse(response.body, object_class: Hash)
47
+ if hashed_response.dig('api_request', 'status_code').to_i > 399
48
+ response.instance_variable_set(:@code, hashed_response['api_request']['status_code'].to_s)
49
+ end
50
+ return unless hashed_response.dig('job', 'error').empty?
51
+
52
+ response.instance_variable_set(:@code, '500')
53
+ end
54
+ end
55
+ end
56
+ end
@@ -14,6 +14,8 @@ module Mindee
14
14
  PROCESSING = :processing
15
15
  # Document parsing is complete.
16
16
  COMPLETED = :completed
17
+ # Job failed
18
+ FAILURE = :failed
17
19
  end
18
20
 
19
21
  # Potential values for requests.
@@ -36,10 +38,13 @@ module Mindee
36
38
  attr_reader :status
37
39
  # @return [Integer, nil]
38
40
  attr_reader :millisecs_taken
41
+ # @return [Hash, nil]
42
+ attr_reader :error
39
43
 
40
44
  # @param http_response [Hash]
41
45
  def initialize(http_response)
42
46
  @id = http_response['id']
47
+ @error = http_response['error']
43
48
  @issued_at = Time.iso8601(http_response['issued_at'])
44
49
  if http_response.key?('available_at') && !http_response['available_at'].nil?
45
50
  @available_at = Time.iso8601(http_response['available_at'])
@@ -108,7 +113,7 @@ module Mindee
108
113
  end
109
114
  if http_response.key?('document') &&
110
115
  (!http_response.key?('job') ||
111
- http_response['job']['status'] == 'completed') &&
116
+ http_response['job']['status'] == 'completed') &&
112
117
  @api_request.status == RequestStatus::SUCCESS
113
118
  @document = Mindee::Parsing::Common::Document.new(product_class, http_response['document'])
114
119
  end
@@ -96,7 +96,7 @@ module Mindee
96
96
  return '' if in_str.nil?
97
97
  return in_str if max_col_size.nil?
98
98
 
99
- in_str.length < max_col_size ? in_str : "#{in_str[0..max_col_size - 4]}..."
99
+ in_str.length <= max_col_size ? in_str : "#{in_str[0..max_col_size - 4]}..."
100
100
  end
101
101
  end
102
102
  end
@@ -1,5 +1,10 @@
1
1
  inherit_from: ../../../.rubocop.yml
2
2
 
3
3
  Metrics/AbcSize:
4
- Max: 75
5
-
4
+ Enabled: false
5
+ Metrics/ClassLength:
6
+ Enabled: false
7
+ Metrics/CyclomaticComplexity:
8
+ Enabled: false
9
+ Metrics/PerceivedComplexity:
10
+ Enabled: false
@@ -7,9 +7,9 @@ require_relative 'driver_license_v1_page'
7
7
  module Mindee
8
8
  module Product
9
9
  module EU
10
- # EU Driver License module.
10
+ # Driver License module.
11
11
  module DriverLicense
12
- # EU Driver License V1 prediction inference.
12
+ # Driver License V1 prediction inference.
13
13
  class DriverLicenseV1 < Mindee::Parsing::Common::Inference
14
14
  @endpoint_name = 'eu_driver_license'
15
15
  @endpoint_version = '1'
@@ -6,7 +6,7 @@ module Mindee
6
6
  module Product
7
7
  module EU
8
8
  module DriverLicense
9
- # EU Driver License V1 document prediction.
9
+ # Driver License V1 document prediction.
10
10
  class DriverLicenseV1Document < Mindee::Parsing::Common::Prediction
11
11
  include Mindee::Parsing::Standard
12
12
  # EU driver license holders address
@@ -7,7 +7,7 @@ module Mindee
7
7
  module Product
8
8
  module EU
9
9
  module DriverLicense
10
- # EU Driver License V1 page.
10
+ # Driver License V1 page.
11
11
  class DriverLicenseV1Page < Mindee::Parsing::Common::Page
12
12
  # @param prediction [Hash]
13
13
  def initialize(prediction)
@@ -19,7 +19,7 @@ module Mindee
19
19
  end
20
20
  end
21
21
 
22
- # EU Driver License V1 page prediction.
22
+ # Driver License V1 page prediction.
23
23
  class DriverLicenseV1PagePrediction < DriverLicenseV1Document
24
24
  include Mindee::Parsing::Standard
25
25
 
@@ -133,7 +133,6 @@ module Mindee
133
133
  # @return [Mindee::Parsing::Standard::StringField]
134
134
  attr_reader :y6
135
135
 
136
- # rubocop:disable Metrics/AbcSize
137
136
  # @param prediction [Hash]
138
137
  # @param page_id [Integer, nil]
139
138
  def initialize(prediction, page_id)
@@ -227,7 +226,6 @@ module Mindee
227
226
  out_str << "\n:MRZ Line 2: #{@mrz2}".rstrip
228
227
  out_str[1..].to_s
229
228
  end
230
- # rubocop:enable Metrics/AbcSize
231
229
  end
232
230
  end
233
231
  end