diff --git a/package-lock.json b/package-lock.json index 2e7c0c34..5408cff0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3314,9 +3314,9 @@ } }, "node_modules/eslint-plugin-sonarjs/node_modules/brace-expansion": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { @@ -3573,9 +3573,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", - "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", "dev": true, "funding": [ { @@ -4181,9 +4181,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "dev": true, "funding": [ { @@ -6390,9 +6390,9 @@ } }, "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", "license": "MIT", "engines": { "node": ">=20.18.1" diff --git a/src/v2/clientOptions/baseParameters.ts b/src/v2/clientOptions/baseProductParameters.ts similarity index 73% rename from src/v2/clientOptions/baseParameters.ts rename to src/v2/clientOptions/baseProductParameters.ts index 579172a2..b258101a 100644 --- a/src/v2/clientOptions/baseParameters.ts +++ b/src/v2/clientOptions/baseProductParameters.ts @@ -1,10 +1,9 @@ -import { FormData } from "undici"; import { MindeeConfigurationError } from "@/errors/index.js"; /** * Constructor parameters for BaseParameters and its subclasses. */ -export interface BaseParametersConstructor { +export interface BaseProductParametersConstructor { modelId: string; alias?: string; webhookIds?: string[]; @@ -25,7 +24,7 @@ export interface BaseParametersConstructor { * webhookIds: ["YOUR_WEBHOOK_ID_1", "YOUR_WEBHOOK_ID_2"], * }; */ -export abstract class BaseParameters { +export abstract class BaseProductParameters { /** * Model ID to use for the inference. **Required.** */ @@ -47,7 +46,7 @@ export abstract class BaseParameters { */ closeFile?: boolean; - protected constructor(params: BaseParametersConstructor) { + protected constructor(params: BaseProductParametersConstructor) { if (params.modelId === undefined || params.modelId === null || params.modelId === "") { throw new MindeeConfigurationError("Model ID must be provided"); } @@ -58,20 +57,20 @@ export abstract class BaseParameters { } /** - * Returns the form data to send to the API. - * @returns A `FormData` object. + * Gets the request parameters for the enqueue request. + * @returns A `Record` mapping parameter names to their string values. */ - getFormData(): FormData { - const form = new FormData(); + getRequestParameters(): Record { + const parameters: Record = {}; - form.set("model_id", this.modelId); + parameters["model_id"] = this.modelId; if (this.alias !== undefined && this.alias !== null) { - form.set("alias", this.alias); + parameters["alias"] = this.alias; } if (this.webhookIds && this.webhookIds.length > 0) { - form.set("webhook_ids", this.webhookIds.join(",")); + parameters["webhook_ids"] = this.webhookIds.join(","); } - return form; + return parameters; } } diff --git a/src/v2/clientOptions/baseSearchParameters.ts b/src/v2/clientOptions/baseSearchParameters.ts new file mode 100644 index 00000000..58cddc5d --- /dev/null +++ b/src/v2/clientOptions/baseSearchParameters.ts @@ -0,0 +1,44 @@ +/** + * Constructor parameters for BaseSearchParameters and its subclasses. + */ +export interface BaseSearchParametersConstructor { + page?: number; + perPage?: number; +} + +/** + * Base parameters for searches. + */ +export abstract class BaseSearchParameters { + /** + * 1-based page index. + */ + page?: number; + + /** + * Number of items per page. + */ + perPage?: number; + + protected constructor(params: BaseSearchParametersConstructor) { + this.page = params.page; + this.perPage = params.perPage; + } + + /** + * Gets the request parameters for the search request. + * @returns A `Record` mapping parameter names to their string values. + */ + getRequestParameters(): Record { + const parameters: Record = {}; + + if (this.page !== null && this.page !== undefined && this.page > 0) { + parameters["page"] = this.page.toString(); + } + if (this.perPage !== null && this.perPage !== undefined && this.perPage > 0) { + parameters["per_page"] = this.perPage.toString(); + } + + return parameters; + } +} diff --git a/src/v2/clientOptions/index.ts b/src/v2/clientOptions/index.ts index 4b5dd6a3..4637d0ae 100644 --- a/src/v2/clientOptions/index.ts +++ b/src/v2/clientOptions/index.ts @@ -3,4 +3,5 @@ export type { PollingOptionsConstructor, TimerOptions, } from "./pollingOptions.js"; -export { BaseParameters } from "./baseParameters.js"; +export { BaseProductParameters } from "./baseProductParameters.js"; +export { BaseSearchParameters } from "./baseSearchParameters.js"; diff --git a/src/v2/http/mindeeApiV2.ts b/src/v2/http/mindeeApiV2.ts index f29a058c..2fa4c957 100644 --- a/src/v2/http/mindeeApiV2.ts +++ b/src/v2/http/mindeeApiV2.ts @@ -1,6 +1,7 @@ import { ApiSettings } from "./apiSettings.js"; import { Dispatcher } from "undici"; -import { BaseParameters } from "@/v2/index.js"; +import { BaseProductParameters } from "@/v2/index.js"; +import { FormData } from "undici"; import { BaseResponse, ErrorResponse, @@ -60,9 +61,10 @@ export class MindeeApiV2 { async reqPostProductEnqueue( product: typeof BaseProduct, inputSource: InputSource, - params: BaseParameters + params: BaseProductParameters ): Promise { - const form = params.getFormData(); + const form = this.#paramsToFormData(params.getRequestParameters()); + if (inputSource instanceof LocalInputSource) { form.set("file", new Blob([inputSource.fileObject]), inputSource.filename); } else { @@ -157,6 +159,14 @@ export class MindeeApiV2 { return this.#processResponse(response, product.responseClass) as InstanceType; } + #paramsToFormData(params: Record): FormData { + const form = new FormData(); + for (const [key, value] of Object.entries(params)) { + form.set(key, value); + } + return form; + } + #processResponse( result: BaseHttpResponse, responseClass: ResponseConstructor, diff --git a/src/v2/index.ts b/src/v2/index.ts index d58f6d47..a3d1fc94 100644 --- a/src/v2/index.ts +++ b/src/v2/index.ts @@ -7,5 +7,5 @@ export { ErrorResponse, LocalResponse, } from "./parsing/index.js"; -export type { BaseParameters, TimerOptions } from "./clientOptions/index.js"; +export type { BaseProductParameters, TimerOptions } from "./clientOptions/index.js"; export { PollingOptions } from "./clientOptions/index.js"; diff --git a/src/v2/parsing/search/baseSearchResponse.ts b/src/v2/parsing/search/baseSearchResponse.ts new file mode 100644 index 00000000..97aa28b6 --- /dev/null +++ b/src/v2/parsing/search/baseSearchResponse.ts @@ -0,0 +1,32 @@ +import { StringDict } from "@/parsing/index.js"; +import { BaseResponse } from "@/v2/parsing/baseResponse.js"; +import { PaginationMetadata } from "./paginationMetadata.js"; + +/** Constructor type for a search response class with a static slug property. */ +export type SearchResponseConstructor = + (new (serverResponse: any) => T) & { readonly slug: string }; + + +/** + * Base class for search responses. + */ +export abstract class BaseSearchResponse extends BaseResponse { + /** + * Pagination metadata. + */ + public pagination: PaginationMetadata; + + protected constructor(serverResponse: StringDict) { + super(serverResponse); + this.pagination = new PaginationMetadata(serverResponse["pagination"]); + } + + protected abstract bodyLines(): string[]; + + toString(): string { + const lines: string[] = this.bodyLines(); + lines.push("Pagination Metadata", "###################"); + lines.push(this.pagination.toString()); + return lines.join("\n"); + } +} diff --git a/src/v2/parsing/search/index.ts b/src/v2/parsing/search/index.ts index da3ce8c4..1dc6c464 100644 --- a/src/v2/parsing/search/index.ts +++ b/src/v2/parsing/search/index.ts @@ -2,3 +2,8 @@ export { PaginationMetadata } from "./paginationMetadata.js"; export { SearchModel } from "./searchModel.js"; export { SearchResponse } from "./searchResponse.js"; export { ModelWebhook } from "./modelWebhook.js"; +export { BaseSearchResponse } from "./baseSearchResponse.js"; +export type { SearchResponseConstructor } from "./baseSearchResponse.js"; +export { ModelSearchResponse } from "./modelSearchResponse.js"; +export { RagDocument } from "./ragDocument.js"; +export { RagDocumentSearchResponse } from "./ragDocumentSearchResponse.js"; diff --git a/src/v2/parsing/search/modelSearchResponse.ts b/src/v2/parsing/search/modelSearchResponse.ts new file mode 100644 index 00000000..ef52193e --- /dev/null +++ b/src/v2/parsing/search/modelSearchResponse.ts @@ -0,0 +1,24 @@ +import { StringDict } from "@/parsing/index.js"; +import { BaseSearchResponse } from "./baseSearchResponse.js"; +import { SearchModels } from "./searchModels.js"; + +/** + * Models search response. + */ +export class ModelSearchResponse extends BaseSearchResponse { + static readonly slug = "models"; + + /** + * List of models returned by the search. + */ + public models: SearchModels; + + constructor(serverResponse: StringDict) { + super(serverResponse); + this.models = new SearchModels(serverResponse["models"] ?? []); + } + + protected bodyLines(): string[] { + return ["Models", "#######", this.models.toString()]; + } +} diff --git a/src/v2/parsing/search/ragDocument.ts b/src/v2/parsing/search/ragDocument.ts new file mode 100644 index 00000000..93397c1c --- /dev/null +++ b/src/v2/parsing/search/ragDocument.ts @@ -0,0 +1,53 @@ +import { StringDict } from "@/parsing/index.js"; + +/** + * Individual RAG document information. + */ +export class RagDocument { + /** + * Unique identifier of the RAG document. + */ + public id: string; + + /** + * Model identifier linked to the RAG document. + */ + public modelId: string; + + /** + * Original filename of the uploaded document. + */ + public filename: string; + + /** + * Date and time of the document creation. + */ + public createdAt: Date; + + /** + * Number of times this document was used in an inference. + */ + public totalMatches: number; + + /** + * Date and time of the latest matching inference, if any. + */ + public lastMatchAt?: Date; + + /** + * Current status of the RAG document. + */ + public status: string; + + constructor(serverResponse: StringDict) { + this.id = serverResponse["id"]; + this.modelId = serverResponse["model_id"]; + this.filename = serverResponse["filename"]; + this.createdAt = new Date(serverResponse["created_at"]); + this.totalMatches = serverResponse["total_matches"]; + this.lastMatchAt = serverResponse["last_match_at"] + ? new Date(serverResponse["last_match_at"]) + : undefined; + this.status = serverResponse["status"]; + } +} diff --git a/src/v2/parsing/search/ragDocumentSearchResponse.ts b/src/v2/parsing/search/ragDocumentSearchResponse.ts new file mode 100644 index 00000000..e5dabccc --- /dev/null +++ b/src/v2/parsing/search/ragDocumentSearchResponse.ts @@ -0,0 +1,24 @@ +import { StringDict } from "@/parsing/index.js"; +import { BaseSearchResponse } from "./baseSearchResponse.js"; +import { RagDocuments } from "@/v2/parsing/search/ragDocuments.js"; + +/** + * RAG documents search response. + */ +export class RagDocumentSearchResponse extends BaseSearchResponse { + static readonly slug = "rag-documents"; + + /** + * Paginated list of matching RAG documents. + */ + public ragDocuments: RagDocuments; + + constructor(serverResponse: StringDict) { + super(serverResponse); + this.ragDocuments = new RagDocuments(serverResponse["rag_documents"] ?? []); + } + + protected bodyLines(): string[] { + return ["RAG Documents", "################", this.ragDocuments.toString()]; + } +} diff --git a/src/v2/parsing/search/ragDocuments.ts b/src/v2/parsing/search/ragDocuments.ts new file mode 100644 index 00000000..033ebdca --- /dev/null +++ b/src/v2/parsing/search/ragDocuments.ts @@ -0,0 +1,32 @@ +import { RagDocument } from "@/v2/parsing/search/ragDocument.js"; +import { StringDict } from "@/parsing/index.js"; + +/** + * List of RAG documents. + */ +export class RagDocuments extends Array { + + constructor(serverResponse: StringDict) { + super(); + this.push(...(serverResponse ?? []).map( + (item: StringDict) => new RagDocument(item) + )); + } + + toString(): string { + if (this.length === 0) { + return "\n"; + } + const lines: string[] = []; + for (const ragDocument of this) { + lines.push(`* :ID: ${ragDocument.id}`); + lines.push(` :Model ID: ${ragDocument.modelId}`); + lines.push(` :Filename: ${ragDocument.filename}`); + lines.push(` :Created At: ${ragDocument.createdAt}`); + lines.push(` :Total Matches: ${ragDocument.totalMatches}`); + lines.push(` :Last Match At: ${ragDocument.lastMatchAt}`); + lines.push(` :Status: ${ragDocument.status}`); + } + return lines.join("\n"); + } +} diff --git a/src/v2/parsing/search/searchModels.ts b/src/v2/parsing/search/searchModels.ts new file mode 100644 index 00000000..2fab1564 --- /dev/null +++ b/src/v2/parsing/search/searchModels.ts @@ -0,0 +1,26 @@ +import { SearchModel } from "@/v2/parsing/search/searchModel.js"; +import { StringDict } from "@/parsing/index.js"; + +export class SearchModels extends Array { + + constructor(serverResponse: StringDict) { + super(); + this.push(...(serverResponse ?? []).map( + (item: StringDict) => new SearchModel(item) + )); + } + + toString(): string { + if (this.length === 0) { + return "\n"; + } + const lines: string[] = []; + for (const model of this) { + lines.push(`* :Name: ${model.name}`); + lines.push(` :ID: ${model.id}`); + lines.push(` :Model Type: ${model.modelType}`); + } + return lines.join("\n"); + } + +} diff --git a/src/v2/parsing/search/searchResponse.ts b/src/v2/parsing/search/searchResponse.ts index 4a3a1ecf..2435b11b 100644 --- a/src/v2/parsing/search/searchResponse.ts +++ b/src/v2/parsing/search/searchResponse.ts @@ -1,39 +1,12 @@ import { StringDict } from "@/parsing/index.js"; -import { BaseResponse } from "@/v2/parsing/baseResponse.js"; -import { PaginationMetadata } from "./paginationMetadata.js"; -import { SearchModel } from "./searchModel.js"; +import { ModelSearchResponse } from "./modelSearchResponse.js"; /** * Models search response. + * @deprecated Use `ModelSearchResponse` instead. */ -export class SearchResponse extends BaseResponse { - /** - * List of models returned by the search. - */ - public models: SearchModel[]; - - /** - * Pagination metadata. - */ - public pagination: PaginationMetadata; - +export class SearchResponse extends ModelSearchResponse { constructor(serverResponse: StringDict) { super(serverResponse); - this.models = (serverResponse["models"] ?? []).map( - (model: StringDict) => new SearchModel(model) - ); - this.pagination = new PaginationMetadata(serverResponse["pagination"]); - } - - toString(): string { - const lines: string[] = ["Models", "#######"]; - for (const model of this.models) { - lines.push(`* :Name: ${model.name}`); - lines.push(` :ID: ${model.id}`); - lines.push(` :Model Type: ${model.modelType}`); - } - lines.push("Pagination", "##########"); - lines.push(this.pagination.toString()); - return lines.join("\n"); } } diff --git a/src/v2/product/baseProduct.ts b/src/v2/product/baseProduct.ts index 0ff28734..cc980159 100644 --- a/src/v2/product/baseProduct.ts +++ b/src/v2/product/baseProduct.ts @@ -1,4 +1,4 @@ -import { BaseParameters } from "@/v2/index.js"; +import { BaseProductParameters } from "@/v2/index.js"; import { ResponseConstructor } from "@/v2/parsing/index.js"; /** @@ -7,7 +7,7 @@ import { ResponseConstructor } from "@/v2/parsing/index.js"; * Child classes are passed to the Client when making requests. */ export abstract class BaseProduct { - static get parametersClass(): new (...args: any[]) => BaseParameters { + static get parametersClass(): new (...args: any[]) => BaseProductParameters { throw new Error("Must define static parameters property"); } static get responseClass(): ResponseConstructor { diff --git a/src/v2/product/classification/params/classificationParameters.ts b/src/v2/product/classification/params/classificationParameters.ts index acef9cbf..16c5f47f 100644 --- a/src/v2/product/classification/params/classificationParameters.ts +++ b/src/v2/product/classification/params/classificationParameters.ts @@ -1,4 +1,4 @@ -import { BaseParameters, BaseParametersConstructor } from "@/v2/clientOptions/baseParameters.js"; +import { BaseProductParameters, BaseProductParametersConstructor } from "@/v2/clientOptions/baseProductParameters.js"; import { logger } from "@/logger.js"; /** @@ -18,8 +18,8 @@ import { logger } from "@/logger.js"; * } * }; */ -export class ClassificationParameters extends BaseParameters { - constructor(params: BaseParametersConstructor & {}) { +export class ClassificationParameters extends BaseProductParameters { + constructor(params: BaseProductParametersConstructor & {}) { super({ ...params }); logger.debug("Classification parameters initialized."); } diff --git a/src/v2/product/crop/params/cropParameters.ts b/src/v2/product/crop/params/cropParameters.ts index 1c2a6fb9..33cfeb3a 100644 --- a/src/v2/product/crop/params/cropParameters.ts +++ b/src/v2/product/crop/params/cropParameters.ts @@ -1,4 +1,4 @@ -import { BaseParameters, BaseParametersConstructor } from "@/v2/clientOptions/baseParameters.js"; +import { BaseProductParameters, BaseProductParametersConstructor } from "@/v2/clientOptions/baseProductParameters.js"; import { logger } from "@/logger.js"; /** @@ -18,8 +18,8 @@ import { logger } from "@/logger.js"; * } * }; */ -export class CropParameters extends BaseParameters { - constructor(params: BaseParametersConstructor & {}) { +export class CropParameters extends BaseProductParameters { + constructor(params: BaseProductParametersConstructor & {}) { super({ ...params }); logger.debug("Crop parameters initialized."); } diff --git a/src/v2/product/extraction/params/extractionParameters.ts b/src/v2/product/extraction/params/extractionParameters.ts index 6bb8124e..adce2738 100644 --- a/src/v2/product/extraction/params/extractionParameters.ts +++ b/src/v2/product/extraction/params/extractionParameters.ts @@ -1,7 +1,6 @@ -import { FormData } from "undici"; import { StringDict } from "@/parsing/stringDict.js"; import { DataSchema } from "./dataSchema.js"; -import { BaseParameters, BaseParametersConstructor } from "@/v2/clientOptions/baseParameters.js"; +import { BaseProductParameters, BaseProductParametersConstructor } from "@/v2/clientOptions/baseProductParameters.js"; import { logger } from "@/logger.js"; /** @@ -22,7 +21,7 @@ import { logger } from "@/logger.js"; * } * }; */ -export class ExtractionParameters extends BaseParameters { +export class ExtractionParameters extends BaseProductParameters { /** * Use Retrieval-Augmented Generation during inference. */ @@ -51,7 +50,7 @@ export class ExtractionParameters extends BaseParameters { */ dataSchema?: DataSchema | StringDict | string; - constructor(params: BaseParametersConstructor & { + constructor(params: BaseProductParametersConstructor & { rag?: boolean; rawText?: boolean; polygon?: boolean; @@ -76,32 +75,28 @@ export class ExtractionParameters extends BaseParameters { logger.debug("Extraction parameters initialized."); } - getFormData(): FormData { - const form = new FormData(); - - form.set("model_id", this.modelId); + getRequestParameters(): Record { + const parameters = super.getRequestParameters(); if (this.rag !== undefined && this.rag !== null) { - form.set("rag", this.rag.toString()); + parameters["rag"] = this.rag.toString(); } if (this.polygon !== undefined && this.polygon !== null) { - form.set("polygon", this.polygon.toString().toLowerCase()); + parameters["polygon"] = this.polygon.toString().toLowerCase(); } if (this.confidence !== undefined && this.confidence !== null) { - form.set("confidence", this.confidence.toString().toLowerCase()); + parameters["confidence"] = this.confidence.toString().toLowerCase(); } if (this.rawText !== undefined && this.rawText !== null) { - form.set("raw_text", this.rawText.toString().toLowerCase()); + parameters["raw_text"] = this.rawText.toString().toLowerCase(); } if (this.textContext !== undefined && this.textContext !== null) { - form.set("text_context", this.textContext); + parameters["text_context"] = this.textContext; } if (this.dataSchema !== undefined && this.dataSchema !== null) { - form.set("data_schema", this.dataSchema.toString()); - } - if (this.webhookIds && this.webhookIds.length > 0) { - form.set("webhook_ids", this.webhookIds.join(",")); + parameters["data_schema"] = this.dataSchema.toString(); } - return form; + + return parameters; } } diff --git a/src/v2/product/ocr/params/ocrParameters.ts b/src/v2/product/ocr/params/ocrParameters.ts index 340ec412..2c408c32 100644 --- a/src/v2/product/ocr/params/ocrParameters.ts +++ b/src/v2/product/ocr/params/ocrParameters.ts @@ -1,4 +1,4 @@ -import { BaseParameters, BaseParametersConstructor } from "@/v2/clientOptions/baseParameters.js"; +import { BaseProductParameters, BaseProductParametersConstructor } from "@/v2/clientOptions/baseProductParameters.js"; import { logger } from "@/logger.js"; /** @@ -18,8 +18,8 @@ import { logger } from "@/logger.js"; * } * }; */ -export class OcrParameters extends BaseParameters { - constructor(params: BaseParametersConstructor & {}) { +export class OcrParameters extends BaseProductParameters { + constructor(params: BaseProductParametersConstructor & {}) { super({ ...params }); logger.debug("OCR parameters initialized."); } diff --git a/src/v2/product/split/params/splitParameters.ts b/src/v2/product/split/params/splitParameters.ts index d9a49d8c..fd90ae29 100644 --- a/src/v2/product/split/params/splitParameters.ts +++ b/src/v2/product/split/params/splitParameters.ts @@ -1,7 +1,7 @@ import { - BaseParameters, - BaseParametersConstructor, -} from "@/v2/clientOptions/baseParameters.js"; + BaseProductParameters, + BaseProductParametersConstructor, +} from "@/v2/clientOptions/baseProductParameters.js"; import { logger } from "@/logger.js"; /** @@ -21,8 +21,8 @@ import { logger } from "@/logger.js"; * } * }; */ -export class SplitParameters extends BaseParameters { - constructor(params: BaseParametersConstructor & {}) { +export class SplitParameters extends BaseProductParameters { + constructor(params: BaseProductParametersConstructor & {}) { super({ ...params }); logger.debug("Split parameters initialized."); } diff --git a/src/v2/search/models/index.ts b/src/v2/search/models/index.ts new file mode 100644 index 00000000..4b5b7f1c --- /dev/null +++ b/src/v2/search/models/index.ts @@ -0,0 +1,2 @@ +export { ModelSearchParameters } from "./modelSearchParameters.js"; +export type { ModelSearchParametersConstructor } from "./modelSearchParameters.js"; diff --git a/src/v2/search/models/modelSearchParameters.ts b/src/v2/search/models/modelSearchParameters.ts new file mode 100644 index 00000000..c01bb31d --- /dev/null +++ b/src/v2/search/models/modelSearchParameters.ts @@ -0,0 +1,42 @@ +import { BaseSearchParameters, BaseSearchParametersConstructor } from "@/v2/clientOptions/baseSearchParameters.js"; + +/** + * Constructor parameters for ModelSearchParameters. + */ +export interface ModelSearchParametersConstructor extends BaseSearchParametersConstructor { + name?: string; + modelType?: string; +} + +/** + * Search parameters for models. + */ +export class ModelSearchParameters extends BaseSearchParameters { + /** + * Case-insensitive search term for the model name + */ + name?: string; + + /** + * Case-insensitive search term for the model type + */ + modelType?: string; + + constructor(params: ModelSearchParametersConstructor = {}) { + super(params); + this.name = params.name; + this.modelType = params.modelType; + } + + /** @inheritdoc */ + getRequestParameters(): Record { + const parameters = super.getRequestParameters(); + if (this.name) { + parameters["name"] = this.name; + } + if (this.modelType) { + parameters["model_type"] = this.modelType; + } + return parameters; + } +} diff --git a/src/v2/search/ragDocuments/index.ts b/src/v2/search/ragDocuments/index.ts new file mode 100644 index 00000000..30411a2e --- /dev/null +++ b/src/v2/search/ragDocuments/index.ts @@ -0,0 +1,2 @@ +export { RagDocumentSearchParameters } from "./ragDocumentSearchParameters.js"; +export type { RagDocumentSearchParametersConstructor } from "./ragDocumentSearchParameters.js"; diff --git a/src/v2/search/ragDocuments/ragDocumentSearchParameters.ts b/src/v2/search/ragDocuments/ragDocumentSearchParameters.ts new file mode 100644 index 00000000..6e78eab2 --- /dev/null +++ b/src/v2/search/ragDocuments/ragDocumentSearchParameters.ts @@ -0,0 +1,45 @@ +import { MindeeConfigurationError } from "@/errors/index.js"; +import { BaseSearchParameters, BaseSearchParametersConstructor } from "@/v2/clientOptions/baseSearchParameters.js"; + +/** + * Constructor parameters for RagDocumentSearchParameters. + */ +export interface RagDocumentSearchParametersConstructor extends BaseSearchParametersConstructor { + modelId?: string; + filename?: string; +} + +/** + * Search parameters for RAG Documents. + */ +export class RagDocumentSearchParameters extends BaseSearchParameters { + /** + * Model identifier to search in. + */ + modelId?: string; + + /** + * Case-insensitive substring search on filename. + */ + filename?: string; + + constructor(params: RagDocumentSearchParametersConstructor = {}) { + super(params); + this.modelId = params.modelId; + this.filename = params.filename; + } + + /** @inheritdoc */ + getRequestParameters(): Record { + const parameters = super.getRequestParameters(); + if (this.modelId) { + parameters["model_id"] = this.modelId; + } else { + throw new MindeeConfigurationError("ModelId is required in RagDocumentSearchParameters"); + } + if (this.filename) { + parameters["filename"] = this.filename; + } + return parameters; + } +} diff --git a/tests/data b/tests/data index e41ab97c..4b7f3376 160000 --- a/tests/data +++ b/tests/data @@ -1 +1 @@ -Subproject commit e41ab97c2833f15ea5c4edf221c2d197d212f632 +Subproject commit 4b7f33766fab0e67804b84447b73c80a902d886a diff --git a/tests/v1/extraction/invoiceSplitter.integration.ts b/tests/v1/extraction/invoiceSplitter.integration.ts index d09bd897..582d53bc 100644 --- a/tests/v1/extraction/invoiceSplitter.integration.ts +++ b/tests/v1/extraction/invoiceSplitter.integration.ts @@ -11,7 +11,7 @@ import { hasAllOptionalDependencies } from "../../helpers/optionalDeps.js"; const hasOptionals = hasAllOptionalDependencies(); describe("MindeeV1 - Integration - InvoiceSplitterV1 #OptionalDepsRequired", - { timeout: 60000, skip: !hasOptionals }, () => { + { timeout: 80000, skip: !hasOptionals }, () => { let client: mindee.v1.Client; beforeEach(() => { diff --git a/tests/v1/extraction/multiReceipts.integration.ts b/tests/v1/extraction/multiReceipts.integration.ts index 0ef87aa0..c766cab6 100644 --- a/tests/v1/extraction/multiReceipts.integration.ts +++ b/tests/v1/extraction/multiReceipts.integration.ts @@ -14,7 +14,7 @@ const apiKey = process.env.MINDEE_API_KEY; let client: Client; let sourceDoc: LocalInputSource; describe("MindeeV1 - Integration - Multi-Receipt Extraction #OptionalDepsRequired", - { timeout: 60000, skip: !hasOptionals }, () => { + { timeout: 80000, skip: !hasOptionals }, () => { describe("A Multi-Receipt PDF", () => { before(async () => { sourceDoc = new PathInput({ diff --git a/tests/v1/extras/extras.integration.ts b/tests/v1/extras/extras.integration.ts index f9822f2d..37721e65 100644 --- a/tests/v1/extras/extras.integration.ts +++ b/tests/v1/extras/extras.integration.ts @@ -5,7 +5,7 @@ import path from "path"; import { V1_PRODUCT_PATH } from "../../index.js"; -describe("MindeeV1 - Integration - Extras", { timeout: 70000 }, () => { +describe("MindeeV1 - Integration - Extras", { timeout: 80000 }, () => { let client: mindee.v1.Client; beforeEach(() => { diff --git a/tests/v1/input/sources.integration.ts b/tests/v1/input/sources.integration.ts index f3476b39..d62b08e5 100644 --- a/tests/v1/input/sources.integration.ts +++ b/tests/v1/input/sources.integration.ts @@ -8,7 +8,7 @@ import { InvoiceV4 } from "@/v1/product/index.js"; import { V1_PRODUCT_PATH } from "../../index.js"; import { PathInput, Base64Input, BufferInput, BytesInput, UrlInput } from "@/index.js"; -describe("MindeeV1 - Integration - File Input", { timeout: 60000 }, () => { +describe("MindeeV1 - Integration - File Input", { timeout: 80000 }, () => { let client: mindee.v1.Client; let filePath: string; diff --git a/tests/v1/input/urlInputSource.integration.ts b/tests/v1/input/urlInputSource.integration.ts index f5b79af1..92d4f3fd 100644 --- a/tests/v1/input/urlInputSource.integration.ts +++ b/tests/v1/input/urlInputSource.integration.ts @@ -4,7 +4,7 @@ import { UrlInput } from "@/index.js"; import { Client } from "@/v1/index.js"; import { InvoiceV4 } from "@/v1/product/index.js"; -describe("MindeeV1 - Integration - URL Input", { timeout: 60000 }, () => { +describe("MindeeV1 - Integration - URL Input", { timeout: 80000 }, () => { it("should retrieve and parse a remote file with redirection", async () => { const apiKey = process.env.MINDEE_API_KEY; if (!apiKey) { diff --git a/tests/v1/workflows/workflow.integration.ts b/tests/v1/workflows/workflow.integration.ts index 25cc1e74..dfb9e5ef 100644 --- a/tests/v1/workflows/workflow.integration.ts +++ b/tests/v1/workflows/workflow.integration.ts @@ -9,7 +9,7 @@ import { FinancialDocumentV1 } from "@/v1/product/index.js"; import { RAGExtra } from "@/v1/parsing/common/extras/ragExtra.js"; import { V1_PRODUCT_PATH } from "../../index.js"; -describe("MindeeV1 - Integration - Workflow calls", { timeout: 60000 }, () => { +describe("MindeeV1 - Integration - Workflow calls", { timeout: 80000 }, () => { let client: mindee.v1.Client; let sample: LocalInputSource; let workflowId: string; diff --git a/tests/v2/parsing/search.spec.ts b/tests/v2/parsing/search.spec.ts deleted file mode 100644 index 4c84de98..00000000 --- a/tests/v2/parsing/search.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import path from "path"; -import assert from "node:assert/strict"; -import { describe, it } from "node:test"; - -import { LocalResponse } from "@/v2/index.js"; -import { SearchResponse } from "@/v2/parsing/search/index.js"; -import { V2_RESOURCE_PATH } from "../../index.js"; - -const filePath = path.join(V2_RESOURCE_PATH, "search/models.json"); - -describe("MindeeV2 - Search Models", () => { - it("should load search models locally", async () => { - const localResponse = new LocalResponse(filePath); - const response = await localResponse.deserializeResponse(SearchResponse); - - assert.ok(response instanceof SearchResponse); - - assert.strictEqual(response.models.length, 5); - assert.strictEqual(response.pagination.totalItems, 5); - assert.strictEqual(response.pagination.page, 1); - assert.strictEqual(response.pagination.perPage, 50); - assert.strictEqual(response.pagination.totalPages, 1); - - const firstModel = response.models[0]; - assert.strictEqual(firstModel.name, "Extraction With Webhooks"); - assert.strictEqual(firstModel.id, "afde5151-aa11-aa11-9289-fa04e50ca3b9"); - assert.strictEqual(firstModel.modelType, "extraction"); - - assert.strictEqual(firstModel.webhooks.length, 2); - assert.strictEqual(firstModel.webhooks[0].id, "a2286ed9-aa11-aa11-bdc5-2f8496c5641a"); - assert.strictEqual(firstModel.webhooks[0].name, "FAILURE"); - assert.strictEqual(firstModel.webhooks[0].url, "https://failure.mindee.com"); - - const lastModel = response.models[response.models.length - 1]; - assert.strictEqual(lastModel.name, "Extraction Without Webhooks Key"); - assert.strictEqual(lastModel.id, "e14e0923-ee55-ee55-a335-8d2110917d7b"); - }); -}); diff --git a/tests/v2/search/modelSearch.spec.ts b/tests/v2/search/modelSearch.spec.ts new file mode 100644 index 00000000..3e96ab8a --- /dev/null +++ b/tests/v2/search/modelSearch.spec.ts @@ -0,0 +1,38 @@ +import path from "path"; +import assert from "node:assert/strict"; +import { describe, it } from "node:test"; + +import { LocalResponse } from "@/v2/index.js"; +import { ModelSearchResponse } from "src/v2/parsing/search/index.js"; +import { V2_RESOURCE_PATH } from "../../index.js"; + +const filePath = path.join(V2_RESOURCE_PATH, "search/models.json"); + +describe("MindeeV2 - Search Models", () => { + it("should load search models locally", async () => { + const localResponse = new LocalResponse(filePath); + const response = await localResponse.deserializeResponse(ModelSearchResponse); + + assert.ok(response instanceof ModelSearchResponse); + + assert.strictEqual(response.models.length, 5); + assert.strictEqual(response.pagination.totalItems, 5); + assert.strictEqual(response.pagination.page, 1); + assert.strictEqual(response.pagination.perPage, 50); + assert.strictEqual(response.pagination.totalPages, 1); + + const firstItem = response.models[0]; + assert.strictEqual(firstItem.name, "Extraction With Webhooks"); + assert.strictEqual(firstItem.id, "afde5151-aa11-aa11-9289-fa04e50ca3b9"); + assert.strictEqual(firstItem.modelType, "extraction"); + + assert.strictEqual(firstItem.webhooks.length, 2); + assert.strictEqual(firstItem.webhooks[0].id, "a2286ed9-aa11-aa11-bdc5-2f8496c5641a"); + assert.strictEqual(firstItem.webhooks[0].name, "FAILURE"); + assert.strictEqual(firstItem.webhooks[0].url, "https://failure.mindee.com"); + + const lastItem = response.models[response.models.length - 1]; + assert.strictEqual(lastItem.name, "Extraction Without Webhooks Key"); + assert.strictEqual(lastItem.id, "e14e0923-ee55-ee55-a335-8d2110917d7b"); + }); +}); diff --git a/tests/v2/search/ragDocumentSearch.spec.ts b/tests/v2/search/ragDocumentSearch.spec.ts new file mode 100644 index 00000000..976f049f --- /dev/null +++ b/tests/v2/search/ragDocumentSearch.spec.ts @@ -0,0 +1,50 @@ +import assert from "node:assert/strict"; +import { describe, it } from "node:test"; +import path from "path"; +import { V2_RESOURCE_PATH } from "../../index.js"; +import { LocalResponse } from "@/v2/index.js"; +import { RagDocumentSearchResponse } from "@/v2/parsing/search/index.js"; + +const filePath = path.join(V2_RESOURCE_PATH, "search/rag_documents.json"); + +describe("MindeeV2 - Search RAG Documents", () => { + it("should load search RAG Documents locally", async () => { + const localResponse = new LocalResponse(filePath); + const response = await localResponse.deserializeResponse(RagDocumentSearchResponse); + + assert.ok(response instanceof RagDocumentSearchResponse); + + assert.strictEqual(response.ragDocuments.length, 3); + assert.strictEqual(response.pagination.totalItems, 3); + assert.strictEqual(response.pagination.page, 1); + assert.strictEqual(response.pagination.perPage, 50); + assert.strictEqual(response.pagination.totalPages, 1); + + const firstItem = response.ragDocuments[0]; + assert.strictEqual(firstItem.id, "cc831599-c545-48b7-aa27-6d7ccd5b8d32"); + assert.strictEqual(firstItem.modelId, "12345678-1234-1234-1234-123456789abc"); + assert.strictEqual(firstItem.filename, "invoice_01.pdf"); + assert.deepStrictEqual(firstItem.createdAt, new Date("2026-06-30T13:13:46.168586Z")); + assert.strictEqual(firstItem.totalMatches, 0); + assert.strictEqual(firstItem.lastMatchAt, undefined); + assert.strictEqual(firstItem.status, "Processing"); + + const secondItem = response.ragDocuments[1]; + assert.strictEqual(secondItem.id, "27467e4c-5602-4315-90d9-3d2da69b05ab"); + assert.strictEqual(secondItem.modelId, "12345678-1234-1234-1234-123456789abc"); + assert.strictEqual(secondItem.filename, "invoice_02.pdf"); + assert.deepStrictEqual(secondItem.createdAt, new Date("2026-06-30T13:13:46.168586Z")); + assert.strictEqual(secondItem.totalMatches, 0); + assert.strictEqual(secondItem.lastMatchAt, undefined); + assert.strictEqual(secondItem.status, "Draft"); + + const thirdItem = response.ragDocuments[2]; + assert.strictEqual(thirdItem.id, "a6bcae7d-0439-476b-8a63-5a39ec05dc21"); + assert.strictEqual(thirdItem.modelId, "12345678-1234-1234-1234-jobid1234567"); + assert.strictEqual(thirdItem.filename, "invoice_03.pdf"); + assert.deepStrictEqual(thirdItem.createdAt, new Date("2026-06-17T14:35:46.228006Z")); + assert.strictEqual(thirdItem.totalMatches, 5); + assert.deepStrictEqual(thirdItem.lastMatchAt, new Date("2026-06-18T14:35:46.248006Z")); + assert.strictEqual(thirdItem.status, "Active"); + }); +});