Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/auto_invoice_splitter_extraction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def parse_single_page(mindee_client, input_source)
end

def parse_multi_page(mindee_client, input_source)
pdf_extractor = Mindee::Extraction::PdfExtractor::PdfExtractor.new(input_source)
pdf_extractor = Mindee::PDF::PDFExtractor::PDFExtractor.new(input_source)
invoice_splitter_response = mindee_client.enqueue_and_parse(
input_source,
Mindee::Product::InvoiceSplitter::InvoiceSplitterV1,
Expand Down
12 changes: 8 additions & 4 deletions lib/mindee.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
require 'mindee/extraction'

module Mindee
# Mindee internal error module.
module Errors
end

# Custom extraction module
module Extraction
end

# Mindee internal http module.
module HTTP
end
Expand All @@ -29,10 +37,6 @@ module ImageCompressor
end
end

# Custom extraction module
module Extraction
end

# Parsing internals and fields.
module Parsing
# Common fields and functions.
Expand Down
26 changes: 18 additions & 8 deletions lib/mindee/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ def enqueue_and_parse(
delay_sec: 1.5,
max_retries: 80
)
validate_async_params(initial_delay_sec, delay_sec, max_retries)
enqueue_res = enqueue(
input_source,
product_class,
Expand All @@ -187,7 +188,8 @@ def enqueue_and_parse(
end
if queue_res.job.status != Mindee::Parsing::Common::JobStatus::COMPLETED
elapsed = initial_delay_sec + (polling_attempts * delay_sec)
raise "Asynchronous parsing request timed out after #{elapsed} seconds (#{polling_attempts} tries)"
raise Errors::MindeeAPIError,
"Asynchronous parsing request timed out after #{elapsed} seconds (#{polling_attempts} tries)"
end

queue_res
Expand Down Expand Up @@ -242,8 +244,8 @@ def execute_workflow(
# @return [Mindee::Parsing::Common::ApiResponse]
def load_prediction(product_class, local_response)
Mindee::Parsing::Common::ApiResponse.new(product_class, local_response.as_hash, local_response.as_hash.to_json)
rescue KeyError
raise 'No prediction found in local response.'
rescue KeyError, Errors::MindeeAPIError
raise Errors::MindeeInputError, 'No prediction found in local response.'
end

# Load a document from an absolute path, as a string.
Expand Down Expand Up @@ -314,11 +316,18 @@ def validate_async_params(initial_delay_sec, delay_sec, max_retries)
min_delay_sec = 1
min_initial_delay_sec = 1
min_retries = 2
raise "Cannot set auto-poll delay to less than #{min_delay_sec} second(s)" if delay_sec < min_delay_sec
if delay_sec < min_delay_sec
raise ArgumentError,
"Cannot set auto-poll delay to less than #{min_delay_sec} second(s)"
end
if initial_delay_sec < min_initial_delay_sec
raise "Cannot set initial parsing delay to less than #{min_initial_delay_sec} second(s)"
raise ArgumentError,
"Cannot set initial parsing delay to less than #{min_initial_delay_sec} second(s)"
end
raise "Cannot set auto-poll retries to less than #{min_retries}" if max_retries < min_retries
return unless max_retries < min_retries

raise ArgumentError,
"Cannot set auto-poll retries to less than #{min_retries}"
end

# Creates an endpoint with the given values. Raises an error if the endpoint is invalid.
Expand All @@ -333,8 +342,9 @@ def validate_async_params(initial_delay_sec, delay_sec, max_retries)
# @param version [String] For custom endpoints, version of the product.
# @return [Mindee::HTTP::Endpoint]
def initialize_endpoint(product_class, endpoint_name: '', account_name: '', version: '')
if (endpoint_name.nil? || endpoint_name.empty?) && product_class == Mindee::Product::Custom::CustomV1
raise 'Missing argument endpoint_name when using custom class'
if (endpoint_name.nil? || endpoint_name.empty?) &&
[Mindee::Product::Custom::CustomV1, Mindee::Product::Generated::GeneratedV1].include?(product_class)
raise Errors::MindeeConfigurationError, 'Missing argument endpoint_name when using custom class'
end

endpoint_name = fix_endpoint_name(product_class, endpoint_name)
Expand Down
5 changes: 5 additions & 0 deletions lib/mindee/errors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

require_relative 'errors/mindee_error'
require_relative 'errors/mindee_http_error'
require_relative 'errors/mindee_input_error'
17 changes: 17 additions & 0 deletions lib/mindee/errors/mindee_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

module Mindee
module Errors
# Base class for all custom mindee errors.
class MindeeError < StandardError; end

# Errors relating to library issues.
class MindeeAPIError < MindeeError; end

# Errors relating to misuse of the library.
class MindeeConfigurationError < MindeeError; end

# Errors relating to geometric manipulation issues.
class MindeeGeometryError < MindeeError; end
end
end
36 changes: 36 additions & 0 deletions lib/mindee/errors/mindee_http_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

require_relative 'mindee_error'

module Mindee
module Errors
# API HttpError
class MindeeHTTPError < MindeeError
# @return [String]
attr_reader :status_code
# @return [Integer]
attr_reader :api_code
# @return [String]
attr_reader :api_details
# @return [String]
attr_reader :api_message

# @param http_error [Hash]
# @param url [String]
# @param code [Integer]
def initialize(http_error, url, code)
@status_code = code
@api_code = http_error['code']
@api_details = http_error['details']
@api_message = http_error['message']
super("#{url} #{@status_code} HTTP error: #{@api_details} - #{@api_message}")
end
end

# Base class for all client-side errors.
class MindeeHTTPClientError < MindeeHTTPError; end

# Base class for all server-side errors.
class MindeeHTTPServerError < MindeeHTTPError; end
end
end
30 changes: 30 additions & 0 deletions lib/mindee/errors/mindee_input_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

module Mindee
module Errors
# Base class for errors relating to input documents.
class MindeeInputError < MindeeError; end

# Errors relating to sources (documents) handling.
class MindeeSourceError < MindeeInputError; end

# Errors relating to mime type issues.
class MindeeMimeTypeError < MindeeSourceError
# @return [String]
attr_reader :invalid_mimetype

# @param mime_type [String]
def initialize(mime_type)
@invalid_mimetype = mime_type
super("'#{@invalid_mimetype}' mime type not allowed, must be one of" \
"#{Mindee::Input::Source::ALLOWED_MIME_TYPES.join(', ')}")
end
end

# Errors relating to the handling of images.
class MindeeImageError < MindeeInputError; end

# Errors relating to the handling of PDF documents.
class MindeePDFError < MindeeInputError; end
end
end
2 changes: 0 additions & 2 deletions lib/mindee/extraction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,3 @@

require_relative 'extraction/tax_extractor'
require_relative 'extraction/multi_receipts_extractor'
require_relative 'extraction/common'
require_relative 'extraction/pdf_extractor'
4 changes: 0 additions & 4 deletions lib/mindee/extraction/common.rb

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

require_relative '../common/image_extractor'
require_relative '../../image/image_extractor'

module Mindee
# Image Extraction Module.
Expand All @@ -15,13 +15,16 @@ def self.extract_receipts(input_source, inference)
# @return [Array<ExtractedImage>] Individual extracted receipts as an array of ExtractedMultiReceiptsImage.

images = []
raise 'No possible receipts candidates found for MultiReceipts extraction.' unless inference.prediction.receipts
unless inference.prediction.receipts
raise Errors::MindeeInputError,
'No possible receipts candidates found for Multi-Receipts extraction.'
end

(0...input_source.count_pdf_pages).each do |page_id|
receipt_positions = inference.pages[page_id].prediction.receipts.map(&:bounding_box)
images.concat(
Mindee::Extraction::ImageExtractor.extract_multiple_images_from_source(input_source, page_id + 1,
receipt_positions)
Mindee::Image::ImageExtractor.extract_multiple_images_from_source(input_source, page_id + 1,
receipt_positions)
)
end

Expand Down
4 changes: 0 additions & 4 deletions lib/mindee/extraction/pdf_extractor.rb

This file was deleted.

2 changes: 1 addition & 1 deletion lib/mindee/http.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

require_relative 'http/endpoint'
require_relative 'http/error'
require_relative 'http/error_handler'
require_relative 'http/workflow_endpoint'
14 changes: 7 additions & 7 deletions lib/mindee/http/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require 'json'
require 'net/http'
require_relative 'error'
require_relative 'error_handler'
require_relative '../version'
require_relative 'response_validation'

Expand Down Expand Up @@ -65,7 +65,7 @@ def predict(input_source, all_words, full_text, close_file, cropper)
return [hashed_response, response.body] if ResponseValidation.valid_sync_response?(response)

ResponseValidation.clean_request!(response)
error = Error.handle_error(@url_name, response)
error = ErrorHandler.handle_error(@url_name, response)
raise error
end

Expand All @@ -83,7 +83,7 @@ def predict_async(input_source, all_words, full_text, close_file, cropper)
return [hashed_response, response.body] if ResponseValidation.valid_async_response?(response)

ResponseValidation.clean_request!(response)
error = Error.handle_error(@url_name, response)
error = ErrorHandler.handle_error(@url_name, response)
raise error
end

Expand All @@ -97,7 +97,7 @@ def parse_async(job_id)
return [hashed_response, response.body] if ResponseValidation.valid_async_response?(response)

ResponseValidation.clean_request!(response)
error = Error.handle_error(@url_name, response)
error = ErrorHandler.handle_error(@url_name, response)
raise error
end

Expand Down Expand Up @@ -201,9 +201,9 @@ def document_queue_req(job_id)
def check_api_key
return unless @api_key.nil? || @api_key.empty?

raise "Missing API key for product \"'#{@url_name}' v#{@version}\" (belonging to \"#{@owner}\"), " \
"check your Client Configuration.\n" \
'You can set this using the ' \
raise Errors::MindeeAPIError,
"Missing API key for product \"'#{@url_name}' v#{@version}\" (belonging to \"#{@owner}\"), " \
"check your Client Configuration.\nYou can set this using the " \
"'#{HTTP::API_KEY_ENV_NAME}' environment variable."
end
end
Expand Down
40 changes: 5 additions & 35 deletions lib/mindee/http/error.rb → lib/mindee/http/error_handler.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# frozen_string_literal: true

require 'json'
require_relative '../errors/mindee_http_error'

module Mindee
module HTTP
# Mindee HTTP error module.
module Error
module ErrorHandler
module_function

# Extracts the HTTP error from the response hash, or the job error if there is one.
Expand Down Expand Up @@ -80,44 +81,13 @@ def handle_error(url, response)
error_obj = create_error_obj(parsed_hash)
case code
when 400..499
MindeeHttpClientError.new(error_obj, url, code)
Errors::MindeeHTTPClientError.new(error_obj, url, code)
when 500..599
MindeeHttpServerError.new(error_obj, url, code)
Errors::MindeeHTTPServerError.new(error_obj, url, code)
else
MindeeHttpError.new(error_obj, url, code)
Errors::MindeeHTTPError.new(error_obj, url, code)
end
end

# API HttpError
class MindeeHttpError < StandardError
# @return [String]
attr_reader :status_code
# @return [Integer]
attr_reader :api_code
# @return [String]
attr_reader :api_details
# @return [String]
attr_reader :api_message

# @param http_error [Hash]
# @param url [String]
# @param code [Integer]
def initialize(http_error, url, code)
@status_code = code
@api_code = http_error['code']
@api_details = http_error['details']
@api_message = http_error['message']
super("#{url} #{@status_code} HTTP error: #{@api_details} - #{@api_message}")
end
end

# API client HttpError
class MindeeHttpClientError < MindeeHttpError
end

# API server HttpError
class MindeeHttpServerError < MindeeHttpError
end
end
end
end
10 changes: 5 additions & 5 deletions lib/mindee/http/workflow_endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require 'json'
require 'net/http'
require_relative 'error'
require_relative 'error_handler'

module Mindee
module HTTP
Expand Down Expand Up @@ -37,7 +37,7 @@ def execute_workflow(input_source, full_text, document_alias, priority, public_u
return [hashed_response, response.body] if ResponseValidation.valid_async_response?(response)

ResponseValidation.clean_request!(response)
error = Error.handle_error(@url_name, response)
error = ErrorHandler.handle_error(@url_name, response)
raise error
end

Expand Down Expand Up @@ -81,9 +81,9 @@ def workflow_execution_req_post(input_source, document_alias, priority, full_tex
def check_api_key
return unless @api_key.nil? || @api_key.empty?

raise "Missing API key. Check your Client Configuration.\n" \
'You can set this using the ' \
"'#{HTTP::API_KEY_ENV_NAME}' environment variable."
raise Errors::MindeeConfigurationError, "Missing API key. Check your Client Configuration.\n" \
"You can set this using the '#{HTTP::API_KEY_ENV_NAME}'" \
'environment variable.'
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/mindee/image.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# frozen_string_literal: true

require_relative 'image/extracted_image'
require_relative 'image/image_compressor'
require_relative 'image/image_extractor'
require_relative 'image/image_utils'
Loading
Loading