mindee 1.1.2 → 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 +25 -0
- data/Gemfile +0 -7
- data/README.md +52 -21
- 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 +11 -5
- metadata +105 -30
- 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,65 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../fields'
|
4
|
-
require_relative 'base'
|
5
|
-
|
6
|
-
module Mindee
|
7
|
-
# Custom document object.
|
8
|
-
class CustomDocument < Document
|
9
|
-
# All value fields in the document
|
10
|
-
# @return [Hash<Symbol, Mindee::ListField>]
|
11
|
-
attr_reader :fields
|
12
|
-
# All classifications in the document
|
13
|
-
# @return [Hash<Symbol, Mindee::ClassificationField>]
|
14
|
-
attr_reader :classifications
|
15
|
-
|
16
|
-
# @param document_type [String]
|
17
|
-
# @param prediction [Hash]
|
18
|
-
# @param input_file [Mindee::InputDocument, nil]
|
19
|
-
# @param page_id [Integer, nil]
|
20
|
-
def initialize(document_type, prediction, input_file: nil, page_id: nil)
|
21
|
-
super(document_type, input_file: input_file)
|
22
|
-
@fields = {}
|
23
|
-
@classifications = {}
|
24
|
-
prediction.each do |field_name, field_prediction|
|
25
|
-
field_sym = field_name.to_sym
|
26
|
-
complete_field = set_field(field_sym, field_prediction, page_id)
|
27
|
-
|
28
|
-
# Create a dynamic accessor function for the field
|
29
|
-
singleton_class.module_eval { attr_accessor field_sym }
|
30
|
-
send("#{field_sym}=", complete_field)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def to_s
|
35
|
-
out_str = String.new
|
36
|
-
out_str << "----- #{@document_type} -----"
|
37
|
-
out_str << "\nFilename: #{@filename}".rstrip
|
38
|
-
@classifications.each do |name, info|
|
39
|
-
out_str << "\n#{name}: #{info}".rstrip
|
40
|
-
end
|
41
|
-
@fields.each do |name, info|
|
42
|
-
out_str << "\n#{name}: #{info}".rstrip
|
43
|
-
end
|
44
|
-
out_str << "\n----------------------"
|
45
|
-
out_str
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
# @param field_prediction [Hash]
|
51
|
-
def set_field(field_sym, field_prediction, page_id)
|
52
|
-
# Currently two types of fields possible in a custom API response:
|
53
|
-
# fields having a list of values, and classification fields.
|
54
|
-
# Here we use the fact that only value lists have the 'values' attribute.
|
55
|
-
|
56
|
-
if field_prediction.key? 'values'
|
57
|
-
@fields[field_sym] = ListField.new(field_prediction, page_id)
|
58
|
-
elsif field_prediction.key? 'value'
|
59
|
-
@classifications[field_sym] = ClassificationField.new(field_prediction)
|
60
|
-
else
|
61
|
-
throw 'Unknown API field type'
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -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