mindee 3.5.0 → 3.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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