Skip to content

Commit 498bc48

Browse files
authored
♻️ rework local and input sources (#376)
1 parent 792408d commit 498bc48

20 files changed

+104
-125
lines changed

.github/workflows/_test-code-samples.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ jobs:
1111
strategy:
1212
matrix:
1313
node-version:
14-
- "18"
1514
- "20"
1615
- "22"
1716
- "24"

.github/workflows/_test-units.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ jobs:
1818
- "18"
1919
- "20"
2020
- "22"
21+
- "24"
2122
runs-on: ${{ matrix.os }}
2223

2324
steps:

src/client.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,11 @@ export class Client {
255255
* @returns A valid prediction
256256
*/
257257
try {
258-
if (Object.prototype.hasOwnProperty.call(localResponse.asDict(), "job")) {
259-
return new AsyncPredictResponse(productClass, localResponse.asDict());
258+
const asDict = await localResponse.asDict();
259+
if (Object.prototype.hasOwnProperty.call(asDict, "job")) {
260+
return new AsyncPredictResponse(productClass, asDict);
260261
}
261-
return new PredictResponse(productClass, localResponse.asDict());
262+
return new PredictResponse(productClass, asDict);
262263
} catch {
263264
throw new MindeeError("No prediction found in local response.");
264265
}

src/clientV2.ts

Lines changed: 7 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
import {
2-
Base64Input, BufferInput, BytesInput, InputSource,
3-
PathInput, StreamInput, UrlInput,
4-
} from "./input";
1+
import { InputSource } from "./input";
52
import { errorHandler } from "./errors/handler";
63
import { LOG_LEVELS, logger } from "./logger";
74

85
import { setTimeout } from "node:timers/promises";
96
import { ErrorResponse, InferenceResponse, JobResponse } from "./parsing/v2";
107
import { MindeeApiV2 } from "./http/mindeeApiV2";
118
import { MindeeHttpErrorV2 } from "./errors/mindeeError";
12-
import { Readable } from "stream";
139

1410
/**
1511
* Parameters for the internal polling loop in {@link ClientV2.enqueueAndGetInference | enqueueAndGetInference()} .
@@ -160,6 +156,9 @@ export class ClientV2 {
160156
if (inputSource === undefined) {
161157
throw new Error("The 'enqueue' function requires an input document.");
162158
}
159+
if (!inputSource.isInitialized()) {
160+
await inputSource.init();
161+
}
163162
return await this.mindeeApi.reqPostInferenceEnqueue(inputSource, params);
164163
}
165164

@@ -232,19 +231,19 @@ export class ClientV2 {
232231
* Send a document to an endpoint and poll the server until the result is sent or
233232
* until the maximum number of tries is reached.
234233
*
235-
* @param inputDoc document to parse.
234+
* @param inputSource file or URL to parse.
236235
* @param params parameters relating to prediction options.
237236
*
238237
* @typeParam T an extension of an `Inference`. Can be omitted as it will be inferred from the `productClass`.
239238
* @category Synchronous
240239
* @returns a `Promise` containing parsing results.
241240
*/
242241
async enqueueAndGetInference(
243-
inputDoc: InputSource,
242+
inputSource: InputSource,
244243
params: InferenceParameters
245244
): Promise<InferenceResponse> {
246245
const validatedAsyncParams = this.#setAsyncParams(params.pollingOptions);
247-
const enqueueResponse: JobResponse = await this.enqueueInference(inputDoc, params);
246+
const enqueueResponse: JobResponse = await this.enqueueInference(inputSource, params);
248247
if (enqueueResponse.job.id === undefined || enqueueResponse.job.id.length === 0) {
249248
logger.error(`Failed enqueueing:\n${enqueueResponse.getRawHttp()}`);
250249
throw Error("Enqueueing of the document failed.");
@@ -283,72 +282,4 @@ Job status: ${pollResults.job.status}.`
283282
" seconds"
284283
);
285284
}
286-
287-
/**
288-
* Load an input source from a local path.
289-
* @param inputPath
290-
*/
291-
sourceFromPath(inputPath: string): PathInput {
292-
return new PathInput({
293-
inputPath: inputPath,
294-
});
295-
}
296-
297-
/**
298-
* Load an input source from a base64 encoded string.
299-
* @param inputString input content, as a string.
300-
* @param filename file name.
301-
*/
302-
sourceFromBase64(inputString: string, filename: string): Base64Input {
303-
return new Base64Input({
304-
inputString: inputString,
305-
filename: filename,
306-
});
307-
}
308-
309-
/**
310-
* Load an input source from a `stream.Readable` object.
311-
* @param inputStream input content, as a readable stream.
312-
* @param filename file name.
313-
*/
314-
sourceFromStream(inputStream: Readable, filename: string): StreamInput {
315-
return new StreamInput({
316-
inputStream: inputStream,
317-
filename: filename,
318-
});
319-
}
320-
321-
/**
322-
* Load an input source from bytes.
323-
* @param inputBytes input content, as a Uint8Array or Buffer.
324-
* @param filename file name.
325-
*/
326-
sourceFromBytes(inputBytes: Uint8Array, filename: string): BytesInput {
327-
return new BytesInput({
328-
inputBytes: inputBytes,
329-
filename: filename,
330-
});
331-
}
332-
333-
/**
334-
* Load an input source from a Buffer.
335-
* @param buffer input content, as a buffer.
336-
* @param filename file name.
337-
*/
338-
sourceFromBuffer(buffer: Buffer, filename: string): BufferInput {
339-
return new BufferInput({
340-
buffer: buffer,
341-
filename: filename,
342-
});
343-
}
344-
345-
/**
346-
* Load an input source from a URL.
347-
* @param url input url. Must be HTTPS.
348-
*/
349-
sourceFromUrl(url: string): UrlInput {
350-
return new UrlInput({
351-
url: url,
352-
});
353-
}
354285
}

src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export * as product from "./product";
2-
export { Client, PredictOptions } from "./client";
2+
export { Client, PredictOptions, WorkflowOptions } from "./client";
33
export { ClientV2, InferenceParameters, PollingOptions } from "./clientV2";
44
export {
55
AsyncPredictResponse,
@@ -9,6 +9,10 @@ export {
99
Document,
1010
Page,
1111
} from "./parsing/common";
12+
export {
13+
InferenceResponse,
14+
JobResponse,
15+
} from "./parsing/v2";
1216
export {
1317
InputSource,
1418
Base64Input,

src/input/localResponse.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { CommonResponse } from "../parsing/v2";
1212
export class LocalResponse {
1313
private file: Buffer;
1414
private readonly inputHandle: Buffer | string;
15+
protected initialized = false;
1516

1617
/**
1718
* Creates an instance of LocalResponse.
@@ -39,13 +40,17 @@ export class LocalResponse {
3940
} else {
4041
throw new MindeeError("Incompatible type for input.");
4142
}
43+
this.initialized = true;
4244
}
4345

4446
/**
4547
* Returns the dictionary representation of the file.
4648
* @returns A JSON-like object.
4749
*/
48-
asDict(): StringDict {
50+
async asDict(): Promise<StringDict> {
51+
if (!this.initialized) {
52+
await this.init();
53+
}
4954
try {
5055
const content = this.file.toString("utf-8");
5156
return JSON.parse(content);
@@ -60,6 +65,11 @@ export class LocalResponse {
6065
* @returns The HMAC signature of the local response.
6166
*/
6267
getHmacSignature(secretKey: string | Buffer | Uint8Array): string {
68+
if (!this.initialized) {
69+
throw new Error(
70+
"The `init()` method must be called before calling `getHmacSignature()`."
71+
);
72+
}
6373
const algorithm = "sha256";
6474
try {
6575
const hmac = crypto.createHmac(algorithm, secretKey);
@@ -76,7 +86,12 @@ export class LocalResponse {
7686
* @param signature - The signature to be compared with.
7787
* @returns True if the HMAC signature is valid.
7888
*/
79-
isValidHmacSignature(secretKey: string | Buffer | Uint8Array, signature: string): boolean {
89+
public isValidHmacSignature(secretKey: string | Buffer | Uint8Array, signature: string): boolean {
90+
if (!this.initialized) {
91+
throw new Error(
92+
"The `init()` method must be called before calling `isValidHmacSignature()`."
93+
);
94+
}
8095
return signature === this.getHmacSignature(secretKey);
8196
}
8297

@@ -90,11 +105,11 @@ export class LocalResponse {
90105
* @returns An instance of `responseClass` populated with the file content.
91106
* @throws MindeeError If the provided class cannot be instantiated.
92107
*/
93-
public deserializeResponse<ResponseT extends CommonResponse>(
108+
public async deserializeResponse<ResponseT extends CommonResponse>(
94109
responseClass: new (serverResponse: StringDict) => ResponseT
95-
): ResponseT {
110+
): Promise<ResponseT> {
96111
try {
97-
return new responseClass(this.asDict());
112+
return new responseClass(await this.asDict());
98113
} catch {
99114
throw new MindeeError("Invalid response provided.");
100115
}

src/input/sources/base64Input.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ export class Base64Input extends LocalInputSource {
2323
this.mimeType = await this.checkMimetype();
2424
// clear out the string
2525
this.inputString = "";
26+
this.initialized = true;
2627
}
2728
}

src/input/sources/bufferInput.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ export class BufferInput extends LocalInputSource {
1717

1818
async init(): Promise<void> {
1919
this.mimeType = await this.checkMimetype();
20+
this.initialized = true;
2021
}
2122
}

src/input/sources/bytesInput.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ export class BytesInput extends LocalInputSource {
2222
this.fileObject = Buffer.from(this.inputBytes);
2323
this.mimeType = await this.checkMimetype();
2424
this.inputBytes = new Uint8Array(0);
25+
this.initialized = true;
2526
}
2627
}

src/input/sources/inputSource.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@ export const INPUT_TYPE_BUFFER = "buffer";
1414

1515
export abstract class InputSource {
1616
fileObject: Buffer | string = "";
17+
protected initialized: boolean = false;
1718

1819
async init() {
1920
throw new Error("not Implemented");
2021
}
21-
}
2222

23+
public isInitialized() {
24+
return this.initialized;
25+
}
26+
}

0 commit comments

Comments
 (0)