mindee 1.4.0 → 2.0.1

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.
Files changed (89) hide show
  1. package/CHANGELOG.md +37 -19
  2. package/README.md +46 -126
  3. package/bin/mindee.d.ts +2 -0
  4. package/bin/mindee.js +5 -0
  5. package/package.json +68 -58
  6. package/src/api/endpoint.d.ts +29 -0
  7. package/src/api/endpoint.js +151 -0
  8. package/src/api/index.d.ts +2 -0
  9. package/src/api/index.js +18 -0
  10. package/src/api/response.d.ts +52 -0
  11. package/src/api/response.js +107 -0
  12. package/src/cli.d.ts +1 -0
  13. package/src/cli.js +114 -0
  14. package/src/client.d.ts +48 -0
  15. package/src/client.js +123 -0
  16. package/src/constants.d.ts +13 -0
  17. package/src/constants.js +54 -0
  18. package/src/documents/custom.d.ts +14 -0
  19. package/src/documents/custom.js +48 -0
  20. package/src/documents/document.d.ts +38 -0
  21. package/src/documents/document.js +59 -0
  22. package/src/documents/documentConfig.d.ts +44 -0
  23. package/src/documents/documentConfig.js +104 -0
  24. package/src/documents/financialDocument.d.ts +32 -0
  25. package/src/documents/financialDocument.js +133 -0
  26. package/src/documents/index.d.ts +12 -0
  27. package/src/documents/index.js +20 -0
  28. package/src/documents/invoice.d.ts +37 -0
  29. package/src/documents/invoice.js +303 -0
  30. package/src/documents/passport.d.ts +36 -0
  31. package/src/documents/passport.js +218 -0
  32. package/src/documents/receipt.d.ts +24 -0
  33. package/src/documents/receipt.js +157 -0
  34. package/src/errors/handler.d.ts +7 -0
  35. package/src/errors/handler.js +18 -0
  36. package/src/fields/amount.d.ts +13 -0
  37. package/src/fields/amount.js +34 -0
  38. package/src/fields/companyRegistration.d.ts +6 -0
  39. package/src/fields/companyRegistration.js +11 -0
  40. package/src/fields/customDocs.d.ts +42 -0
  41. package/src/fields/customDocs.js +61 -0
  42. package/src/fields/date.d.ts +12 -0
  43. package/src/fields/date.js +25 -0
  44. package/src/fields/field.d.ts +74 -0
  45. package/src/fields/field.js +106 -0
  46. package/src/fields/fullText.d.ts +24 -0
  47. package/src/fields/fullText.js +89 -0
  48. package/src/fields/index.d.ts +11 -0
  49. package/src/fields/index.js +27 -0
  50. package/src/fields/locale.d.ts +13 -0
  51. package/src/fields/locale.js +40 -0
  52. package/src/fields/orientation.d.ts +10 -0
  53. package/src/fields/orientation.js +22 -0
  54. package/src/fields/paymentDetails.d.ts +31 -0
  55. package/src/fields/paymentDetails.js +58 -0
  56. package/src/fields/tax.d.ts +30 -0
  57. package/src/fields/tax.js +50 -0
  58. package/src/geometry.d.ts +59 -0
  59. package/src/geometry.js +113 -0
  60. package/src/index.d.ts +2 -0
  61. package/src/index.js +12 -0
  62. package/src/inputs.d.ts +69 -0
  63. package/src/inputs.js +196 -0
  64. package/src/logger.d.ts +20 -0
  65. package/src/logger.js +35 -0
  66. package/mindee/api/financialDocument.js +0 -47
  67. package/mindee/api/index.js +0 -5
  68. package/mindee/api/invoice.js +0 -53
  69. package/mindee/api/object.js +0 -82
  70. package/mindee/api/receipt.js +0 -39
  71. package/mindee/api/request.js +0 -72
  72. package/mindee/api/response.js +0 -80
  73. package/mindee/documents/document.js +0 -69
  74. package/mindee/documents/fields/amount.js +0 -25
  75. package/mindee/documents/fields/date.js +0 -29
  76. package/mindee/documents/fields/field.js +0 -86
  77. package/mindee/documents/fields/index.js +0 -7
  78. package/mindee/documents/fields/locale.js +0 -30
  79. package/mindee/documents/fields/orientation.js +0 -24
  80. package/mindee/documents/fields/paymentDetails.js +0 -52
  81. package/mindee/documents/fields/tax.js +0 -47
  82. package/mindee/documents/financialDocument.js +0 -269
  83. package/mindee/documents/index.js +0 -5
  84. package/mindee/documents/invoice.js +0 -456
  85. package/mindee/documents/receipt.js +0 -287
  86. package/mindee/errors/handler.js +0 -16
  87. package/mindee/index.js +0 -39
  88. package/mindee/inputs.js +0 -181
  89. package/mindee/logger.js +0 -34
@@ -1,287 +0,0 @@
1
- const Document = require("./document");
2
- const Field = require("./fields").field;
3
- const Date = require("./fields").date;
4
- const Amount = require("./fields").amount;
5
- const Locale = require("./fields").locale;
6
- const Orientation = require("./fields").orientation;
7
- const Tax = require("./fields").tax;
8
- const fs = require("fs").promises;
9
-
10
- class Receipt extends Document {
11
- /**
12
- * @param {Object} apiPrediction - Json parsed prediction from HTTP response
13
- * @param {Input} input - Input object
14
- * @param {Integer} pageNumber - Page number for multi pages pdf input
15
- * @param {Object} locale - locale value for creating Receipt object from scratch
16
- * @param {Object} totalIncl - total tax Included value for creating Receipt object from scratch
17
- * @param {Object} date - date value for creating Receipt object from scratch
18
- * @param {Object} category - category value for creating Receipt object from scratch
19
- * @param {Object} merchantName - merchant name value for creating Receipt object from scratch
20
- * @param {Object} time - time value for creating Receipt object from scratch
21
- * @param {Object} taxes - taxes value for creating Receipt object from scratch
22
- * @param {Object} orientation - orientation value for creating Receipt object from scratch
23
- * @param {Object} totalTax - total taxes value for creating Receipt object from scratch
24
- * @param {Object} totalExcl - total taxes excluded value for creating Receipt object from scratch
25
- * @param {String} level - specify whether object is built from "page" level or "document" level prediction
26
- */
27
- constructor({
28
- apiPrediction = undefined,
29
- inputFile = undefined,
30
- locale = undefined,
31
- totalIncl = undefined,
32
- date = undefined,
33
- category = undefined,
34
- merchantName = undefined,
35
- time = undefined,
36
- taxes = undefined,
37
- orientation = undefined,
38
- totalTax = undefined,
39
- totalExcl = undefined,
40
- words = undefined,
41
- pageNumber = 0,
42
- level = "page",
43
- }) {
44
- super(inputFile);
45
- this.level = level;
46
- this.constructPrediction = function (item) {
47
- return { prediction: { value: item }, valueKey: "value", pageNumber };
48
- };
49
- if (apiPrediction === undefined) {
50
- this.#initFromScratch({
51
- locale,
52
- totalExcl,
53
- totalIncl,
54
- date,
55
- category,
56
- merchantName,
57
- time,
58
- taxes,
59
- orientation,
60
- totalTax,
61
- pageNumber,
62
- });
63
- } else {
64
- this.#initFromApiPrediction(apiPrediction, pageNumber, words);
65
- }
66
- this.#checklist();
67
- this.#reconstruct();
68
- }
69
-
70
- #initFromScratch({
71
- locale,
72
- totalExcl,
73
- totalIncl,
74
- date,
75
- category,
76
- merchantName,
77
- time,
78
- taxes,
79
- orientation,
80
- totalTax,
81
- pageNumber,
82
- }) {
83
- this.locale = new Locale(this.constructPrediction(locale));
84
- this.totalIncl = new Amount(this.constructPrediction(totalIncl));
85
- this.date = new Date(this.constructPrediction(date));
86
- this.category = new Field(this.constructPrediction(category));
87
- this.merchantName = new Field(this.constructPrediction(merchantName));
88
- this.time = new Field(this.constructPrediction(time));
89
- if (taxes !== undefined) {
90
- this.taxes = [];
91
- for (const t of taxes) {
92
- this.taxes.push(
93
- new Tax({
94
- prediction: { value: t[0], rate: t[1] },
95
- pageNumber,
96
- valueKey: "value",
97
- rateKey: "rate",
98
- })
99
- );
100
- }
101
- }
102
- this.orientation = new Orientation(this.constructPrediction(orientation));
103
- this.totalTax = new Amount(this.constructPrediction(totalTax));
104
- this.totalExcl = new Amount(this.constructPrediction(totalExcl));
105
- }
106
-
107
- /**
108
- Set the object attributes with api prediction values
109
- @param apiPrediction: Raw prediction from HTTP response
110
- @param pageNumber: Page number for multi pages pdf input
111
- */
112
- #initFromApiPrediction(apiPrediction, pageNumber, words) {
113
- this.locale = new Locale({ prediction: apiPrediction.locale, pageNumber });
114
- this.totalIncl = new Amount({
115
- prediction: apiPrediction.total_incl,
116
- valueKey: "value",
117
- pageNumber,
118
- });
119
- this.date = new Date({
120
- prediction: apiPrediction.date,
121
- valueKey: "value",
122
- pageNumber,
123
- });
124
- this.category = new Field({
125
- prediction: apiPrediction.category,
126
- pageNumber,
127
- });
128
- this.merchantName = new Field({
129
- prediction: apiPrediction.supplier,
130
- valueKey: "value",
131
- pageNumber,
132
- });
133
- this.time = new Field({
134
- prediction: apiPrediction.time,
135
- valueKey: "value",
136
- pageNumber,
137
- });
138
- this.taxes = apiPrediction.taxes.map(
139
- (taxPrediction) =>
140
- new Tax({
141
- prediction: taxPrediction,
142
- pageNumber,
143
- valueKey: "value",
144
- rateKey: "rate",
145
- codeKey: "code",
146
- })
147
- );
148
- this.totalTax = new Amount({
149
- prediction: { value: undefined, confidence: 0 },
150
- valueKey: "value",
151
- pageNumber,
152
- });
153
- this.totalExcl = new Amount({
154
- prediction: { value: undefined, confidence: 0 },
155
- valueKey: "value",
156
- pageNumber,
157
- });
158
- if (this.level === "page") {
159
- this.orientation = new Orientation({
160
- prediction: apiPrediction.orientation,
161
- pageNumber,
162
- });
163
- } else {
164
- this.orientation = new Orientation(
165
- this.constructPrediction({
166
- prediction: {
167
- value: undefined,
168
- confidence: 0.0,
169
- degrees: undefined,
170
- },
171
- })
172
- );
173
- }
174
- if (words && words.length > 0) this.words = words;
175
- }
176
-
177
- toString() {
178
- return `
179
- -----Receipt data-----
180
- Filename: ${this.filename}
181
- Total amount: ${this.totalIncl.value}
182
- Date: ${this.date.value}
183
- Category: ${this.category.value}
184
- Time: ${this.time.value}
185
- Merchant name: ${this.merchantName.value}
186
- Taxes: ${this.taxes.map((tax) => tax.toString()).join(" - ")}
187
- Total taxes: ${this.totalTax.value}
188
- `;
189
- }
190
-
191
- static async load(path) {
192
- const file = fs.readFile(path);
193
- const args = JSON.parse(file);
194
- return new Receipt({ reconsctruted: true, ...args });
195
- }
196
-
197
- /**
198
- * Call all check methods
199
- */
200
- #checklist() {
201
- this.checklist = { taxesMatchTotalIncl: this.#taxesMatchTotal() };
202
- }
203
-
204
- #taxesMatchTotal() {
205
- // Check taxes and total amount exist
206
-
207
- if (this.taxes.length === 0 || this.totalIncl.value == null) return false;
208
-
209
- // Reconstruct total_incl from taxes
210
- let totalVat = 0;
211
- let reconstructedTotal = 0;
212
- this.taxes.forEach((tax) => {
213
- if (tax.value == null || !tax.rate) return false;
214
- totalVat += tax.value;
215
- reconstructedTotal += tax.value + (100 * tax.value) / tax.rate;
216
- });
217
-
218
- // Sanity check
219
- if (totalVat <= 0) return false;
220
-
221
- // Crate epsilon
222
- const eps = 1 / (100 * totalVat);
223
-
224
- if (
225
- this.totalIncl.value * (1 - eps) - 0.02 <= reconstructedTotal &&
226
- reconstructedTotal <= this.totalIncl.value * (1 + eps) + 0.02
227
- ) {
228
- this.taxes = this.taxes.map((tax) => ({ ...tax, probability: 1.0 }));
229
- this.totalTax.probability = 1.0;
230
- this.totalIncl.probability = 1.0;
231
- return true;
232
- }
233
- return false;
234
- }
235
-
236
- /**
237
- * Call all fields that need to be reconstructed
238
- */
239
- #reconstruct() {
240
- this.#reconstructTotalExclFromTCCAndTaxes();
241
- this.#reconstructTotalTax();
242
- }
243
-
244
- /**
245
- * Set this.totalExcl with Amount object
246
- * The totalExcl Amount value is the difference between totalIncl and sum of taxes
247
- * The totalExcl Amount probability is the product of this.taxes probabilities multiplied by totalIncl probability
248
- */
249
- #reconstructTotalExclFromTCCAndTaxes() {
250
- if (this.taxes.length && this.totalIncl.value != null) {
251
- const totalExcl = {
252
- value: this.totalIncl.value - Field.arraySum(this.taxes),
253
- confidence:
254
- Field.arrayProbability(this.taxes) * this.totalIncl.probability,
255
- };
256
- this.totalExcl = new Amount({
257
- prediction: totalExcl,
258
- valueKey: "value",
259
- reconstructed: true,
260
- });
261
- }
262
- }
263
-
264
- /**
265
- * Set this.totalTax with Amount object
266
- * The totalTax Amount value is the sum of all this.taxes value
267
- * The totalTax Amount probability is the product of this.taxes probabilities
268
- */
269
- #reconstructTotalTax() {
270
- if (this.taxes.length && this.totalTax.value == null) {
271
- const totalTax = {
272
- value: this.taxes
273
- .map((tax) => tax.value || 0)
274
- .reduce((a, b) => a + b, 0),
275
- confidence: Field.arrayProbability(this.taxes),
276
- };
277
- if (totalTax.value > 0)
278
- this.totalTax = new Amount({
279
- prediction: totalTax,
280
- valueKey: "value",
281
- reconstructed: true,
282
- });
283
- }
284
- }
285
- }
286
-
287
- module.exports = Receipt;
@@ -1,16 +0,0 @@
1
- const { logger } = require("../logger");
2
-
3
- class ErrorHandler {
4
- constructor(throwOnError = true) {
5
- this.throwOnError = throwOnError;
6
- }
7
-
8
- throw(error, force = true) {
9
- if (this.throwOnError || force) throw error;
10
- else logger.error(error.message);
11
- }
12
- }
13
-
14
- const errorHandler = new ErrorHandler();
15
-
16
- module.exports = errorHandler;
package/mindee/index.js DELETED
@@ -1,39 +0,0 @@
1
- const errorHandler = require("./errors/handler");
2
- const { logger, LOG_LEVELS } = require("./logger");
3
- const APIReceipt = require("./api/receipt");
4
- const APIInvoice = require("./api/invoice");
5
- const APIFinancialDocument = require("./api/financialDocument");
6
-
7
- class Client {
8
- /**
9
- * @param {string} receiptToken - Receipt Expense Token from Mindee dashboard
10
- * @param {string} invoiceToken - Invoice Token from Mindee dashboard
11
- * @param {boolean} throwOnError - Throw if an error is send from the API / SDK (true by default)
12
- * @param {boolean} debug - Enable debug logging (disable by default)
13
- */
14
- constructor({
15
- receiptToken = undefined,
16
- invoiceToken = undefined,
17
- throwOnError = true,
18
- debug = undefined,
19
- } = {}) {
20
- this.receiptToken = receiptToken || process.env.MINDEE_RECEIPT_TOKEN;
21
- this.invoiceToken = invoiceToken || process.env.MINDEE_INVOICE_TOKEN;
22
- errorHandler.throwOnError = throwOnError;
23
- logger.level =
24
- debug ?? process.env.MINDEE_DEBUG
25
- ? LOG_LEVELS["debug"]
26
- : LOG_LEVELS["warn"];
27
- this.receipt = new APIReceipt(this.receiptToken);
28
- this.invoice = new APIInvoice(this.invoiceToken);
29
- this.financialDocument = new APIFinancialDocument(
30
- this.invoiceToken,
31
- this.receiptToken
32
- );
33
- }
34
- }
35
-
36
- exports.Client = Client;
37
- exports.documents = require("./documents");
38
- exports.api = require("./api");
39
- exports.inputs = require("./inputs");
package/mindee/inputs.js DELETED
@@ -1,181 +0,0 @@
1
- const fs = require("fs").promises;
2
- const errorHandler = require("./errors/handler");
3
- const path = require("path");
4
- const { PDFDocument } = require("pdf-lib");
5
- const concat = require("concat-stream");
6
- const { Base64Encode } = require("base64-stream");
7
- const fileType = require("file-type");
8
- const ArrayBufferEncode = require("base64-arraybuffer");
9
- const { logger } = require("./logger");
10
-
11
- class Input {
12
- MIMETYPES = {
13
- pdf: "application/pdf",
14
- heic: "image/heic",
15
- jpg: "image/jpeg",
16
- jpeg: "image/jpeg",
17
- png: "image/png",
18
- tif: "image/tiff",
19
- tiff: "image/tiff",
20
- webp: "image/webp",
21
- };
22
- ALLOWED_INPUT_TYPE = ["base64", "path", "stream", "dummy"];
23
- MAX_DOC_PAGES = 3;
24
-
25
- /**
26
- * @param {(String | Buffer)} file - the file that will be read. Either path or base64 string, or a steam
27
- * @param {String} inputType - the type of input used in file ("base64", "path", "dummy").
28
- * NB: dummy is only used for tests purposes
29
- * @param {String} filename - File name of the input
30
- * @param {Boolean} cut_pdf: Automatically reconstruct pdf with more than 4 pages
31
- * NB: Because of async calls, init() should be called after creating the object
32
- */
33
- constructor({ file, filename = undefined, inputType, allowCutPdf = true }) {
34
- // Check if inputType is valid
35
- if (!this.ALLOWED_INPUT_TYPE.includes(inputType)) {
36
- errorHandler.throw(
37
- new Error(
38
- `The input type is invalid. It should be \
39
- ${this.ALLOWED_INPUT_TYPE.toString()}`
40
- )
41
- );
42
- }
43
- this.file = file;
44
- this.filename = filename;
45
- this.inputType = inputType;
46
- this.allowCutPdf = allowCutPdf;
47
- }
48
-
49
- async init() {
50
- if (this.inputType === "base64") await this.initBase64();
51
- else if (this.inputType === "path") await this.initFile();
52
- else if (this.inputType === "stream") await this.initStream();
53
- else this.initDummy();
54
-
55
- if (this.fileExtension === "application/pdf" && this.allowCutPdf === true) {
56
- await this.cutPdf();
57
- }
58
- }
59
-
60
- async initBase64() {
61
- this.fileObject = this.file;
62
- this.filepath = undefined;
63
-
64
- if (this.filename === undefined) {
65
- const mimeType = await fileType.fromBuffer(
66
- Buffer.from(this.fileObject, "base64")
67
- );
68
- if (mimeType !== undefined) {
69
- this.fileExtension = mimeType.mime;
70
- this.filename = `from_${this.inputType}.${mimeType.ext}`;
71
- } else {
72
- throw "Could not determine the MIME type. Please specify the 'filename' option.";
73
- }
74
- } else {
75
- const filetype = this.filename.split(".").pop();
76
- this.fileExtension = this.MIMETYPES[filetype];
77
- }
78
- }
79
-
80
- async initFile() {
81
- this.fileObject = await fs.readFile(this.file);
82
- this.filepath = this.file;
83
- this.filename = this.filename || path.basename(this.file);
84
-
85
- // Check if file type is valid
86
- const filetype = this.filename.split(".").pop();
87
- if (!(filetype in this.MIMETYPES)) {
88
- errorHandler.throw(
89
- new Error(
90
- `File type is not allowed. It must be ${Object.keys(
91
- this.MIMETYPES
92
- ).toString()}`
93
- )
94
- );
95
- }
96
- this.fileExtension = this.MIMETYPES[filetype];
97
- }
98
-
99
- async initStream() {
100
- const file = await this.streamToBase64(this.file);
101
-
102
- this.file = file;
103
- this.inputType = "base64";
104
- await this.initBase64();
105
- }
106
-
107
- initDummy() {
108
- this.fileObject = "";
109
- this.filename = "";
110
- this.filepath = "";
111
- this.fileExtension = "";
112
- }
113
-
114
- /**
115
- * Convert ReadableStream to Base64 encoded String
116
- *
117
- * @param {*} stream ReadableStream to encode
118
- * @returns Base64 encoded String
119
- */
120
- async streamToBase64(stream) {
121
- return new Promise((resolve, reject) => {
122
- const base64 = new Base64Encode();
123
-
124
- const cbConcat = (base64) => {
125
- resolve(base64);
126
- };
127
-
128
- stream
129
- .pipe(base64)
130
- .pipe(concat(cbConcat))
131
- .on("error", (error) => {
132
- reject(error);
133
- });
134
- });
135
- }
136
-
137
- async countPages() {
138
- let pdfDocument = await PDFDocument.load(this.fileObject, {
139
- ignoreEncryption: true,
140
- });
141
- return pdfDocument.getPageCount();
142
- }
143
-
144
- /** Merge PDF pages */
145
- async cutPdf() {
146
- let currentPdf = await PDFDocument.load(this.fileObject, {
147
- ignoreEncryption: true,
148
- });
149
-
150
- const pdfLength = currentPdf.getPageCount();
151
- if (pdfLength <= this.MAX_DOC_PAGES) {
152
- return;
153
- }
154
-
155
- if (currentPdf.isEncrypted) {
156
- logger.warn(
157
- "PDF of %d pages is encrypted, not possible to cut pages.",
158
- pdfLength
159
- );
160
- return;
161
- }
162
-
163
- const newPdf = await PDFDocument.create();
164
- const pagesNumbers = [0, pdfLength - 2, pdfLength - 1].slice(
165
- 0,
166
- this.MAX_DOC_PAGES
167
- );
168
-
169
- const pages = await newPdf.copyPages(currentPdf, pagesNumbers);
170
- pages.forEach((page) => newPdf.addPage(page));
171
- const data = await newPdf.save();
172
-
173
- if (this.inputType === "path") {
174
- this.fileObject = Buffer.from(data);
175
- } else if (this.inputType === "base64") {
176
- this.fileObject = ArrayBufferEncode.encode(data);
177
- }
178
- }
179
- }
180
-
181
- module.exports = Input;
package/mindee/logger.js DELETED
@@ -1,34 +0,0 @@
1
- const LOGGER_LEVELS = {
2
- debug: 0,
3
- info: 1,
4
- warn: 2,
5
- error: 3,
6
- };
7
-
8
- class Logger {
9
- constructor(level = "debug") {
10
- if (!(level in LOGGER_LEVELS)) level = "debug";
11
- this.level = LOGGER_LEVELS[level];
12
- }
13
-
14
- debug(...args) {
15
- if (this.level <= LOGGER_LEVELS["debug"]) console.debug(...args);
16
- }
17
-
18
- info(...args) {
19
- if (this.level <= LOGGER_LEVELS["info"]) console.info(...args);
20
- }
21
-
22
- warn(...args) {
23
- if (this.level <= LOGGER_LEVELS["warn"]) console.warn(...args);
24
- }
25
-
26
- error(...args) {
27
- if (this.level <= LOGGER_LEVELS["error"]) console.error(...args);
28
- }
29
- }
30
-
31
- module.exports = {
32
- logger: new Logger(),
33
- LOG_LEVELS: LOGGER_LEVELS,
34
- };