mindee 1.2.0 → 2.0.0
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/.gitignore +1 -1
- data/.rubocop.yml +2 -2
- data/.yardopts +4 -0
- data/CHANGELOG.md +21 -0
- data/README.md +46 -23
- data/Rakefile +6 -1
- data/bin/mindee.rb +70 -61
- data/docs/ruby-api-builder.md +131 -0
- data/docs/ruby-getting-started.md +265 -0
- data/docs/ruby-invoice-ocr.md +261 -0
- data/docs/ruby-passport-ocr.md +156 -0
- data/docs/ruby-receipt-ocr.md +170 -0
- data/lib/mindee/client.rb +128 -93
- data/lib/mindee/document_config.rb +22 -154
- data/lib/mindee/geometry.rb +105 -8
- data/lib/mindee/http/endpoint.rb +80 -0
- data/lib/mindee/input/pdf_processing.rb +106 -0
- data/lib/mindee/input/sources.rb +97 -0
- data/lib/mindee/input.rb +3 -0
- data/lib/mindee/parsing/document.rb +31 -0
- data/lib/mindee/parsing/error.rb +22 -0
- data/lib/mindee/parsing/inference.rb +53 -0
- data/lib/mindee/parsing/page.rb +46 -0
- data/lib/mindee/parsing/prediction/base.rb +30 -0
- data/lib/mindee/{fields → parsing/prediction/common_fields}/amount.rb +5 -1
- data/lib/mindee/{fields → parsing/prediction/common_fields}/base.rb +16 -5
- data/lib/mindee/{fields → parsing/prediction/common_fields}/company_registration.rb +0 -0
- data/lib/mindee/{fields/datefield.rb → parsing/prediction/common_fields/date.rb} +0 -0
- data/lib/mindee/{fields → parsing/prediction/common_fields}/locale.rb +0 -0
- data/lib/mindee/{fields → parsing/prediction/common_fields}/payment_details.rb +0 -0
- data/lib/mindee/parsing/prediction/common_fields/position.rb +39 -0
- data/lib/mindee/{fields → parsing/prediction/common_fields}/tax.rb +7 -2
- data/lib/mindee/parsing/prediction/common_fields/text.rb +12 -0
- data/lib/mindee/parsing/prediction/common_fields.rb +11 -0
- data/lib/mindee/parsing/prediction/custom/custom_v1.rb +58 -0
- data/lib/mindee/{fields/custom_docs.rb → parsing/prediction/custom/fields.rb} +5 -5
- data/lib/mindee/parsing/prediction/eu/license_plate/license_plate_v1.rb +34 -0
- data/lib/mindee/parsing/prediction/fr/bank_account_details/bank_account_details_v1.rb +40 -0
- data/lib/mindee/parsing/prediction/fr/carte_vitale/carte_vitale_v1.rb +49 -0
- data/lib/mindee/parsing/prediction/fr/id_card/id_card_v1.rb +84 -0
- data/lib/mindee/parsing/prediction/invoice/invoice_line_item.rb +58 -0
- data/lib/mindee/parsing/prediction/invoice/invoice_v4.rb +216 -0
- data/lib/mindee/parsing/prediction/passport/passport_v1.rb +184 -0
- data/lib/mindee/parsing/prediction/receipt/receipt_v4.rb +84 -0
- data/lib/mindee/parsing/prediction/shipping_container/shipping_container_v1.rb +38 -0
- data/lib/mindee/parsing/prediction/us/bank_check/bank_check_v1.rb +70 -0
- data/lib/mindee/parsing/prediction.rb +12 -0
- data/lib/mindee/parsing.rb +4 -0
- data/lib/mindee/version.rb +1 -1
- data/mindee.gemspec +2 -1
- metadata +57 -24
- data/lib/mindee/documents/base.rb +0 -35
- data/lib/mindee/documents/custom.rb +0 -65
- data/lib/mindee/documents/financial_doc.rb +0 -135
- data/lib/mindee/documents/invoice.rb +0 -162
- data/lib/mindee/documents/passport.rb +0 -163
- data/lib/mindee/documents/receipt.rb +0 -109
- data/lib/mindee/documents.rb +0 -7
- data/lib/mindee/endpoint.rb +0 -105
- data/lib/mindee/fields/orientation.rb +0 -26
- data/lib/mindee/fields.rb +0 -11
- data/lib/mindee/inputs.rb +0 -153
- data/lib/mindee/response.rb +0 -27
@@ -1,135 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../fields'
|
4
|
-
require_relative 'base'
|
5
|
-
require_relative 'invoice'
|
6
|
-
require_relative 'receipt'
|
7
|
-
|
8
|
-
module Mindee
|
9
|
-
# Union of `Invoice` and `Receipt`.
|
10
|
-
class FinancialDocument < Document
|
11
|
-
# @return [Mindee::Locale]
|
12
|
-
attr_reader :locale
|
13
|
-
# @return [Mindee::Amount]
|
14
|
-
attr_reader :total_incl
|
15
|
-
# @return [Mindee::Amount]
|
16
|
-
attr_reader :total_excl
|
17
|
-
# @return [Mindee::Amount]
|
18
|
-
attr_reader :total_tax
|
19
|
-
# @return [Mindee::DateField]
|
20
|
-
attr_reader :date
|
21
|
-
# @return [Mindee::Field]
|
22
|
-
attr_reader :category
|
23
|
-
# @return [Mindee::Field]
|
24
|
-
attr_reader :invoice_number
|
25
|
-
# @return [Mindee::Field]
|
26
|
-
attr_reader :time
|
27
|
-
# @return [Mindee::DateField]
|
28
|
-
attr_reader :due_date
|
29
|
-
# @return [Array<Mindee::TaxField>]
|
30
|
-
attr_reader :taxes
|
31
|
-
# @return [Mindee::Field]
|
32
|
-
attr_reader :supplier
|
33
|
-
# @return [Mindee::Field]
|
34
|
-
attr_reader :supplier_address
|
35
|
-
# @return [Mindee::Field]
|
36
|
-
attr_reader :customer_name
|
37
|
-
# @return [Mindee::Field]
|
38
|
-
attr_reader :customer_address
|
39
|
-
# @return [Array<Mindee::CompanyRegistration>]
|
40
|
-
attr_reader :company_registration
|
41
|
-
# @return [Array<Mindee::CompanyRegistration>]
|
42
|
-
attr_reader :customer_company_registration
|
43
|
-
# @return [Array<Mindee::PaymentDetails>]
|
44
|
-
attr_reader :payment_details
|
45
|
-
|
46
|
-
# @param prediction [Hash]
|
47
|
-
# @param input_file [Mindee::InputDocument, nil]
|
48
|
-
# @param page_id [Integer, nil]
|
49
|
-
def initialize(prediction, input_file: nil, page_id: nil)
|
50
|
-
super('financial_doc', input_file: input_file)
|
51
|
-
@locale = Locale.new(prediction['locale'])
|
52
|
-
if prediction.include? 'invoice_number'
|
53
|
-
build_from_invoice(
|
54
|
-
Invoice.new(prediction, input_file: input_file, page_id: page_id)
|
55
|
-
)
|
56
|
-
else
|
57
|
-
build_from_receipt(
|
58
|
-
Receipt.new(prediction, input_file: input_file, page_id: page_id)
|
59
|
-
)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def to_s
|
64
|
-
customer_company_registration = @customer_company_registration.map(&:value).join('; ')
|
65
|
-
payment_details = @payment_details.map(&:to_s).join("\n ")
|
66
|
-
company_registration = @company_registration.map(&:to_s).join('; ')
|
67
|
-
taxes = @taxes.join("\n ")
|
68
|
-
out_str = String.new
|
69
|
-
out_str << '-----Financial Document data-----'
|
70
|
-
out_str << "\nFilename: #{@filename}".rstrip
|
71
|
-
out_str << "\nCategory: #{@category}".rstrip
|
72
|
-
out_str << "\nInvoice number: #{@invoice_number}".rstrip
|
73
|
-
out_str << "\nTotal amount including taxes: #{@total_incl}".rstrip
|
74
|
-
out_str << "\nTotal amount excluding taxes: #{@total_excl}".rstrip
|
75
|
-
out_str << "\nInvoice date: #{@date}".rstrip
|
76
|
-
out_str << "\nInvoice due date: #{@due_date}".rstrip
|
77
|
-
out_str << "\nSupplier name: #{@supplier}".rstrip
|
78
|
-
out_str << "\nSupplier address: #{@supplier_address}".rstrip
|
79
|
-
out_str << "\nCustomer name: #{@customer_name}".rstrip
|
80
|
-
out_str << "\nCustomer company registration: #{customer_company_registration}".rstrip
|
81
|
-
out_str << "\nCustomer address: #{@customer_address}".rstrip
|
82
|
-
out_str << "\nPayment details: #{payment_details}".rstrip
|
83
|
-
out_str << "\nCompany numbers: #{company_registration}".rstrip
|
84
|
-
out_str << "\nTaxes: #{taxes}".rstrip
|
85
|
-
out_str << "\nTotal taxes: #{@total_tax}".rstrip
|
86
|
-
out_str << "\nTime: #{@time}".rstrip
|
87
|
-
out_str << "\nLocale: #{@locale}".rstrip
|
88
|
-
out_str << "\n----------------------"
|
89
|
-
out_str
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
93
|
-
|
94
|
-
# @param invoice [Mindee::Invoice]
|
95
|
-
def build_from_invoice(invoice)
|
96
|
-
@orientation = invoice.orientation
|
97
|
-
@category = empty_field
|
98
|
-
@total_incl = invoice.total_incl
|
99
|
-
@total_excl = invoice.total_excl
|
100
|
-
@total_tax = invoice.total_tax
|
101
|
-
@date = invoice.date
|
102
|
-
@time = empty_field
|
103
|
-
@due_date = invoice.due_date
|
104
|
-
@invoice_number = invoice.invoice_number
|
105
|
-
@taxes = invoice.taxes
|
106
|
-
@supplier = invoice.supplier
|
107
|
-
@supplier_address = invoice.supplier_address
|
108
|
-
@company_registration = invoice.company_registration
|
109
|
-
@customer_company_registration = invoice.customer_company_registration
|
110
|
-
@payment_details = invoice.payment_details
|
111
|
-
end
|
112
|
-
|
113
|
-
# @param receipt [Mindee::Receipt]
|
114
|
-
def build_from_receipt(receipt)
|
115
|
-
@orientation = receipt.orientation
|
116
|
-
@category = receipt.category
|
117
|
-
@total_incl = receipt.total_incl
|
118
|
-
@total_excl = receipt.total_excl
|
119
|
-
@total_tax = receipt.total_tax
|
120
|
-
@date = receipt.date
|
121
|
-
@time = receipt.time
|
122
|
-
@due_date = empty_field
|
123
|
-
@taxes = receipt.taxes
|
124
|
-
@supplier = receipt.supplier
|
125
|
-
@supplier_address = empty_field
|
126
|
-
@company_registration = empty_field
|
127
|
-
@customer_company_registration = empty_field
|
128
|
-
@payment_details = empty_field
|
129
|
-
end
|
130
|
-
|
131
|
-
def empty_field
|
132
|
-
Mindee::Field.new({}, nil)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
@@ -1,162 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../fields'
|
4
|
-
require_relative 'base'
|
5
|
-
|
6
|
-
module Mindee
|
7
|
-
# Invoice document.
|
8
|
-
class Invoice < Document
|
9
|
-
# @return [Mindee::Locale]
|
10
|
-
attr_reader :locale
|
11
|
-
# @return [Mindee::Amount]
|
12
|
-
attr_reader :total_incl
|
13
|
-
# @return [Mindee::Amount]
|
14
|
-
attr_reader :total_excl
|
15
|
-
# @return [Mindee::Amount]
|
16
|
-
attr_reader :total_tax
|
17
|
-
# @return [Mindee::DateField]
|
18
|
-
attr_reader :date
|
19
|
-
# @return [Mindee::Field]
|
20
|
-
attr_reader :invoice_number
|
21
|
-
# @return [Mindee::DateField]
|
22
|
-
attr_reader :due_date
|
23
|
-
# @return [Array<Mindee::TaxField>]
|
24
|
-
attr_reader :taxes
|
25
|
-
# @return [Array<Mindee::CompanyRegistration>]
|
26
|
-
attr_reader :customer_company_registration
|
27
|
-
# @return [Array<Mindee::PaymentDetails>]
|
28
|
-
attr_reader :payment_details
|
29
|
-
# @return [Array<Mindee::CompanyRegistration>]
|
30
|
-
attr_reader :company_registration
|
31
|
-
# @return [Mindee::Field]
|
32
|
-
attr_reader :customer_name
|
33
|
-
# @return [Mindee::Field]
|
34
|
-
attr_reader :supplier
|
35
|
-
# @return [Mindee::Field]
|
36
|
-
attr_reader :supplier_address
|
37
|
-
# @return [Mindee::Field]
|
38
|
-
attr_reader :customer_address
|
39
|
-
# @return [Mindee::Orientation]
|
40
|
-
attr_reader :orientation
|
41
|
-
|
42
|
-
# @param prediction [Hash]
|
43
|
-
# @param input_file [Mindee::InputDocument, nil]
|
44
|
-
# @param page_id [Integer, nil]
|
45
|
-
def initialize(prediction, input_file: nil, page_id: nil)
|
46
|
-
super('invoice', input_file: input_file)
|
47
|
-
@orientation = Orientation.new(prediction['orientation'], page_id) if page_id
|
48
|
-
@locale = Locale.new(prediction['locale'])
|
49
|
-
@total_incl = Amount.new(prediction['total_incl'], page_id)
|
50
|
-
@total_excl = Amount.new(prediction['total_excl'], page_id)
|
51
|
-
@customer_address = Field.new(prediction['customer_address'], page_id)
|
52
|
-
@customer_name = Field.new(prediction['customer'], page_id)
|
53
|
-
@date = DateField.new(prediction['date'], page_id)
|
54
|
-
@due_date = DateField.new(prediction['due_date'], page_id)
|
55
|
-
@invoice_number = Field.new(prediction['invoice_number'], page_id)
|
56
|
-
@supplier = Field.new(prediction['supplier'], page_id)
|
57
|
-
@supplier_address = Field.new(prediction['supplier_address'], page_id)
|
58
|
-
|
59
|
-
@customer_company_registration = []
|
60
|
-
prediction['customer_company_registration'].each do |item|
|
61
|
-
@customer_company_registration.push(CompanyRegistration.new(item, page_id))
|
62
|
-
end
|
63
|
-
@taxes = []
|
64
|
-
prediction['taxes'].each do |item|
|
65
|
-
@taxes.push(TaxField.new(item, page_id))
|
66
|
-
end
|
67
|
-
@payment_details = []
|
68
|
-
prediction['payment_details'].each do |item|
|
69
|
-
@payment_details.push(PaymentDetails.new(item, page_id))
|
70
|
-
end
|
71
|
-
@company_registration = []
|
72
|
-
prediction['company_registration'].each do |item|
|
73
|
-
@company_registration.push(CompanyRegistration.new(item, page_id))
|
74
|
-
end
|
75
|
-
|
76
|
-
@total_tax = Amount.new(
|
77
|
-
{ value: nil, confidence: 0.0 }, page_id
|
78
|
-
)
|
79
|
-
reconstruct(page_id)
|
80
|
-
end
|
81
|
-
|
82
|
-
def to_s
|
83
|
-
customer_company_registration = @customer_company_registration.map(&:value).join('; ')
|
84
|
-
payment_details = @payment_details.map(&:to_s).join("\n ")
|
85
|
-
company_registration = @company_registration.map(&:to_s).join('; ')
|
86
|
-
taxes = @taxes.join("\n ")
|
87
|
-
out_str = String.new
|
88
|
-
out_str << '----- Invoice V3 -----'
|
89
|
-
out_str << "\nFilename: #{@filename}".rstrip
|
90
|
-
out_str << "\nInvoice number: #{@invoice_number}".rstrip
|
91
|
-
out_str << "\nTotal amount including taxes: #{@total_incl}".rstrip
|
92
|
-
out_str << "\nTotal amount excluding taxes: #{@total_excl}".rstrip
|
93
|
-
out_str << "\nInvoice date: #{@date}".rstrip
|
94
|
-
out_str << "\nInvoice due date: #{@due_date}".rstrip
|
95
|
-
out_str << "\nSupplier name: #{@supplier}".rstrip
|
96
|
-
out_str << "\nSupplier address: #{@supplier_address}".rstrip
|
97
|
-
out_str << "\nCustomer name: #{@customer_name}".rstrip
|
98
|
-
out_str << "\nCustomer company registration: #{customer_company_registration}".rstrip
|
99
|
-
out_str << "\nCustomer address: #{@customer_address}".rstrip
|
100
|
-
out_str << "\nPayment details: #{payment_details}".rstrip
|
101
|
-
out_str << "\nCompany numbers: #{company_registration}".rstrip
|
102
|
-
out_str << "\nTaxes: #{taxes}".rstrip
|
103
|
-
out_str << "\nTotal taxes: #{@total_tax}".rstrip
|
104
|
-
out_str << "\nLocale: #{@locale}".rstrip
|
105
|
-
out_str << "\n----------------------"
|
106
|
-
out_str
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
def reconstruct(page_id)
|
112
|
-
construct_total_tax_from_taxes(page_id)
|
113
|
-
construct_total_excl_from_tcc_and_taxes(page_id)
|
114
|
-
construct_total_incl_from_taxes_plus_excl(page_id)
|
115
|
-
construct_total_tax_from_totals(page_id)
|
116
|
-
end
|
117
|
-
|
118
|
-
def construct_total_excl_from_tcc_and_taxes(page_id)
|
119
|
-
return if @total_incl.value.nil? || taxes.empty? || !@total_excl.value.nil?
|
120
|
-
|
121
|
-
total_excl = {
|
122
|
-
'value' => @total_incl.value - @taxes.map(&:value).sum,
|
123
|
-
'confidence' => Field.array_confidence(@taxes) * @total_incl.confidence,
|
124
|
-
}
|
125
|
-
@total_excl = Amount.new(total_excl, page_id, reconstructed: true)
|
126
|
-
end
|
127
|
-
|
128
|
-
def construct_total_incl_from_taxes_plus_excl(page_id)
|
129
|
-
return if @total_excl.value.nil? || @taxes.empty? || !@total_incl.value.nil?
|
130
|
-
|
131
|
-
total_incl = {
|
132
|
-
'value' => @taxes.map(&:value).sum + @total_excl.value,
|
133
|
-
'confidence' => Field.array_confidence(@taxes) * @total_excl.confidence,
|
134
|
-
}
|
135
|
-
@total_incl = Amount.new(total_incl, page_id, reconstructed: true)
|
136
|
-
end
|
137
|
-
|
138
|
-
def construct_total_tax_from_taxes(page_id)
|
139
|
-
return if @taxes.empty?
|
140
|
-
|
141
|
-
total_tax = {
|
142
|
-
'value' => @taxes.map(&:value).sum,
|
143
|
-
'confidence' => Field.array_confidence(@taxes),
|
144
|
-
}
|
145
|
-
return unless total_tax['value'].positive?
|
146
|
-
|
147
|
-
@total_tax = Amount.new(total_tax, page_id, reconstructed: true)
|
148
|
-
end
|
149
|
-
|
150
|
-
def construct_total_tax_from_totals(page_id)
|
151
|
-
return if !@total_tax.value.nil? || @total_incl.value.nil? || @total_excl.value.nil?
|
152
|
-
|
153
|
-
total_tax = {
|
154
|
-
'value' => @total_incl.value - @total_excl.value,
|
155
|
-
'confidence' => Field.array_confidence(@taxes),
|
156
|
-
}
|
157
|
-
return unless total_tax['value'] >= 0
|
158
|
-
|
159
|
-
@total_tax = Amount.new(total_tax, page_id, reconstructed: true)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
@@ -1,163 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'mrz'
|
4
|
-
|
5
|
-
require_relative '../fields'
|
6
|
-
require_relative 'base'
|
7
|
-
|
8
|
-
# We need to do this disgusting thing to avoid the following error message:
|
9
|
-
# td3 line one does not match the required format (MRZ::InvalidFormatError)
|
10
|
-
#
|
11
|
-
# See:
|
12
|
-
# https://github.com/streetspotr/mrz/issues/2
|
13
|
-
# https://github.com/streetspotr/mrz/pull/3
|
14
|
-
#
|
15
|
-
MRZ::TD3Parser::FORMAT_ONE = %r{\A(.{2})(.{3})([^<]+)<(.*)\z}.freeze
|
16
|
-
|
17
|
-
module Mindee
|
18
|
-
# Passport document.
|
19
|
-
class Passport < Document
|
20
|
-
# @return [Mindee::Orientation]
|
21
|
-
attr_reader :orientation
|
22
|
-
attr_reader :country,
|
23
|
-
:id_number,
|
24
|
-
:expiry_date,
|
25
|
-
:issuance_date,
|
26
|
-
:surname,
|
27
|
-
:given_names,
|
28
|
-
:full_name,
|
29
|
-
:birth_date,
|
30
|
-
:birth_place,
|
31
|
-
:gender,
|
32
|
-
:mrz1,
|
33
|
-
:mrz2,
|
34
|
-
:mrz
|
35
|
-
|
36
|
-
# @param prediction [Hash]
|
37
|
-
# @param input_file [Mindee::InputDocument, nil]
|
38
|
-
# @param page_id [Integer, nil]
|
39
|
-
def initialize(prediction, input_file: nil, page_id: nil)
|
40
|
-
super('passport', input_file: input_file)
|
41
|
-
@orientation = Orientation.new(prediction['orientation'], page_id) if page_id
|
42
|
-
@country = Field.new(prediction['country'], page_id)
|
43
|
-
@id_number = Field.new(prediction['id_number'], page_id)
|
44
|
-
@birth_date = DateField.new(prediction['birth_date'], page_id)
|
45
|
-
@expiry_date = DateField.new(prediction['expiry_date'], page_id)
|
46
|
-
@issuance_date = DateField.new(prediction['issuance_date'], page_id)
|
47
|
-
@birth_place = Field.new(prediction['birth_place'], page_id)
|
48
|
-
@gender = Field.new(prediction['gender'], page_id)
|
49
|
-
@surname = Field.new(prediction['surname'], page_id)
|
50
|
-
@mrz1 = Field.new(prediction['mrz1'], page_id)
|
51
|
-
@mrz2 = Field.new(prediction['mrz2'], page_id)
|
52
|
-
@given_names = []
|
53
|
-
prediction['given_names'].each do |item|
|
54
|
-
@given_names.push(Field.new(item, page_id))
|
55
|
-
end
|
56
|
-
@full_name = construct_full_name(page_id)
|
57
|
-
@mrz = construct_mrz(page_id)
|
58
|
-
check_mrz
|
59
|
-
end
|
60
|
-
|
61
|
-
def to_s
|
62
|
-
given_names = @given_names.join(' ')
|
63
|
-
out_str = String.new
|
64
|
-
out_str << '-----Passport data-----'
|
65
|
-
out_str << "\nFilename: #{@filename}".rstrip
|
66
|
-
out_str << "\nFull name: #{@full_name}".rstrip
|
67
|
-
out_str << "\nGiven names: #{given_names}".rstrip
|
68
|
-
out_str << "\nSurname: #{@surname}".rstrip
|
69
|
-
out_str << "\nCountry: #{@country}".rstrip
|
70
|
-
out_str << "\nID Number: #{@id_number}".rstrip
|
71
|
-
out_str << "\nIssuance date: #{@issuance_date}".rstrip
|
72
|
-
out_str << "\nBirth date: #{@birth_date}".rstrip
|
73
|
-
out_str << "\nExpiry date: #{@expiry_date}".rstrip
|
74
|
-
out_str << "\nMRZ 1: #{@mrz1}".rstrip
|
75
|
-
out_str << "\nMRZ 2: #{@mrz2}".rstrip
|
76
|
-
out_str << "\nMRZ: #{@mrz}".rstrip
|
77
|
-
out_str << "\n----------------------"
|
78
|
-
out_str
|
79
|
-
end
|
80
|
-
|
81
|
-
# @return [Boolean]
|
82
|
-
def expired?
|
83
|
-
return true unless @expiry_date.date_object
|
84
|
-
|
85
|
-
@expiry_date.date_object < Date.today
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
def check_mrz
|
91
|
-
return if @mrz1.value.nil? || @mrz2.value.nil?
|
92
|
-
|
93
|
-
mrz = MRZ.parse([@mrz1.value, @mrz2.value])
|
94
|
-
checks = {
|
95
|
-
mrz_valid: valid_mrz?(mrz),
|
96
|
-
mrz_valid_birth_date: valid_birth_date?(mrz),
|
97
|
-
mrz_valid_expiry_date: valid_expiry_date?(mrz),
|
98
|
-
mrz_valid_id_number: valid_id_number?(mrz),
|
99
|
-
mrz_valid_surname: valid_surname?(mrz),
|
100
|
-
mrz_valid_country: valid_country?(mrz),
|
101
|
-
}
|
102
|
-
@checklist.merge!(checks)
|
103
|
-
end
|
104
|
-
|
105
|
-
def valid_mrz?(mrz)
|
106
|
-
check = mrz.valid?
|
107
|
-
@mrz.confidence = 1.0 if check
|
108
|
-
check
|
109
|
-
end
|
110
|
-
|
111
|
-
def valid_birth_date?(mrz)
|
112
|
-
check = mrz.valid_birth_date? && mrz.birth_date == @birth_date.date_object
|
113
|
-
@birth_date.confidence = 1.0 if check
|
114
|
-
check
|
115
|
-
end
|
116
|
-
|
117
|
-
def valid_expiry_date?(mrz)
|
118
|
-
check = mrz.valid_expiration_date? && mrz.expiration_date == @expiry_date.date_object
|
119
|
-
@expiry_date.confidence = 1.0 if check
|
120
|
-
check
|
121
|
-
end
|
122
|
-
|
123
|
-
def valid_id_number?(mrz)
|
124
|
-
check = mrz.valid_document_number? && mrz.document_number == @id_number.value
|
125
|
-
@id_number.confidence = 1.0 if check
|
126
|
-
check
|
127
|
-
end
|
128
|
-
|
129
|
-
def valid_surname?(mrz)
|
130
|
-
check = mrz.last_name == @surname.value
|
131
|
-
@surname.confidence = 1.0 if check
|
132
|
-
check
|
133
|
-
end
|
134
|
-
|
135
|
-
def valid_country?(mrz)
|
136
|
-
check = mrz.nationality == @country.value
|
137
|
-
@country.confidence = 1.0 if check
|
138
|
-
check
|
139
|
-
end
|
140
|
-
|
141
|
-
def construct_full_name(page_id)
|
142
|
-
return unless @surname.value &&
|
143
|
-
!@given_names.empty? &&
|
144
|
-
@given_names[0].value
|
145
|
-
|
146
|
-
full_name = {
|
147
|
-
'value' => "#{@given_names[0].value} #{@surname.value}",
|
148
|
-
'confidence' => Field.array_confidence([@surname, @given_names[0]]),
|
149
|
-
}
|
150
|
-
Field.new(full_name, page_id, reconstructed: true)
|
151
|
-
end
|
152
|
-
|
153
|
-
def construct_mrz(page_id)
|
154
|
-
return if @mrz1.value.nil? || @mrz2.value.nil?
|
155
|
-
|
156
|
-
mrz = {
|
157
|
-
'value' => @mrz1.value + @mrz2.value,
|
158
|
-
'confidence' => Field.array_confidence([@mrz1, @mrz2]),
|
159
|
-
}
|
160
|
-
Field.new(mrz, page_id, reconstructed: true)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
end
|
@@ -1,109 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../fields'
|
4
|
-
require_relative 'base'
|
5
|
-
|
6
|
-
module Mindee
|
7
|
-
# Receipt document.
|
8
|
-
class Receipt < Document
|
9
|
-
# @return [Mindee::Locale]
|
10
|
-
attr_reader :locale
|
11
|
-
# @return [Mindee::Amount]
|
12
|
-
attr_reader :total_incl
|
13
|
-
# @return [Mindee::Amount]
|
14
|
-
attr_reader :total_excl
|
15
|
-
# @return [Mindee::Amount]
|
16
|
-
attr_reader :total_tax
|
17
|
-
# @return [Mindee::DateField]
|
18
|
-
attr_reader :date
|
19
|
-
# @return [Mindee::Field]
|
20
|
-
attr_reader :supplier
|
21
|
-
# @return [Array<Mindee::TaxField>]
|
22
|
-
attr_reader :taxes
|
23
|
-
# @return [Mindee::Orientation]
|
24
|
-
attr_reader :orientation
|
25
|
-
# @return [Mindee::Field]
|
26
|
-
attr_reader :time
|
27
|
-
# @return [Mindee::Field]
|
28
|
-
attr_reader :category
|
29
|
-
|
30
|
-
# @param prediction [Hash]
|
31
|
-
# @param input_file [Mindee::InputDocument, nil]
|
32
|
-
# @param page_id [Integer, nil]
|
33
|
-
def initialize(prediction, input_file: nil, page_id: nil)
|
34
|
-
super('receipt', input_file: input_file)
|
35
|
-
@orientation = Orientation.new(prediction['orientation'], page_id) if page_id
|
36
|
-
@locale = Locale.new(prediction['locale'])
|
37
|
-
@total_incl = Amount.new(prediction['total_incl'], page_id)
|
38
|
-
@date = DateField.new(prediction['date'], page_id)
|
39
|
-
@category = Field.new(prediction['category'], page_id)
|
40
|
-
@supplier = Field.new(prediction['supplier'], page_id)
|
41
|
-
@time = Field.new(prediction['time'], page_id)
|
42
|
-
@taxes = []
|
43
|
-
prediction['taxes'].each do |item|
|
44
|
-
@taxes.push(TaxField.new(item, page_id))
|
45
|
-
end
|
46
|
-
|
47
|
-
@total_tax = Amount.new(
|
48
|
-
{ value: nil, confidence: 0.0 }, page_id
|
49
|
-
)
|
50
|
-
@total_excl = Amount.new(
|
51
|
-
{ value: nil, confidence: 0.0 }, page_id
|
52
|
-
)
|
53
|
-
reconstruct(page_id)
|
54
|
-
end
|
55
|
-
|
56
|
-
def to_s
|
57
|
-
taxes = @taxes.join("\n ")
|
58
|
-
out_str = String.new
|
59
|
-
out_str << '-----Receipt data-----'
|
60
|
-
out_str << "\nFilename: #{@filename}".rstrip
|
61
|
-
out_str << "\nTotal amount including taxes: #{@total_incl}".rstrip
|
62
|
-
out_str << "\nTotal amount excluding taxes: #{@total_excl}".rstrip
|
63
|
-
out_str << "\nDate: #{@date}".rstrip
|
64
|
-
out_str << "\nCategory: #{@category}".rstrip
|
65
|
-
out_str << "\nTime: #{@time}".rstrip
|
66
|
-
out_str << "\nMerchant name: #{@supplier}".rstrip
|
67
|
-
out_str << "\nTaxes: #{taxes}".rstrip
|
68
|
-
out_str << "\nTotal taxes: #{@total_tax}".rstrip
|
69
|
-
out_str << "\nLocale: #{@locale}".rstrip
|
70
|
-
out_str << "\n----------------------"
|
71
|
-
out_str
|
72
|
-
end
|
73
|
-
|
74
|
-
private
|
75
|
-
|
76
|
-
def reconstruct(page_id)
|
77
|
-
construct_total_tax_from_taxes(page_id)
|
78
|
-
construct_total_excl(page_id)
|
79
|
-
end
|
80
|
-
|
81
|
-
def construct_total_tax_from_taxes(page_id)
|
82
|
-
return if @taxes.empty? || !@total_tax.value.nil?
|
83
|
-
|
84
|
-
total_tax = {
|
85
|
-
'value' => @taxes.map do |tax|
|
86
|
-
if tax.value.nil?
|
87
|
-
0
|
88
|
-
else
|
89
|
-
tax.value
|
90
|
-
end
|
91
|
-
end.sum,
|
92
|
-
'confidence' => Field.array_confidence(@taxes),
|
93
|
-
}
|
94
|
-
return unless total_tax['value'].positive?
|
95
|
-
|
96
|
-
@total_tax = Amount.new(total_tax, page_id, reconstructed: true)
|
97
|
-
end
|
98
|
-
|
99
|
-
def construct_total_excl(page_id)
|
100
|
-
return if @taxes.empty? || @total_incl.value.nil?
|
101
|
-
|
102
|
-
total_excl = {
|
103
|
-
'value' => @total_incl.value - Field.array_sum(@taxes),
|
104
|
-
'confidence' => Field.array_confidence(@taxes) * @total_incl.confidence,
|
105
|
-
}
|
106
|
-
@total_excl = Amount.new(total_excl, page_id, reconstructed: true)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
data/lib/mindee/documents.rb
DELETED
data/lib/mindee/endpoint.rb
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'net/http'
|
4
|
-
require_relative 'version'
|
5
|
-
|
6
|
-
module Mindee
|
7
|
-
MINDEE_API_URL = 'https://api.mindee.net/v1'
|
8
|
-
USER_AGENT = "mindee-api-ruby@v#{Mindee::VERSION} ruby-v#{RUBY_VERSION} #{Mindee::PLATFORM}"
|
9
|
-
|
10
|
-
INVOICE_VERSION = '3'
|
11
|
-
INVOICE_URL_NAME = 'invoices'
|
12
|
-
|
13
|
-
RECEIPT_VERSION = '3'
|
14
|
-
RECEIPT_URL_NAME = 'expense_receipts'
|
15
|
-
|
16
|
-
PASSPORT_VERSION = '1'
|
17
|
-
PASSPORT_URL_NAME = 'passport'
|
18
|
-
|
19
|
-
# Generic API endpoint for a product.
|
20
|
-
class Endpoint
|
21
|
-
attr_reader :api_key
|
22
|
-
|
23
|
-
def initialize(owner, url_name, version, key_name: nil, api_key: nil)
|
24
|
-
@owner = owner
|
25
|
-
@url_name = url_name
|
26
|
-
@version = version
|
27
|
-
@key_name = key_name || url_name
|
28
|
-
@api_key = api_key || set_api_key_from_env
|
29
|
-
@url_root = "#{MINDEE_API_URL}/products/#{@owner}/#{@url_name}/v#{@version}"
|
30
|
-
end
|
31
|
-
|
32
|
-
# @param input_doc [Mindee::InputDocument]
|
33
|
-
# @param include_words [Boolean]
|
34
|
-
# @param close_file [Boolean]
|
35
|
-
# @return [Net::HTTPResponse]
|
36
|
-
def predict_request(input_doc, include_words: false, close_file: true)
|
37
|
-
uri = URI("#{@url_root}/predict")
|
38
|
-
headers = {
|
39
|
-
'Authorization' => "Token #{@api_key}",
|
40
|
-
'User-Agent' => USER_AGENT,
|
41
|
-
}
|
42
|
-
req = Net::HTTP::Post.new(uri, headers)
|
43
|
-
|
44
|
-
params = {
|
45
|
-
'document' => input_doc.read_document(close: close_file),
|
46
|
-
}
|
47
|
-
params.push ['include_mvision', 'true'] if include_words
|
48
|
-
|
49
|
-
req.set_form(params, 'multipart/form-data')
|
50
|
-
|
51
|
-
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
52
|
-
http.request(req)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def envvar_key_name
|
57
|
-
key_name = to_envar(@key_name)
|
58
|
-
key_name = "#{to_envar(@owner)}_#{key_name}" if @owner != 'mindee'
|
59
|
-
"MINDEE_#{key_name}_API_KEY"
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
# Create a standard way to get/set environment variable names.
|
65
|
-
def to_envar(name)
|
66
|
-
name.sub('-', '_').upcase
|
67
|
-
end
|
68
|
-
|
69
|
-
# Set the endpoint's API key from an environment variable, if present.
|
70
|
-
# We look first for the specific key, if not set, we'll use the generic key
|
71
|
-
def set_api_key_from_env
|
72
|
-
env_key = ENV.fetch(envvar_key_name, nil)
|
73
|
-
env_key = ENV.fetch('MINDEE_API_KEY', nil) if env_key.nil?
|
74
|
-
@api_key = env_key if env_key
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# Invoice API endpoint
|
79
|
-
class InvoiceEndpoint < Endpoint
|
80
|
-
def initialize(api_key)
|
81
|
-
super('mindee', INVOICE_URL_NAME, INVOICE_VERSION, key_name: 'invoice', api_key: api_key)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# Receipt API endpoint
|
86
|
-
class ReceiptEndpoint < Endpoint
|
87
|
-
def initialize(api_key)
|
88
|
-
super('mindee', RECEIPT_URL_NAME, RECEIPT_VERSION, key_name: 'receipt', api_key: api_key)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# Passport API endpoint
|
93
|
-
class PassportEndpoint < Endpoint
|
94
|
-
def initialize(api_key)
|
95
|
-
super('mindee', PASSPORT_URL_NAME, PASSPORT_VERSION, api_key: api_key)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
# Custom (constructed) API endpoint
|
100
|
-
class CustomEndpoint < Endpoint
|
101
|
-
def initialize(document_type, account_name, version, api_key)
|
102
|
-
super(account_name, document_type, version, api_key: api_key)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|