mindee 4.35.0 → 4.36.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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v4.36.1 - 2025-12-30
4
+ ### Fixes
5
+ * :bug: extracted images should take rotation into account
6
+ * :recycle: fix minor issues with param syntaxes
7
+
8
+
9
+ ## v4.36.0 - 2025-12-19
10
+ ### Changes
11
+ * :sparkles: add support for dataschema param
12
+
13
+
3
14
  ## v4.35.0 - 2025-12-16
4
15
  ### Changes
5
16
  * :sparkles: add multi-receipt custom file saving formats
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mindee",
3
- "version": "4.35.0",
3
+ "version": "4.36.1",
4
4
  "description": "Mindee Client Library for Node.js",
5
5
  "main": "src/index.js",
6
6
  "bin": "bin/mindee.js",
package/src/clientV2.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { InputSource } from "./input";
1
+ import { DataSchema, InputSource } from "./input";
2
2
  import { InferenceResponse, JobResponse } from "./parsing/v2";
3
3
  import { MindeeApiV2 } from "./http/mindeeApiV2";
4
+ import { StringDict } from "./parsing/common";
4
5
  /**
5
6
  * Parameters for the internal polling loop in {@link ClientV2.enqueueAndGetInference | enqueueAndGetInference()} .
6
7
  *
@@ -88,6 +89,11 @@ export interface InferenceParameters {
88
89
  /** By default, the file is closed once the upload is finished.
89
90
  * Set to `false` to keep it open. */
90
91
  closeFile?: boolean;
92
+ /**
93
+ * Dynamic changes to the data schema of the model for this inference.
94
+ * Not recommended, for specific use only.
95
+ */
96
+ dataSchema?: DataSchema | StringDict | string;
91
97
  }
92
98
  /**
93
99
  * Options for the V2 Mindee Client.
@@ -121,6 +127,11 @@ export declare class ClientV2 {
121
127
  * @param {ClientOptions} options options for the initialization of a client.
122
128
  */
123
129
  constructor({ apiKey, throwOnError, debug }?: ClientOptions);
130
+ /**
131
+ * Checks the Data Schema.
132
+ * @param params Input Inference parameters.
133
+ */
134
+ validateDataSchema(params: InferenceParameters): void;
124
135
  /**
125
136
  * Send the document to an asynchronous endpoint and return its ID in the queue.
126
137
  * @param inputSource file or URL to parse.
package/src/clientV2.js CHANGED
@@ -7,6 +7,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
7
7
  var _ClientV2_instances, _ClientV2_setAsyncParams;
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.ClientV2 = void 0;
10
+ const input_1 = require("./input");
10
11
  const handler_1 = require("./errors/handler");
11
12
  const logger_1 = require("./logger");
12
13
  const promises_1 = require("node:timers/promises");
@@ -35,6 +36,17 @@ class ClientV2 {
35
36
  : logger_1.LOG_LEVELS["warn"];
36
37
  logger_1.logger.debug("ClientV2 initialized");
37
38
  }
39
+ /**
40
+ * Checks the Data Schema.
41
+ * @param params Input Inference parameters.
42
+ */
43
+ validateDataSchema(params) {
44
+ if (params.dataSchema !== undefined && params.dataSchema !== null) {
45
+ if (!(params.dataSchema instanceof input_1.DataSchema)) {
46
+ params.dataSchema = new input_1.DataSchema(params.dataSchema);
47
+ }
48
+ }
49
+ }
38
50
  /**
39
51
  * Send the document to an asynchronous endpoint and return its ID in the queue.
40
52
  * @param inputSource file or URL to parse.
@@ -46,6 +58,7 @@ class ClientV2 {
46
58
  if (inputSource === undefined) {
47
59
  throw new Error("The 'enqueue' function requires an input document.");
48
60
  }
61
+ this.validateDataSchema(params);
49
62
  await inputSource.init();
50
63
  return await this.mindeeApi.reqPostInferenceEnqueue(inputSource, params);
51
64
  }
@@ -44,3 +44,4 @@ export declare function getMinYCoordinate(polygon: Array<Point>): number;
44
44
  export declare function getMinXCoordinate(polygon: Array<Point>): number;
45
45
  export declare function compareOnY(polygon1: Array<Point>, polygon2: Array<Point>): number;
46
46
  export declare function compareOnX(polygon1: Array<Point>, polygon2: Array<Point>): number;
47
+ export declare function adjustForRotation(polygon: Array<Point>, orientation: number): Array<Point>;
@@ -13,6 +13,7 @@ exports.getMinYCoordinate = getMinYCoordinate;
13
13
  exports.getMinXCoordinate = getMinXCoordinate;
14
14
  exports.compareOnY = compareOnY;
15
15
  exports.compareOnX = compareOnX;
16
+ exports.adjustForRotation = adjustForRotation;
16
17
  /**
17
18
  * Get the central point (centroid) given a list of points.
18
19
  */
@@ -124,3 +125,15 @@ function compareOnX(polygon1, polygon2) {
124
125
  }
125
126
  return sort < 0 ? -1 : 1;
126
127
  }
128
+ function adjustForRotation(polygon, orientation) {
129
+ if (orientation === 90) {
130
+ return polygon.map(([x, y]) => [y, 1 - x]);
131
+ }
132
+ if (orientation === 180) {
133
+ return polygon.map(([x, y]) => [1 - x, 1 - y]);
134
+ }
135
+ if (orientation === 270) {
136
+ return polygon.map(([x, y]) => [1 - y, x]);
137
+ }
138
+ return polygon;
139
+ }
@@ -102,6 +102,9 @@ _MindeeApiV2_instances = new WeakSet(), _MindeeApiV2_processResponse = function
102
102
  if (params.textContext !== undefined && params.textContext !== null) {
103
103
  form.append("text_context", params.textContext);
104
104
  }
105
+ if (params.dataSchema !== undefined && params.dataSchema !== null) {
106
+ form.append("data_schema", params.dataSchema.toString());
107
+ }
105
108
  if (params.webhookIds && params.webhookIds.length > 0) {
106
109
  form.append("webhook_ids", params.webhookIds.join(","));
107
110
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.extractFromPage = extractFromPage;
4
4
  const pdf_lib_1 = require("@cantoo/pdf-lib");
5
5
  const geometry_1 = require("../../geometry");
6
+ const polygonUtils_1 = require("../../geometry/polygonUtils");
6
7
  /**
7
8
  * Extracts elements from a page based off of a list of bounding boxes.
8
9
  *
@@ -15,7 +16,9 @@ async function extractFromPage(pdfPage, polygons) {
15
16
  // Manual upscale.
16
17
  // Fixes issues with the OCR.
17
18
  const qualityScale = 300 / 72;
18
- for (const polygon of polygons) {
19
+ const orientation = pdfPage.getRotation().angle;
20
+ for (const origPolygon of polygons) {
21
+ const polygon = (0, polygonUtils_1.adjustForRotation)(origPolygon, orientation);
19
22
  const tempPdf = await pdf_lib_1.PDFDocument.create();
20
23
  const newWidth = width * ((0, geometry_1.getMinMaxX)(polygon).max - (0, geometry_1.getMinMaxX)(polygon).min);
21
24
  const newHeight = height * ((0, geometry_1.getMinMaxY)(polygon).max - (0, geometry_1.getMinMaxY)(polygon).min);
@@ -25,17 +28,59 @@ async function extractFromPage(pdfPage, polygons) {
25
28
  top: height - ((0, geometry_1.getMinMaxY)(polygon).min * height),
26
29
  bottom: height - ((0, geometry_1.getMinMaxY)(polygon).max * height),
27
30
  });
28
- const samplePage = tempPdf.addPage([newWidth * qualityScale, newHeight * qualityScale]);
31
+ // Determine the final page dimensions based on orientation
32
+ let finalWidth;
33
+ let finalHeight;
34
+ if (orientation === 90 || orientation === 270) {
35
+ // For 90/270 rotations, swap width and height
36
+ finalWidth = newHeight * qualityScale;
37
+ finalHeight = newWidth * qualityScale;
38
+ }
39
+ else {
40
+ finalWidth = newWidth * qualityScale;
41
+ finalHeight = newHeight * qualityScale;
42
+ }
43
+ const samplePage = tempPdf.addPage([finalWidth, finalHeight]);
29
44
  samplePage.drawRectangle({
30
45
  x: 0,
31
46
  y: 0,
32
- width: newWidth * qualityScale,
33
- height: newHeight * qualityScale,
34
- });
35
- samplePage.drawPage(cropped, {
36
- width: newWidth * qualityScale,
37
- height: newHeight * qualityScale,
47
+ width: finalWidth,
48
+ height: finalHeight,
38
49
  });
50
+ // Draw the cropped page with rotation applied
51
+ if (orientation === 0) {
52
+ samplePage.drawPage(cropped, {
53
+ width: newWidth * qualityScale,
54
+ height: newHeight * qualityScale,
55
+ });
56
+ }
57
+ else if (orientation === 90) {
58
+ samplePage.drawPage(cropped, {
59
+ x: 0,
60
+ y: finalHeight,
61
+ width: newWidth * qualityScale,
62
+ height: newHeight * qualityScale,
63
+ rotate: (0, pdf_lib_1.degrees)(270),
64
+ });
65
+ }
66
+ else if (orientation === 180) {
67
+ samplePage.drawPage(cropped, {
68
+ x: finalWidth,
69
+ y: finalHeight,
70
+ width: newWidth * qualityScale,
71
+ height: newHeight * qualityScale,
72
+ rotate: (0, pdf_lib_1.degrees)(180),
73
+ });
74
+ }
75
+ else if (orientation === 270) {
76
+ samplePage.drawPage(cropped, {
77
+ x: finalWidth,
78
+ y: 0,
79
+ width: newWidth * qualityScale,
80
+ height: newHeight * qualityScale,
81
+ rotate: (0, pdf_lib_1.degrees)(90),
82
+ });
83
+ }
39
84
  extractedElements.push(await tempPdf.save());
40
85
  }
41
86
  return extractedElements;
@@ -65,6 +65,7 @@ async function extractReceipts(inputFile, inference) {
65
65
  const pdfDoc = await loadPdfDoc(inputFile);
66
66
  for (let pageId = 0; pageId < pdfDoc.getPageCount(); pageId++) {
67
67
  const [page] = await pdfDoc.copyPages(pdfDoc, [pageId]);
68
+ page.setRotation((0, pdf_lib_1.degrees)(inference.pages[pageId].orientation?.value ?? 0));
68
69
  const receiptPositions = inference.pages[pageId].prediction.receipts.map((receipt) => receipt.boundingBox);
69
70
  const extractedReceipts = await extractReceiptsFromPage(page, receiptPositions, pageId);
70
71
  images.push(...extractedReceipts);
@@ -0,0 +1,73 @@
1
+ import { StringDict } from "../parsing/common";
2
+ export declare class DataSchemaField {
3
+ /**
4
+ * Display name for the field, also impacts inference results.
5
+ */
6
+ title: string;
7
+ /**
8
+ * Name of the field in the data schema.
9
+ */
10
+ name: string;
11
+ /**
12
+ * Whether this field can contain multiple values.
13
+ */
14
+ isArray: boolean;
15
+ /**
16
+ * Data type of the field.
17
+ */
18
+ type: string;
19
+ /**
20
+ * Allowed values when type is `classification`. Leave empty for other types.
21
+ */
22
+ classificationValues?: Array<string>;
23
+ /**
24
+ * Whether to remove duplicate values in the array.
25
+ * Only applicable if `is_array` is True.
26
+ */
27
+ uniqueValues?: boolean;
28
+ /**
29
+ * Detailed description of what this field represents.
30
+ */
31
+ description?: string;
32
+ /**
33
+ * Optional extraction guidelines.
34
+ */
35
+ guidelines?: string;
36
+ /**
37
+ * Subfields when type is `nested_object`. Leave empty for other types.
38
+ */
39
+ nestedFields?: StringDict;
40
+ constructor(fields: StringDict);
41
+ toJSON(): Record<string, unknown>;
42
+ toString(): string;
43
+ }
44
+ /**
45
+ * The structure to completely replace the data schema of the model.
46
+ */
47
+ export declare class DataSchemaReplace {
48
+ /**
49
+ * List of fields in the Data Schema.
50
+ */
51
+ fields: Array<DataSchemaField>;
52
+ constructor(dataSchemaReplace: StringDict);
53
+ toJSON(): {
54
+ fields: Record<string, unknown>[];
55
+ };
56
+ toString(): string;
57
+ }
58
+ /**
59
+ * Modify the Data Schema.
60
+ */
61
+ export declare class DataSchema {
62
+ /**
63
+ * If set, completely replaces the data schema of the model.
64
+ */
65
+ replace?: DataSchemaReplace;
66
+ constructor(dataSchema: StringDict | string);
67
+ toJSON(): {
68
+ replace: {
69
+ fields: Record<string, unknown>[];
70
+ } | undefined;
71
+ };
72
+ toString(): string;
73
+ }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DataSchema = exports.DataSchemaReplace = exports.DataSchemaField = void 0;
4
+ const errors_1 = require("../errors");
5
+ class DataSchemaField {
6
+ constructor(fields) {
7
+ this.name = fields["name"];
8
+ this.title = fields["title"];
9
+ this.isArray = fields["is_array"];
10
+ this.type = fields["type"];
11
+ this.classificationValues = fields["classification_values"];
12
+ this.uniqueValues = fields["unique_values"];
13
+ this.description = fields["description"];
14
+ this.guidelines = fields["guidelines"];
15
+ this.nestedFields = fields["nested_fields"];
16
+ }
17
+ toJSON() {
18
+ const out = {
19
+ name: this.name,
20
+ title: this.title,
21
+ // eslint-disable-next-line @typescript-eslint/naming-convention,camelcase
22
+ is_array: this.isArray,
23
+ type: this.type,
24
+ };
25
+ // eslint-disable-next-line camelcase
26
+ if (this.classificationValues !== undefined)
27
+ out.classification_values = this.classificationValues;
28
+ // eslint-disable-next-line camelcase
29
+ if (this.uniqueValues !== undefined)
30
+ out.unique_values = this.uniqueValues;
31
+ if (this.description !== undefined)
32
+ out.description = this.description;
33
+ if (this.guidelines !== undefined)
34
+ out.guidelines = this.guidelines;
35
+ // eslint-disable-next-line camelcase
36
+ if (this.nestedFields !== undefined)
37
+ out.nested_fields = this.nestedFields;
38
+ return out;
39
+ }
40
+ toString() {
41
+ return JSON.stringify(this.toJSON());
42
+ }
43
+ }
44
+ exports.DataSchemaField = DataSchemaField;
45
+ /**
46
+ * The structure to completely replace the data schema of the model.
47
+ */
48
+ class DataSchemaReplace {
49
+ constructor(dataSchemaReplace) {
50
+ if (!dataSchemaReplace || !dataSchemaReplace.fields) {
51
+ throw new errors_1.MindeeError("Invalid Data Schema provided.");
52
+ }
53
+ if (dataSchemaReplace["fields"].length === 0) {
54
+ throw new TypeError("Data Schema replacement fields cannot be empty.");
55
+ }
56
+ this.fields = dataSchemaReplace["fields"].map((field) => (new DataSchemaField(field)));
57
+ }
58
+ toJSON() {
59
+ return { fields: this.fields.map(e => e.toJSON()) };
60
+ }
61
+ toString() {
62
+ return JSON.stringify(this.toJSON());
63
+ }
64
+ }
65
+ exports.DataSchemaReplace = DataSchemaReplace;
66
+ /**
67
+ * Modify the Data Schema.
68
+ */
69
+ class DataSchema {
70
+ constructor(dataSchema) {
71
+ if (typeof dataSchema === "string") {
72
+ this.replace = new DataSchemaReplace(JSON.parse(dataSchema)["replace"]);
73
+ }
74
+ else if (dataSchema instanceof DataSchema) {
75
+ this.replace = dataSchema.replace;
76
+ }
77
+ else {
78
+ this.replace = new DataSchemaReplace(dataSchema["replace"]);
79
+ }
80
+ }
81
+ toJSON() {
82
+ return { replace: this.replace?.toJSON() };
83
+ }
84
+ toString() {
85
+ return JSON.stringify(this.toJSON());
86
+ }
87
+ }
88
+ exports.DataSchema = DataSchema;
@@ -1,3 +1,4 @@
1
- export { PageOptions, PageOptionsOperation } from "./pageOptions";
1
+ export { DataSchema, DataSchemaField, DataSchemaReplace } from "./dataSchema";
2
2
  export * from "./sources";
3
3
  export { LocalResponse } from "./localResponse";
4
+ export { PageOptions, PageOptionsOperation } from "./pageOptions";
@@ -14,9 +14,13 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.LocalResponse = exports.PageOptionsOperation = void 0;
18
- var pageOptions_1 = require("./pageOptions");
19
- Object.defineProperty(exports, "PageOptionsOperation", { enumerable: true, get: function () { return pageOptions_1.PageOptionsOperation; } });
17
+ exports.PageOptionsOperation = exports.LocalResponse = exports.DataSchemaReplace = exports.DataSchemaField = exports.DataSchema = void 0;
18
+ var dataSchema_1 = require("./dataSchema");
19
+ Object.defineProperty(exports, "DataSchema", { enumerable: true, get: function () { return dataSchema_1.DataSchema; } });
20
+ Object.defineProperty(exports, "DataSchemaField", { enumerable: true, get: function () { return dataSchema_1.DataSchemaField; } });
21
+ Object.defineProperty(exports, "DataSchemaReplace", { enumerable: true, get: function () { return dataSchema_1.DataSchemaReplace; } });
20
22
  __exportStar(require("./sources"), exports);
21
23
  var localResponse_1 = require("./localResponse");
22
24
  Object.defineProperty(exports, "LocalResponse", { enumerable: true, get: function () { return localResponse_1.LocalResponse; } });
25
+ var pageOptions_1 = require("./pageOptions");
26
+ Object.defineProperty(exports, "PageOptionsOperation", { enumerable: true, get: function () { return pageOptions_1.PageOptionsOperation; } });
@@ -0,0 +1,12 @@
1
+ import { StringDict } from "../common";
2
+ /**
3
+ * Data schema options activated during the inference.
4
+ */
5
+ export declare class DataSchemaActiveOption {
6
+ /**
7
+ * Whether to replace the data schema.
8
+ */
9
+ replace: boolean;
10
+ constructor(serverResponse: StringDict);
11
+ toString(): string;
12
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DataSchemaActiveOption = void 0;
4
+ /**
5
+ * Data schema options activated during the inference.
6
+ */
7
+ class DataSchemaActiveOption {
8
+ constructor(serverResponse) {
9
+ this.replace = serverResponse["replace"];
10
+ }
11
+ toString() {
12
+ return `Data Schema\n-----------\n:Replace: ${this.replace ? "True" : "False"}`;
13
+ }
14
+ }
15
+ exports.DataSchemaActiveOption = DataSchemaActiveOption;
@@ -1,4 +1,5 @@
1
1
  import { StringDict } from "../common";
2
+ import { DataSchemaActiveOption } from "./dataSchemaActiveOption";
2
3
  export declare class InferenceActiveOptions {
3
4
  /**
4
5
  * Whether the RAG feature was activated.
@@ -20,6 +21,10 @@ export declare class InferenceActiveOptions {
20
21
  * Whether the text context feature was activated.
21
22
  */
22
23
  textContext: boolean;
24
+ /**
25
+ * Data schema options provided for the inference.
26
+ */
27
+ dataSchema: DataSchemaActiveOption;
23
28
  constructor(serverResponse: StringDict);
24
29
  toString(): string;
25
30
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InferenceActiveOptions = void 0;
4
+ const dataSchemaActiveOption_1 = require("./dataSchemaActiveOption");
4
5
  class InferenceActiveOptions {
5
6
  constructor(serverResponse) {
6
7
  this.rag = serverResponse["rag"];
@@ -8,6 +9,7 @@ class InferenceActiveOptions {
8
9
  this.polygon = serverResponse["polygon"];
9
10
  this.confidence = serverResponse["confidence"];
10
11
  this.textContext = serverResponse["text_context"];
12
+ this.dataSchema = new dataSchemaActiveOption_1.DataSchemaActiveOption(serverResponse["data_schema"]);
11
13
  }
12
14
  toString() {
13
15
  return "Active Options\n" +
@@ -15,7 +17,9 @@ class InferenceActiveOptions {
15
17
  `:Raw Text: ${this.rawText ? "True" : "False"}\n` +
16
18
  `:Polygon: ${this.polygon ? "True" : "False"}\n` +
17
19
  `:Confidence: ${this.confidence ? "True" : "False"}\n` +
18
- `:RAG: ${this.rag ? "True" : "False"}\n`;
20
+ `:RAG: ${this.rag ? "True" : "False"}\n` +
21
+ `:Text Context: ${this.textContext ? "True" : "False"}\n\n` +
22
+ `${this.dataSchema}\n`;
19
23
  }
20
24
  }
21
25
  exports.InferenceActiveOptions = InferenceActiveOptions;