mindee 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.rubocop.yml +2 -2
  4. data/.yardopts +4 -0
  5. data/CHANGELOG.md +21 -0
  6. data/README.md +46 -23
  7. data/Rakefile +6 -1
  8. data/bin/mindee.rb +70 -61
  9. data/docs/ruby-api-builder.md +131 -0
  10. data/docs/ruby-getting-started.md +265 -0
  11. data/docs/ruby-invoice-ocr.md +261 -0
  12. data/docs/ruby-passport-ocr.md +156 -0
  13. data/docs/ruby-receipt-ocr.md +170 -0
  14. data/lib/mindee/client.rb +128 -93
  15. data/lib/mindee/document_config.rb +22 -154
  16. data/lib/mindee/geometry.rb +105 -8
  17. data/lib/mindee/http/endpoint.rb +80 -0
  18. data/lib/mindee/input/pdf_processing.rb +106 -0
  19. data/lib/mindee/input/sources.rb +97 -0
  20. data/lib/mindee/input.rb +3 -0
  21. data/lib/mindee/parsing/document.rb +31 -0
  22. data/lib/mindee/parsing/error.rb +22 -0
  23. data/lib/mindee/parsing/inference.rb +53 -0
  24. data/lib/mindee/parsing/page.rb +46 -0
  25. data/lib/mindee/parsing/prediction/base.rb +30 -0
  26. data/lib/mindee/{fields → parsing/prediction/common_fields}/amount.rb +5 -1
  27. data/lib/mindee/{fields → parsing/prediction/common_fields}/base.rb +16 -5
  28. data/lib/mindee/{fields → parsing/prediction/common_fields}/company_registration.rb +0 -0
  29. data/lib/mindee/{fields/datefield.rb → parsing/prediction/common_fields/date.rb} +0 -0
  30. data/lib/mindee/{fields → parsing/prediction/common_fields}/locale.rb +0 -0
  31. data/lib/mindee/{fields → parsing/prediction/common_fields}/payment_details.rb +0 -0
  32. data/lib/mindee/parsing/prediction/common_fields/position.rb +39 -0
  33. data/lib/mindee/{fields → parsing/prediction/common_fields}/tax.rb +7 -2
  34. data/lib/mindee/parsing/prediction/common_fields/text.rb +12 -0
  35. data/lib/mindee/parsing/prediction/common_fields.rb +11 -0
  36. data/lib/mindee/parsing/prediction/custom/custom_v1.rb +58 -0
  37. data/lib/mindee/{fields/custom_docs.rb → parsing/prediction/custom/fields.rb} +5 -5
  38. data/lib/mindee/parsing/prediction/eu/license_plate/license_plate_v1.rb +34 -0
  39. data/lib/mindee/parsing/prediction/fr/bank_account_details/bank_account_details_v1.rb +40 -0
  40. data/lib/mindee/parsing/prediction/fr/carte_vitale/carte_vitale_v1.rb +49 -0
  41. data/lib/mindee/parsing/prediction/fr/id_card/id_card_v1.rb +84 -0
  42. data/lib/mindee/parsing/prediction/invoice/invoice_line_item.rb +58 -0
  43. data/lib/mindee/parsing/prediction/invoice/invoice_v4.rb +216 -0
  44. data/lib/mindee/parsing/prediction/passport/passport_v1.rb +184 -0
  45. data/lib/mindee/parsing/prediction/receipt/receipt_v4.rb +84 -0
  46. data/lib/mindee/parsing/prediction/shipping_container/shipping_container_v1.rb +38 -0
  47. data/lib/mindee/parsing/prediction/us/bank_check/bank_check_v1.rb +70 -0
  48. data/lib/mindee/parsing/prediction.rb +12 -0
  49. data/lib/mindee/parsing.rb +4 -0
  50. data/lib/mindee/version.rb +1 -1
  51. data/mindee.gemspec +2 -1
  52. metadata +57 -24
  53. data/lib/mindee/documents/base.rb +0 -35
  54. data/lib/mindee/documents/custom.rb +0 -65
  55. data/lib/mindee/documents/financial_doc.rb +0 -135
  56. data/lib/mindee/documents/invoice.rb +0 -162
  57. data/lib/mindee/documents/passport.rb +0 -163
  58. data/lib/mindee/documents/receipt.rb +0 -109
  59. data/lib/mindee/documents.rb +0 -7
  60. data/lib/mindee/endpoint.rb +0 -105
  61. data/lib/mindee/fields/orientation.rb +0 -26
  62. data/lib/mindee/fields.rb +0 -11
  63. data/lib/mindee/inputs.rb +0 -153
  64. 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
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'documents/invoice'
4
- require_relative 'documents/receipt'
5
- require_relative 'documents/passport'
6
- require_relative 'documents/financial_doc'
7
- require_relative 'documents/custom'
@@ -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