mindee 3.5.0 → 3.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +39 -4
- data/bin/mindee.rb +6 -0
- data/docs/bank_account_details_v2.md +1 -1
- data/docs/bank_check_v1.md +1 -1
- data/docs/bank_statement_fr_v1.md +1 -1
- data/docs/barcode_reader_v1.md +1 -1
- data/docs/carte_grise_v1.md +1 -1
- data/docs/carte_vitale_v1.md +1 -1
- data/docs/code_samples/resume_v1_async.txt +19 -0
- data/docs/cropper_v1.md +1 -1
- data/docs/custom_v1.md +1 -1
- data/docs/eu_driver_license_v1.md +5 -5
- data/docs/expense_receipts_v5.md +1 -1
- data/docs/financial_document_v1.md +1 -1
- data/docs/generated_v1.md +1 -1
- data/docs/getting_started.md +1 -1
- data/docs/idcard_fr_v2.md +1 -1
- data/docs/international_id_v2.md +226 -0
- data/docs/invoice_splitter_v1.md +1 -1
- data/docs/invoices_v4.md +1 -1
- data/docs/license_plates_v1.md +1 -1
- data/docs/multi_receipts_detector_v1.md +1 -1
- data/docs/passport_v1.md +1 -1
- data/docs/proof_of_address_v1.md +1 -1
- data/docs/resume_v1.md +334 -0
- data/docs/us_driver_license_v1.md +1 -1
- data/docs/us_w9_v1.md +1 -1
- data/lib/mindee/http/endpoint.rb +24 -17
- data/lib/mindee/http/error.rb +11 -4
- data/lib/mindee/http/response_validation.rb +56 -0
- data/lib/mindee/parsing/common/api_response.rb +6 -1
- data/lib/mindee/parsing/standard/base_field.rb +1 -1
- data/lib/mindee/product/.rubocop.yml +7 -2
- data/lib/mindee/product/eu/driver_license/driver_license_v1.rb +2 -2
- data/lib/mindee/product/eu/driver_license/driver_license_v1_document.rb +1 -1
- data/lib/mindee/product/eu/driver_license/driver_license_v1_page.rb +2 -2
- data/lib/mindee/product/fr/carte_grise/carte_grise_v1_document.rb +0 -2
- data/lib/mindee/product/resume/resume_v1.rb +39 -0
- data/lib/mindee/product/resume/resume_v1_certificate.rb +69 -0
- data/lib/mindee/product/resume/resume_v1_document.rb +322 -0
- data/lib/mindee/product/resume/resume_v1_education.rb +90 -0
- data/lib/mindee/product/resume/resume_v1_language.rb +55 -0
- data/lib/mindee/product/resume/resume_v1_page.rb +32 -0
- data/lib/mindee/product/resume/resume_v1_professional_experience.rb +97 -0
- data/lib/mindee/product/resume/resume_v1_social_networks_url.rb +55 -0
- data/lib/mindee/product.rb +1 -0
- data/lib/mindee/version.rb +1 -1
- 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-
|
268
|
+
[Join our Slack](https://join.slack.com/t/mindee-community/shared_invite/zt-2d0ds7dtz-DPAF81ZqTy20chsYpQBW5g)
|
data/docs/us_w9_v1.md
CHANGED
data/lib/mindee/http/endpoint.rb
CHANGED
@@ -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 [
|
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
|
58
|
+
return [hashed_response, response.body] if ResponseValidation.valid_sync_response?(response)
|
58
59
|
|
59
|
-
|
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 [
|
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
|
75
|
+
return [hashed_response, response.body] if ResponseValidation.valid_async_response?(response)
|
74
76
|
|
75
|
-
|
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 [
|
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
|
89
|
+
return [hashed_response, response.body] if ResponseValidation.valid_async_response?(response)
|
87
90
|
|
88
|
-
|
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::
|
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
|
-
|
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
|
data/lib/mindee/http/error.rb
CHANGED
@@ -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
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
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
|
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
|
@@ -7,9 +7,9 @@ require_relative 'driver_license_v1_page'
|
|
7
7
|
module Mindee
|
8
8
|
module Product
|
9
9
|
module EU
|
10
|
-
#
|
10
|
+
# Driver License module.
|
11
11
|
module DriverLicense
|
12
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|