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.
- 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
|
+

|
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
|