mindee 3.6.0 → 3.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28d1e6c48c575030a3c6519080f7cff23b52745c212d8db9cc43f8c800c1c3d8
4
- data.tar.gz: a96015beeeac1378f72f77bd3bcb73c3032e0946e39cc7a4519b5db3eca3e8c4
3
+ metadata.gz: d18b48dabb484d078d9fe9ccbe4266d80fde752fb261c13ec6143e69c0ebe0c8
4
+ data.tar.gz: 9340689c20fa1d161461252a379f0754fe7482dbac8fb89407845fc501ac4ae1
5
5
  SHA512:
6
- metadata.gz: 2ca08ce6349eb1ebeaf7cf2bbba6004ff638cfc0db480d7b41bf183f6f6a4066bd1a76a36edbf4282eb65f31c89487cad388cc1f2ea6bfa2bb6bed7ff6c6e517
7
- data.tar.gz: e18f1c1f8190c73987b036745fba0e6dca91b98ee71bc6144d8f1612be4c497cbb5f0301951b91db494c4812ca07ef6ec86fdeee17bdb3e83aacaef481b2fb3f
6
+ metadata.gz: c74414360e4f02582286e8e49e1fbff59dbc654c75876717268f6f3805c7dfbfbd14729828dde8a86d53b8fcbe3eaca0bf0c988dd66919d54c9cfbc719e6b49f
7
+ data.tar.gz: d14ac158a9d719cdfe2f5ecc5ba0b6a16eb6bae3ce83474a285be980cb00791acfe0e71aa9bb6dbd17945264168ce19f7e5ca75746083994d8a8d0927d76b43f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Mindee Ruby API Library Changelog
2
2
 
3
+ ## v3.6.1 - 2024-03-07
4
+ ### Changes
5
+ * :recycle: update error handling to account for future evolutions
6
+ * :memo: update miscellaneous product documentations
7
+ * :memo: add used environment variables to readme
8
+
9
+
3
10
  ## v3.6.0 - 2024-02-21
4
11
  ### Changes
5
12
  * :sparkles: add support for resume V1
data/README.md CHANGED
@@ -1,12 +1,15 @@
1
1
  [![License: MIT](https://img.shields.io/github/license/mindee/mindee-api-ruby)](https://opensource.org/licenses/MIT) [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/mindee/mindee-api-ruby/test.yml)](https://github.com/mindee/mindee-api-ruby) [![Gem Version](https://img.shields.io/gem/v/mindee)](https://rubygems.org/gems/mindee) [![Downloads](https://img.shields.io/gem/dt/mindee.svg)](https://rubygems.org/gems/mindee)
2
2
 
3
3
  # Mindee API Helper Library for Ruby
4
+
4
5
  Quickly and easily connect to Mindee's API services using Ruby.
5
6
 
6
7
  ## Requirements
8
+
7
9
  The following Ruby versions are tested and supported: 2.6, 2.7, 3.0, 3.1, 3.2
8
10
 
9
11
  ## Quick Start
12
+
10
13
  Here's the TL;DR of getting started.
11
14
 
12
15
  First, get an [API Key](https://developers.mindee.com/docs/create-api-key)
@@ -18,15 +21,38 @@ gem 'mindee'
18
21
  ```
19
22
 
20
23
  And then execute:
24
+
21
25
  ```sh
22
26
  bundle install
23
27
  ```
24
28
 
25
29
  Finally, Ruby away!
26
30
 
31
+ ### Environment Variables
32
+
33
+ This library offers customizable features through environment variables. While there may be instances where you need to
34
+ rely on them, it's crucial to exercise caution when modifying them to avoid unintended consequences.
35
+
36
+ If you're unsure whether you need to adjust these variables, it's advisable to refrain from doing so unless you have a
37
+ specific reason. Accidentally overwriting them can lead to unexpected behavior.
38
+
39
+ Before making any changes, we recommend reviewing the following information to understand the purpose and potential
40
+ impact of each environment variable:
41
+
42
+ * `MINDEE_API_KEY`:
43
+ * **Description**: Your personal Mindee API Key as shown on the platform. Be careful not to show this publicly!
44
+ * **Default Value**: `nil`
45
+ * `MINDEE_BASE_URL`:
46
+ * **Description**: The default base URL of the API endpoint. Use this variable to specify the root URL for API requests. Modify as needed for proxy configurations or changes in API endpoint location.
47
+ * **Default Value**: `https://api.mindee.net/v1`
48
+ * `MINDEE_REQUEST_TIMEOUT`:
49
+ * **Description**: The default timeout for HTTP requests (in seconds).
50
+ * **Default Value**: `120`
51
+
27
52
  ### Loading a File and Parsing It
28
53
 
29
54
  #### Global Documents
55
+
30
56
  ```ruby
31
57
  require 'mindee'
32
58
 
@@ -47,26 +73,31 @@ puts result.document
47
73
  **Note:** Files can also be loaded from:
48
74
 
49
75
  A URL (`https`):
76
+
50
77
  ```rb
51
78
  input_source = mindee_client.source_from_url("https://my-url")
52
79
  ```
53
80
 
54
81
  A bytes input stream:
82
+
55
83
  ```rb
56
84
  input_source = mindee_client.source_from_bytes('/path/to/the/file.ext', "name-of-my-file.ext")
57
85
  ```
58
86
 
59
87
  A base64 encoded string:
88
+
60
89
  ```rb
61
90
  input_source = mindee_client.source_from_b64string('/path/to/the/file.ext', "name-of-my-file.ext")
62
91
  ```
63
92
 
64
93
  A ruby `file` object:
94
+
65
95
  ```rb
66
96
  input_source = mindee_client.source_from_file(input_file, "name-of-my-file.ext")
67
97
  ```
68
98
 
69
99
  #### Region-Specific Documents
100
+
70
101
  ```ruby
71
102
  require 'mindee'
72
103
 
@@ -86,6 +117,7 @@ puts result.document
86
117
  ```
87
118
 
88
119
  ### Custom Document (API Builder)
120
+
89
121
  ```ruby
90
122
  require 'mindee'
91
123
 
@@ -119,17 +151,19 @@ end
119
151
  ## CLI Tool
120
152
 
121
153
  A command-line interface tool is available to quickly test documents:
154
+
122
155
  ```sh
123
156
  ruby ./bin/mindee.rb invoice path/to/your/file.ext
124
157
  ```
125
158
 
126
-
127
159
  Using the ruby bundler:
160
+
128
161
  ```sh
129
162
  bundle exec ruby ./bin/mindee.rb invoice path/to/your/file.ext
130
163
  ```
131
164
 
132
165
  ## Further Reading
166
+
133
167
  There's more to it than that for those that need more features, or want to
134
168
  customize the experience.
135
169
 
@@ -157,15 +191,15 @@ customize the experience.
157
191
  * [Invoice Splitter API Ruby](https://developers.mindee.com/docs/invoice-splitter-api-ruby)
158
192
  * [Multi Receipts Detector API Ruby](https://developers.mindee.com/docs/multi-receipts-detector-api-ruby)
159
193
 
160
-
161
194
  You can also take a look at the
162
195
  [Reference Documentation](https://mindee.github.io/mindee-api-ruby/).
163
196
 
164
-
165
197
  ## License
198
+
166
199
  Copyright © Mindee, SA
167
200
 
168
201
  Available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
169
202
 
170
203
  ## Questions?
204
+
171
205
  [Join our Slack](https://join.slack.com/t/mindee-community/shared_invite/zt-2d0ds7dtz-DPAF81ZqTy20chsYpQBW5g)
@@ -31,6 +31,37 @@ puts result.document
31
31
 
32
32
  **Output (RST):**
33
33
  ```rst
34
+ ########
35
+ Document
36
+ ########
37
+ :Mindee ID: cfa20a58-20cf-43b6-8cec-9505fa69d1c2
38
+ :Filename: default_sample.jpg
39
+
40
+ Inference
41
+ #########
42
+ :Product: mindee/international_id v2.0
43
+ :Rotation applied: No
44
+
45
+ Prediction
46
+ ==========
47
+ :Document Type: IDENTIFICATION_CARD
48
+ :Document Number: 12345678A
49
+ :Surnames: MUESTRA
50
+ MUESTRA
51
+ :Given Names: CARMEN
52
+ :Sex: F
53
+ :Birth Date: 1980-01-01
54
+ :Birth Place: CAMPO DE CRIPTANA CIUDAD REAL ESPANA
55
+ :Nationality: ESP
56
+ :Personal Number: BAB1834284<44282767Q0
57
+ :Country of Issue: ESP
58
+ :State of Issue: MADRID
59
+ :Issue Date:
60
+ :Expiration Date: 2030-01-01
61
+ :Address: C/REAL N13, 1 DCHA COLLADO VILLALBA MADRID MADRID MADRID
62
+ :MRZ Line 1: IDESPBAB1834284<44282767Q0<<<<
63
+ :MRZ Line 2: 8001010F1301017ESP<<<<<<<<<<<3
64
+ :MRZ Line 3: MUESTRA<MUESTRA<<CARMEN<<<<<<<
34
65
  ```
35
66
 
36
67
  # Field Types
@@ -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
@@ -3,7 +3,7 @@
3
3
  # Mindee
4
4
  module Mindee
5
5
  # Current version.
6
- VERSION = '3.6.0'
6
+ VERSION = '3.6.1'
7
7
 
8
8
  # Finds and return the current platform.
9
9
  # @return [String]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mindee
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.0
4
+ version: 3.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mindee, SA
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-21 00:00:00.000000000 Z
11
+ date: 2024-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: marcel
@@ -181,6 +181,7 @@ files:
181
181
  - lib/mindee/http/.rubocop.yml
182
182
  - lib/mindee/http/endpoint.rb
183
183
  - lib/mindee/http/error.rb
184
+ - lib/mindee/http/response_validation.rb
184
185
  - lib/mindee/input.rb
185
186
  - lib/mindee/input/sources.rb
186
187
  - lib/mindee/parsing.rb