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.
- package/CHANGELOG.md +37 -19
- package/README.md +46 -126
- package/bin/mindee.d.ts +2 -0
- package/bin/mindee.js +5 -0
- package/package.json +68 -58
- package/src/api/endpoint.d.ts +29 -0
- package/src/api/endpoint.js +151 -0
- package/src/api/index.d.ts +2 -0
- package/src/api/index.js +18 -0
- package/src/api/response.d.ts +52 -0
- package/src/api/response.js +107 -0
- package/src/cli.d.ts +1 -0
- package/src/cli.js +114 -0
- package/src/client.d.ts +48 -0
- package/src/client.js +123 -0
- package/src/constants.d.ts +13 -0
- package/src/constants.js +54 -0
- package/src/documents/custom.d.ts +14 -0
- package/src/documents/custom.js +48 -0
- package/src/documents/document.d.ts +38 -0
- package/src/documents/document.js +59 -0
- package/src/documents/documentConfig.d.ts +44 -0
- package/src/documents/documentConfig.js +104 -0
- package/src/documents/financialDocument.d.ts +32 -0
- package/src/documents/financialDocument.js +133 -0
- package/src/documents/index.d.ts +12 -0
- package/src/documents/index.js +20 -0
- package/src/documents/invoice.d.ts +37 -0
- package/src/documents/invoice.js +303 -0
- package/src/documents/passport.d.ts +36 -0
- package/src/documents/passport.js +218 -0
- package/src/documents/receipt.d.ts +24 -0
- package/src/documents/receipt.js +157 -0
- package/src/errors/handler.d.ts +7 -0
- package/src/errors/handler.js +18 -0
- package/src/fields/amount.d.ts +13 -0
- package/src/fields/amount.js +34 -0
- package/src/fields/companyRegistration.d.ts +6 -0
- package/src/fields/companyRegistration.js +11 -0
- package/src/fields/customDocs.d.ts +42 -0
- package/src/fields/customDocs.js +61 -0
- package/src/fields/date.d.ts +12 -0
- package/src/fields/date.js +25 -0
- package/src/fields/field.d.ts +74 -0
- package/src/fields/field.js +106 -0
- package/src/fields/fullText.d.ts +24 -0
- package/src/fields/fullText.js +89 -0
- package/src/fields/index.d.ts +11 -0
- package/src/fields/index.js +27 -0
- package/src/fields/locale.d.ts +13 -0
- package/src/fields/locale.js +40 -0
- package/src/fields/orientation.d.ts +10 -0
- package/src/fields/orientation.js +22 -0
- package/src/fields/paymentDetails.d.ts +31 -0
- package/src/fields/paymentDetails.js +58 -0
- package/src/fields/tax.d.ts +30 -0
- package/src/fields/tax.js +50 -0
- package/src/geometry.d.ts +59 -0
- package/src/geometry.js +113 -0
- package/src/index.d.ts +2 -0
- package/src/index.js +12 -0
- package/src/inputs.d.ts +69 -0
- package/src/inputs.js +196 -0
- package/src/logger.d.ts +20 -0
- package/src/logger.js +35 -0
- package/mindee/api/financialDocument.js +0 -47
- package/mindee/api/index.js +0 -5
- package/mindee/api/invoice.js +0 -53
- package/mindee/api/object.js +0 -82
- package/mindee/api/receipt.js +0 -39
- package/mindee/api/request.js +0 -72
- package/mindee/api/response.js +0 -80
- package/mindee/documents/document.js +0 -69
- package/mindee/documents/fields/amount.js +0 -25
- package/mindee/documents/fields/date.js +0 -29
- package/mindee/documents/fields/field.js +0 -86
- package/mindee/documents/fields/index.js +0 -7
- package/mindee/documents/fields/locale.js +0 -30
- package/mindee/documents/fields/orientation.js +0 -24
- package/mindee/documents/fields/paymentDetails.js +0 -52
- package/mindee/documents/fields/tax.js +0 -47
- package/mindee/documents/financialDocument.js +0 -269
- package/mindee/documents/index.js +0 -5
- package/mindee/documents/invoice.js +0 -456
- package/mindee/documents/receipt.js +0 -287
- package/mindee/errors/handler.js +0 -16
- package/mindee/index.js +0 -39
- package/mindee/inputs.js +0 -181
- package/mindee/logger.js +0 -34
package/src/inputs.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.BytesInput = exports.StreamInput = exports.Base64Input = exports.PathInput = exports.Input = exports.INPUT_TYPE_PATH = exports.INPUT_TYPE_BYTES = exports.INPUT_TYPE_BASE64 = exports.INPUT_TYPE_STREAM = void 0;
|
|
27
|
+
const fs_1 = require("fs");
|
|
28
|
+
const path = __importStar(require("path"));
|
|
29
|
+
const fileType = __importStar(require("file-type"));
|
|
30
|
+
const handler_1 = require("./errors/handler");
|
|
31
|
+
const pdf_lib_1 = require("pdf-lib");
|
|
32
|
+
const node_buffer_1 = require("node:buffer");
|
|
33
|
+
const logger_1 = require("./logger");
|
|
34
|
+
exports.INPUT_TYPE_STREAM = "stream";
|
|
35
|
+
exports.INPUT_TYPE_BASE64 = "base64";
|
|
36
|
+
exports.INPUT_TYPE_BYTES = "bytes";
|
|
37
|
+
exports.INPUT_TYPE_PATH = "path";
|
|
38
|
+
const MIMETYPES = new Map([
|
|
39
|
+
[".pdf", "application/pdf"],
|
|
40
|
+
[".heic", "image/heic"],
|
|
41
|
+
[".jpg", "image/jpeg"],
|
|
42
|
+
[".jpeg", "image/jpeg"],
|
|
43
|
+
[".png", "image/png"],
|
|
44
|
+
[".tif", "image/tiff"],
|
|
45
|
+
[".tiff", "image/tiff"],
|
|
46
|
+
[".webp", "image/webp"],
|
|
47
|
+
]);
|
|
48
|
+
const ALLOWED_INPUT_TYPES = [
|
|
49
|
+
exports.INPUT_TYPE_STREAM,
|
|
50
|
+
exports.INPUT_TYPE_BASE64,
|
|
51
|
+
exports.INPUT_TYPE_BYTES,
|
|
52
|
+
exports.INPUT_TYPE_PATH,
|
|
53
|
+
];
|
|
54
|
+
class Input {
|
|
55
|
+
/**
|
|
56
|
+
* @param {String} inputType - the type of input used in file ("base64", "path", "dummy").
|
|
57
|
+
* NB: dummy is only used for tests purposes
|
|
58
|
+
* @param {Boolean} cutPages
|
|
59
|
+
* NB: Because of async calls, init() should be called after creating the object
|
|
60
|
+
*/
|
|
61
|
+
constructor({ inputType }) {
|
|
62
|
+
this.MAX_DOC_PAGES = 3;
|
|
63
|
+
this.filename = "";
|
|
64
|
+
this.mimeType = "";
|
|
65
|
+
this.fileObject = node_buffer_1.Buffer.alloc(0);
|
|
66
|
+
// Check if inputType is valid
|
|
67
|
+
if (!ALLOWED_INPUT_TYPES.includes(inputType)) {
|
|
68
|
+
const allowed = Array.from(MIMETYPES.keys()).join(", ");
|
|
69
|
+
handler_1.errorHandler.throw(new Error(`Invalid input type, must be one of ${allowed}.`));
|
|
70
|
+
}
|
|
71
|
+
this.inputType = inputType;
|
|
72
|
+
logger_1.logger.debug(`Loading file from: ${inputType}`);
|
|
73
|
+
}
|
|
74
|
+
async init() {
|
|
75
|
+
throw new Error("not Implemented");
|
|
76
|
+
}
|
|
77
|
+
isPdf() {
|
|
78
|
+
return this.mimeType === "application/pdf";
|
|
79
|
+
}
|
|
80
|
+
async checkMimetype() {
|
|
81
|
+
let mimeType;
|
|
82
|
+
const fileExt = path.extname(this.filename);
|
|
83
|
+
if (fileExt) {
|
|
84
|
+
mimeType = MIMETYPES.get(fileExt.toLowerCase()) || "";
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const guess = await fileType.fromBuffer(this.fileObject);
|
|
88
|
+
if (guess !== undefined) {
|
|
89
|
+
mimeType = guess.mime;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
throw "Could not determine the MIME type of the file";
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!mimeType) {
|
|
96
|
+
const allowed = Array.from(MIMETYPES.keys()).join(", ");
|
|
97
|
+
const err = new Error(`Invalid file type, must be one of ${allowed}.`);
|
|
98
|
+
handler_1.errorHandler.throw(err);
|
|
99
|
+
}
|
|
100
|
+
logger_1.logger.debug(`File is of type: ${mimeType}`);
|
|
101
|
+
return mimeType;
|
|
102
|
+
}
|
|
103
|
+
async countPages() {
|
|
104
|
+
const pdfDocument = await pdf_lib_1.PDFDocument.load(this.fileObject, {
|
|
105
|
+
ignoreEncryption: true,
|
|
106
|
+
});
|
|
107
|
+
return pdfDocument.getPageCount();
|
|
108
|
+
}
|
|
109
|
+
/** Merge PDF pages */
|
|
110
|
+
async cutPdf() {
|
|
111
|
+
const currentPdf = await pdf_lib_1.PDFDocument.load(this.fileObject, {
|
|
112
|
+
ignoreEncryption: true,
|
|
113
|
+
});
|
|
114
|
+
const pdfLength = currentPdf.getPageCount();
|
|
115
|
+
if (pdfLength <= this.MAX_DOC_PAGES) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const newPdf = await pdf_lib_1.PDFDocument.create();
|
|
119
|
+
const pagesNumbers = [0, pdfLength - 2, pdfLength - 1].slice(0, this.MAX_DOC_PAGES);
|
|
120
|
+
logger_1.logger.debug(`Cutting PDF, keeping pages: ${pagesNumbers}`);
|
|
121
|
+
const pages = await newPdf.copyPages(currentPdf, pagesNumbers);
|
|
122
|
+
pages.forEach((page) => newPdf.addPage(page));
|
|
123
|
+
const data = await newPdf.save();
|
|
124
|
+
this.fileObject = node_buffer_1.Buffer.from(data);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.Input = Input;
|
|
128
|
+
class PathInput extends Input {
|
|
129
|
+
constructor({ inputPath }) {
|
|
130
|
+
super({
|
|
131
|
+
inputType: exports.INPUT_TYPE_PATH,
|
|
132
|
+
});
|
|
133
|
+
this.inputPath = inputPath;
|
|
134
|
+
this.filename = path.basename(this.inputPath);
|
|
135
|
+
}
|
|
136
|
+
async init() {
|
|
137
|
+
logger_1.logger.debug(`Loading from: ${this.inputPath}`);
|
|
138
|
+
this.fileObject = node_buffer_1.Buffer.from(await fs_1.promises.readFile(this.inputPath));
|
|
139
|
+
this.mimeType = await this.checkMimetype();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.PathInput = PathInput;
|
|
143
|
+
class Base64Input extends Input {
|
|
144
|
+
constructor({ inputString, filename }) {
|
|
145
|
+
super({
|
|
146
|
+
inputType: exports.INPUT_TYPE_BASE64,
|
|
147
|
+
});
|
|
148
|
+
this.filename = filename;
|
|
149
|
+
this.inputString = inputString;
|
|
150
|
+
}
|
|
151
|
+
async init() {
|
|
152
|
+
this.fileObject = node_buffer_1.Buffer.from(this.inputString, "base64");
|
|
153
|
+
this.mimeType = await this.checkMimetype();
|
|
154
|
+
// clear out the string
|
|
155
|
+
this.inputString = "";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports.Base64Input = Base64Input;
|
|
159
|
+
class StreamInput extends Input {
|
|
160
|
+
constructor({ inputStream, filename }) {
|
|
161
|
+
super({
|
|
162
|
+
inputType: exports.INPUT_TYPE_STREAM,
|
|
163
|
+
});
|
|
164
|
+
this.filename = filename;
|
|
165
|
+
this.inputStream = inputStream;
|
|
166
|
+
}
|
|
167
|
+
async init() {
|
|
168
|
+
this.fileObject = await this.stream2buffer(this.inputStream);
|
|
169
|
+
this.mimeType = await this.checkMimetype();
|
|
170
|
+
}
|
|
171
|
+
async stream2buffer(stream) {
|
|
172
|
+
return new Promise((resolve, reject) => {
|
|
173
|
+
const _buf = Array();
|
|
174
|
+
stream.on("data", (chunk) => _buf.push(chunk));
|
|
175
|
+
stream.on("end", () => resolve(node_buffer_1.Buffer.concat(_buf)));
|
|
176
|
+
stream.on("error", (err) => reject(`Error converting stream - ${err}`));
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
exports.StreamInput = StreamInput;
|
|
181
|
+
class BytesInput extends Input {
|
|
182
|
+
constructor({ inputBytes, filename }) {
|
|
183
|
+
super({
|
|
184
|
+
inputType: exports.INPUT_TYPE_BYTES,
|
|
185
|
+
});
|
|
186
|
+
this.filename = filename;
|
|
187
|
+
this.inputBytes = inputBytes;
|
|
188
|
+
}
|
|
189
|
+
async init() {
|
|
190
|
+
this.fileObject = node_buffer_1.Buffer.from(this.inputBytes, "hex");
|
|
191
|
+
this.mimeType = await this.checkMimetype();
|
|
192
|
+
// clear out the string
|
|
193
|
+
this.inputBytes = "";
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
exports.BytesInput = BytesInput;
|
package/src/logger.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface LoggerLevels {
|
|
2
|
+
[index: string]: number;
|
|
3
|
+
}
|
|
4
|
+
interface LoggerInterface {
|
|
5
|
+
debug(level: any[]): void;
|
|
6
|
+
info(level: any[]): void;
|
|
7
|
+
warn(level: any[]): void;
|
|
8
|
+
error(level: any[]): void;
|
|
9
|
+
}
|
|
10
|
+
export declare const LOG_LEVELS: LoggerLevels;
|
|
11
|
+
declare class Logger implements LoggerInterface {
|
|
12
|
+
level: string | number;
|
|
13
|
+
constructor(level?: string | number);
|
|
14
|
+
debug(...args: any[]): void;
|
|
15
|
+
info(...args: any[]): void;
|
|
16
|
+
warn(...args: any[]): void;
|
|
17
|
+
error(...args: any[]): void;
|
|
18
|
+
}
|
|
19
|
+
export declare const logger: Logger;
|
|
20
|
+
export {};
|
package/src/logger.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logger = exports.LOG_LEVELS = void 0;
|
|
4
|
+
exports.LOG_LEVELS = {
|
|
5
|
+
debug: 0,
|
|
6
|
+
info: 1,
|
|
7
|
+
warn: 2,
|
|
8
|
+
error: 3,
|
|
9
|
+
};
|
|
10
|
+
class Logger {
|
|
11
|
+
constructor(level = "warn") {
|
|
12
|
+
this.level = level;
|
|
13
|
+
if (!(level in exports.LOG_LEVELS)) {
|
|
14
|
+
this.level = "debug";
|
|
15
|
+
}
|
|
16
|
+
this.level = exports.LOG_LEVELS[level];
|
|
17
|
+
}
|
|
18
|
+
debug(...args) {
|
|
19
|
+
if (this.level <= exports.LOG_LEVELS["debug"])
|
|
20
|
+
console.debug(args);
|
|
21
|
+
}
|
|
22
|
+
info(...args) {
|
|
23
|
+
if (this.level <= exports.LOG_LEVELS["info"])
|
|
24
|
+
console.info(args);
|
|
25
|
+
}
|
|
26
|
+
warn(...args) {
|
|
27
|
+
if (this.level <= exports.LOG_LEVELS["warn"])
|
|
28
|
+
console.warn(args);
|
|
29
|
+
}
|
|
30
|
+
error(...args) {
|
|
31
|
+
if (this.level <= exports.LOG_LEVELS["error"])
|
|
32
|
+
console.error(args);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.logger = new Logger();
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
const APIObject = require("./object");
|
|
2
|
-
const Input = require("../inputs");
|
|
3
|
-
|
|
4
|
-
class APIFinancialDocument extends APIObject {
|
|
5
|
-
constructor(invoiceToken, receiptToken) {
|
|
6
|
-
super(undefined, "financialDocument");
|
|
7
|
-
this.invoiceToken = invoiceToken;
|
|
8
|
-
this.receiptToken = receiptToken;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @param {String} file: Receipt filepath (allowed jpg, png, tiff, pdf)
|
|
13
|
-
* @param {String} inputType: String in {'path', 'stream', 'base64'}
|
|
14
|
-
* @param {Boolean} includeWords: extract all words into http_response
|
|
15
|
-
* @param {String} version: expense_receipt api version
|
|
16
|
-
* @param {Boolean} cutPdf: Automatically reconstruct pdf with more than 4 pages
|
|
17
|
-
* @returns {Response} Wrapped response with Receipts objects parsed
|
|
18
|
-
*/
|
|
19
|
-
async parse({
|
|
20
|
-
input,
|
|
21
|
-
inputType = "path",
|
|
22
|
-
filename = undefined,
|
|
23
|
-
version = "3",
|
|
24
|
-
cutPdf = true,
|
|
25
|
-
includeWords = false,
|
|
26
|
-
}) {
|
|
27
|
-
const inputFile = new Input({
|
|
28
|
-
file: input,
|
|
29
|
-
inputType: inputType,
|
|
30
|
-
filename: filename,
|
|
31
|
-
allowCutPdf: cutPdf,
|
|
32
|
-
});
|
|
33
|
-
await inputFile.init();
|
|
34
|
-
this.apiToken =
|
|
35
|
-
inputFile.fileExtension === "application/pdf"
|
|
36
|
-
? this.invoiceToken
|
|
37
|
-
: this.receiptToken;
|
|
38
|
-
const url =
|
|
39
|
-
inputFile.fileExtension === "application/pdf"
|
|
40
|
-
? `/invoices/v${version}/predict`
|
|
41
|
-
: `/expense_receipts/v${version}/predict`;
|
|
42
|
-
super.parse();
|
|
43
|
-
return super._request(url, inputFile, includeWords);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
module.exports = APIFinancialDocument;
|
package/mindee/api/index.js
DELETED
package/mindee/api/invoice.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
const APIObject = require("./object");
|
|
2
|
-
const Input = require("../inputs");
|
|
3
|
-
|
|
4
|
-
class APIInvoice extends APIObject {
|
|
5
|
-
constructor(apiToken = undefined) {
|
|
6
|
-
super(apiToken, "invoice");
|
|
7
|
-
this.baseUrl = `${this.baseUrl}/invoices/`;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @param {Boolean} includeWords: , extract all words into http_response
|
|
12
|
-
* @param {Boolean} cutPdf: Automatically reconstruct pdf with more than 4 pages
|
|
13
|
-
* @param {String} inputType: String in {'path', 'stream', 'base64'}
|
|
14
|
-
* @param {String} file: Receipt filepath (allowed jpg, png, tiff, pdf)
|
|
15
|
-
* @param {String} version: expense_receipt api version
|
|
16
|
-
* @returns {Response} Wrapped response with Receipts objects parsed
|
|
17
|
-
*/
|
|
18
|
-
async parse({
|
|
19
|
-
input,
|
|
20
|
-
inputType = "path",
|
|
21
|
-
filename = undefined,
|
|
22
|
-
version = "3",
|
|
23
|
-
cutPdf = true,
|
|
24
|
-
includeWords = false,
|
|
25
|
-
}) {
|
|
26
|
-
super.parse();
|
|
27
|
-
const inputFile = new Input({
|
|
28
|
-
file: input,
|
|
29
|
-
inputType: inputType,
|
|
30
|
-
filename: filename,
|
|
31
|
-
allowCutPdf: cutPdf,
|
|
32
|
-
});
|
|
33
|
-
await inputFile.init();
|
|
34
|
-
const url = `v${version}/predict`;
|
|
35
|
-
return await super._request(url, inputFile, includeWords);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
@param {String} inputFile - Input object
|
|
40
|
-
@param {} response - HTTP response
|
|
41
|
-
@param {Document} documentType - Document class in {"Receipt", "Invoice", "Financial_document"}
|
|
42
|
-
@returns {Response}
|
|
43
|
-
*/
|
|
44
|
-
wrapResponse(inputFile, response, documentType) {
|
|
45
|
-
let result = super.wrapResponse(inputFile, response, documentType);
|
|
46
|
-
result.documentType =
|
|
47
|
-
result.httpResponse.data?.predictions?.[0]?.document_type?.value?.toLowerCase() ||
|
|
48
|
-
result.documentType;
|
|
49
|
-
return result;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
module.exports = APIInvoice;
|
package/mindee/api/object.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
const Response = require("./response");
|
|
2
|
-
const errorHandler = require("../errors/handler");
|
|
3
|
-
const request = require("./request");
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Base class for APIs (APIReceipt & APIInvoice)
|
|
7
|
-
* @param {String} apiToken - Token of the API used for parsing document
|
|
8
|
-
* @param {String} apiName - Name of the API used for parsing document
|
|
9
|
-
*/
|
|
10
|
-
class APIObject {
|
|
11
|
-
constructor(apiToken = undefined, apiName = "") {
|
|
12
|
-
this.apiToken = apiToken;
|
|
13
|
-
this.baseUrl = "https://api.mindee.net/v1/products/mindee";
|
|
14
|
-
this.apiName = apiName;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
*/
|
|
19
|
-
parse() {
|
|
20
|
-
if (!this.apiToken) {
|
|
21
|
-
errorHandler.throw({
|
|
22
|
-
error: new Error(
|
|
23
|
-
`Missing API token for ${this.apiName}. \
|
|
24
|
-
Have you create a mindee Client with a ${this.apiName}Token in parameters ?`
|
|
25
|
-
),
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
@param {String} url - API url for request
|
|
32
|
-
@param {Input} inputFile - input file for API
|
|
33
|
-
@param {Boolean} includeWords - Include Mindee vision words in Response
|
|
34
|
-
@returns {Response}
|
|
35
|
-
*/
|
|
36
|
-
async _request(url, inputFile, includeWords = false) {
|
|
37
|
-
const headers = {
|
|
38
|
-
"X-Inferuser-Token": this.apiToken,
|
|
39
|
-
};
|
|
40
|
-
const response = await request(
|
|
41
|
-
`${this.baseUrl}${url}`,
|
|
42
|
-
"POST",
|
|
43
|
-
headers,
|
|
44
|
-
inputFile,
|
|
45
|
-
includeWords
|
|
46
|
-
);
|
|
47
|
-
return this.wrapResponse(inputFile, response, this.apiName);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
@param {String} inputFile - Input object
|
|
52
|
-
@param {} response - HTTP response
|
|
53
|
-
@param {Document} documentType - Document class in {"Receipt", "Invoice", "Financial_document"}
|
|
54
|
-
@returns {Response}
|
|
55
|
-
*/
|
|
56
|
-
wrapResponse(inputFile, response, documentType) {
|
|
57
|
-
if (response.statusCode > 201) {
|
|
58
|
-
const errorMessage = JSON.stringify(response.data, null, 4);
|
|
59
|
-
errorHandler.throw(
|
|
60
|
-
new Error(
|
|
61
|
-
`${this.apiName} API ${response.statusCode} HTTP error: ${errorMessage}`
|
|
62
|
-
),
|
|
63
|
-
false
|
|
64
|
-
);
|
|
65
|
-
return new Response({
|
|
66
|
-
httpResponse: response,
|
|
67
|
-
documentType: documentType,
|
|
68
|
-
document: undefined,
|
|
69
|
-
input: inputFile,
|
|
70
|
-
error: true,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
return new Response({
|
|
74
|
-
httpResponse: response,
|
|
75
|
-
documentType: documentType,
|
|
76
|
-
document: inputFile,
|
|
77
|
-
input: inputFile,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
module.exports = APIObject;
|
package/mindee/api/receipt.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
const APIObject = require("./object");
|
|
2
|
-
const Input = require("../inputs");
|
|
3
|
-
|
|
4
|
-
class APIReceipt extends APIObject {
|
|
5
|
-
constructor(apiToken = undefined) {
|
|
6
|
-
super(apiToken, "receipt");
|
|
7
|
-
this.baseUrl = `${this.baseUrl}/expense_receipts/`;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @param {String} file: Receipt filepath (allowed jpg, png, tiff, pdf)
|
|
12
|
-
* @param {String} inputType: String in {'path', 'stream', 'base64'}
|
|
13
|
-
* @param {Boolean} includeWords: extract all words into http_response
|
|
14
|
-
* @param {String} version: expense_receipt api version
|
|
15
|
-
* @param {Boolean} cutPdf: Automatically reconstruct pdf with more than 4 pages
|
|
16
|
-
* @returns {Response} Wrapped response with Receipts objects parsed
|
|
17
|
-
*/
|
|
18
|
-
async parse({
|
|
19
|
-
input,
|
|
20
|
-
inputType = "path",
|
|
21
|
-
filename = undefined,
|
|
22
|
-
version = "3",
|
|
23
|
-
cutPdf = true,
|
|
24
|
-
includeWords = false,
|
|
25
|
-
}) {
|
|
26
|
-
super.parse();
|
|
27
|
-
const inputFile = new Input({
|
|
28
|
-
file: input,
|
|
29
|
-
inputType: inputType,
|
|
30
|
-
filename: filename,
|
|
31
|
-
allowCutPdf: cutPdf,
|
|
32
|
-
});
|
|
33
|
-
await inputFile.init();
|
|
34
|
-
const url = `v${version}/predict`;
|
|
35
|
-
return await super._request(url, inputFile, includeWords);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
module.exports = APIReceipt;
|
package/mindee/api/request.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
const https = require("https");
|
|
2
|
-
const { version: sdkVersion } = require("../../package.json");
|
|
3
|
-
const { URL } = require("url");
|
|
4
|
-
const FormData = require("form-data");
|
|
5
|
-
const os = require("os");
|
|
6
|
-
|
|
7
|
-
const request = (url, method, headers, input, includeWords = false) => {
|
|
8
|
-
return new Promise(function (resolve, reject) {
|
|
9
|
-
let form = new FormData();
|
|
10
|
-
|
|
11
|
-
headers["User-Agent"] = `mindee-api-nodejs@v${sdkVersion} nodejs-${
|
|
12
|
-
process.version
|
|
13
|
-
} ${os.type().toLowerCase()}`;
|
|
14
|
-
|
|
15
|
-
const fileParams = { filename: input.filename };
|
|
16
|
-
|
|
17
|
-
if (input.inputType === "base64") {
|
|
18
|
-
form.append(
|
|
19
|
-
"document",
|
|
20
|
-
Buffer.from(input.fileObject, "base64"),
|
|
21
|
-
fileParams
|
|
22
|
-
);
|
|
23
|
-
} else {
|
|
24
|
-
form.append("document", input.fileObject, fileParams);
|
|
25
|
-
}
|
|
26
|
-
if (includeWords) {
|
|
27
|
-
form.append("include_mvision", "true");
|
|
28
|
-
}
|
|
29
|
-
headers = { ...headers, ...form.getHeaders() };
|
|
30
|
-
|
|
31
|
-
const uri = new URL(url);
|
|
32
|
-
const options = {
|
|
33
|
-
method: method,
|
|
34
|
-
headers: headers,
|
|
35
|
-
hostname: uri.hostname,
|
|
36
|
-
path: `${uri.pathname}${uri.search}`,
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const req = https.request(options, function (res) {
|
|
40
|
-
let responseBody = [];
|
|
41
|
-
|
|
42
|
-
res.on("data", function (chunk) {
|
|
43
|
-
responseBody += chunk;
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
res.on("end", function () {
|
|
47
|
-
try {
|
|
48
|
-
resolve({
|
|
49
|
-
...res,
|
|
50
|
-
data: JSON.parse(responseBody),
|
|
51
|
-
});
|
|
52
|
-
} catch (error) {
|
|
53
|
-
reject(error);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
req.on("error", (err) => {
|
|
59
|
-
reject(err);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
if (["path", "stream"].includes(input.inputType)) {
|
|
63
|
-
form.pipe(req);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (input.inputType === "base64") {
|
|
67
|
-
form.pipe(req);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
module.exports = request;
|
package/mindee/api/response.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
const Receipt = require("../documents").receipt;
|
|
2
|
-
const Invoice = require("../documents").invoice;
|
|
3
|
-
const FinancialDocument = require("../documents").financialDocument;
|
|
4
|
-
const fs = require("fs").promises;
|
|
5
|
-
|
|
6
|
-
class Response {
|
|
7
|
-
constructor({
|
|
8
|
-
httpResponse,
|
|
9
|
-
documentType,
|
|
10
|
-
input,
|
|
11
|
-
error,
|
|
12
|
-
reconsctruted = false,
|
|
13
|
-
...args
|
|
14
|
-
}) {
|
|
15
|
-
this.httpResponse = httpResponse;
|
|
16
|
-
this.documentType = documentType;
|
|
17
|
-
this.input = input;
|
|
18
|
-
if (!error && !reconsctruted) this.formatResponse();
|
|
19
|
-
if (reconsctruted === true) {
|
|
20
|
-
Object.assign(this, args);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async dump(path) {
|
|
25
|
-
return await fs.writeFile(path, JSON.stringify(Object.entries(this)));
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static async load(path) {
|
|
29
|
-
const file = fs.readFile(path);
|
|
30
|
-
const args = JSON.parse(file);
|
|
31
|
-
return new Response({ reconsctruted: true, ...args });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
formatResponse() {
|
|
35
|
-
let http_data_document = this.httpResponse.data.document;
|
|
36
|
-
const constructors = {
|
|
37
|
-
receipt: (params) => new Receipt(params),
|
|
38
|
-
invoice: (params) => new Invoice(params),
|
|
39
|
-
financialDocument: (params) => new FinancialDocument(params),
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const predictions = http_data_document.inference.pages.entries();
|
|
43
|
-
this[`${this.documentType}s`] = [];
|
|
44
|
-
let document_words_content = [];
|
|
45
|
-
|
|
46
|
-
// Create a list of Document (Receipt, Invoice...) for each page of the input document
|
|
47
|
-
for (const [pageNumber, prediction] of predictions) {
|
|
48
|
-
let page_words_content = [];
|
|
49
|
-
if (
|
|
50
|
-
"ocr" in http_data_document &&
|
|
51
|
-
Object.keys(http_data_document.ocr).length > 0
|
|
52
|
-
) {
|
|
53
|
-
page_words_content =
|
|
54
|
-
http_data_document.ocr["mvision-v1"].pages[pageNumber].all_words;
|
|
55
|
-
document_words_content.push(
|
|
56
|
-
...http_data_document.ocr["mvision-v1"].pages[pageNumber].all_words
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
this[`${this.documentType}s`].push(
|
|
60
|
-
constructors[this.documentType]({
|
|
61
|
-
apiPrediction: prediction.prediction,
|
|
62
|
-
inputFile: this.input,
|
|
63
|
-
pageNumber: pageNumber,
|
|
64
|
-
words: page_words_content,
|
|
65
|
-
})
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Merge the list of Document into a unique Document
|
|
70
|
-
this[this.documentType] = constructors[this.documentType]({
|
|
71
|
-
apiPrediction: http_data_document.inference.prediction,
|
|
72
|
-
inputFile: this.input,
|
|
73
|
-
pageNumber: http_data_document.n_pages,
|
|
74
|
-
level: "document",
|
|
75
|
-
words: document_words_content,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
module.exports = Response;
|