Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
npm run lint:full
npm run lint
npm run lint:package
6 changes: 4 additions & 2 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
npm test
npm run lint:full
npm run lint
npm run lint:package
npm run lint:secrets
npm run license:check
npm run docs
npm test
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,9 @@
"test:integration:light": "node tests/runner.mjs integration",
"test:v2": "tsc --noEmit && node tests/runner.mjs spec v2",
"lint": "tsc --noEmit && eslint --report-unused-disable-directives './src/**/*.ts' './tests/**/*.ts'",
"lint:check": "npm run lint",
"lint:fix": "tsc --noEmit && eslint --fix --report-unused-disable-directives './src/**/*.ts' './tests/**/*.ts'",
"lint:package": "npm run build:dist && publint ./dist && attw --pack ./dist --profile esm-only",
"lint:secrets": "secretlint '**/*'",
"lint:full": "npm run lint:check && npm run lint:package && npm run lint:secrets",
"license:check": "license-checker-rseidelsohn --onlyAllow \"MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;LGPL-3.0-or-later;Python-2.0;BlueOak-1.0.0;CC-BY-3.0;CC0-1.0;0BSD;LGPL-3.0-only;WTFPL;Artistic-2.0;Unlicense\"",
"docs": "typedoc --out docs/_build ./src/index.ts",
"docs:dist": "typedoc --out docs/_build ./src/index.ts && cp -r ./docs/code_samples ./docs/_build/",
Expand Down
26 changes: 25 additions & 1 deletion src/v2/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { MindeeApiV2 } from "./http/mindeeApiV2.js";
import { MindeeHttpErrorV2 } from "./http/errors.js";
import { PollingOptions, PollingOptionsConstructor } from "./clientOptions/index.js";
import { BaseProduct } from "@/v2/product/baseProduct.js";
import { BaseSearch } from "@/v2/search/baseSearch.js";
import { ModelSearch } from "@/v2/search/models/modelSearch.js";

/**
* Options for the V2 Mindee Client.
Expand Down Expand Up @@ -60,9 +62,31 @@ export class Client {
* @param name Optional name filter.
* @param modelType Optional model type filter.
* @returns a `Promise` containing the search response.
* @deprecated Use `search(ModelSearch, {})` instead.
*/
async searchModels(name?: string, modelType?: string): Promise<SearchResponse> {
return await this.mindeeApi.reqGetSearchModel(name, modelType);
return await this.search(ModelSearch, { name: name, modelType: modelType });
}

/**
* Searches for resources matching the given criteria.
* @param search
* @param searchParameters Search parameters.
* @returns a `Promise` containing the search response.
*/
async search<S extends typeof BaseSearch>(
search: S,
searchParameters: InstanceType<S["parametersClass"]> | ConstructorParameters<S["parametersClass"]>[0],
): Promise<InstanceType<S["responseClass"]>> {
if (!searchParameters) {
throw new MindeeError("Search parameters are required.");
}

const paramsInstance = searchParameters instanceof search.parametersClass
? searchParameters
: new search.parametersClass(searchParameters);

return await this.mindeeApi.reqGetSearch(search, paramsInstance);
}

/** Enqueues a product inference job without waiting for completion. */
Expand Down
Original file line number Diff line number Diff line change
@@ -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[];
Expand All @@ -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.**
*/
Expand All @@ -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");
}
Expand All @@ -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<string, string> {
const parameters: Record<string, string> = {};

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;
}
}
44 changes: 44 additions & 0 deletions src/v2/clientOptions/baseSearchParameters.ts
Original file line number Diff line number Diff line change
@@ -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<string, string> {
const parameters: Record<string, string> = {};

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;
}
}
3 changes: 2 additions & 1 deletion src/v2/clientOptions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
39 changes: 25 additions & 14 deletions src/v2/http/mindeeApiV2.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ApiSettings } from "./apiSettings.js";
import { Dispatcher } from "undici";
import { BaseParameters } from "@/v2/index.js";
import { BaseProductParameters } from "@/v2/index.js";
import { BaseSearchParameters } from "@/v2/clientOptions/baseSearchParameters.js";
import { FormData } from "undici";
import {
BaseResponse,
ErrorResponse,
Expand All @@ -17,7 +19,7 @@ import { MindeeDeserializationError, MindeeError } from "@/errors/index.js";
import { MindeeHttpErrorV2 } from "./errors.js";
import { logger } from "@/logger.js";
import { BaseProduct } from "@/v2/product/baseProduct.js";
import { SearchResponse } from "@/v2/parsing/search/index.js";
import { BaseSearch } from "@/v2/search/baseSearch.js";

/**
* Mindee V2 API handler.
Expand All @@ -30,25 +32,25 @@ export class MindeeApiV2 {
}

/**
* Search for models available to the account.
* @param name Optional name filter.
* @param modelType Optional model type filter.
* Searches for resources matching the given criteria.
* @param search
* @param parameters Search parameters.
* @returns a `Promise` containing the search response.
*/
async reqGetSearchModel(name?: string, modelType?: string): Promise<SearchResponse> {
const queryParams: Record<string, string> = {};
if (name) queryParams["name"] = name;
if (modelType) queryParams["model_type"] = modelType;
async reqGetSearch<S extends typeof BaseSearch>(
search: S,
parameters: BaseSearchParameters
): Promise<InstanceType<S["responseClass"]>> {
const options: RequestOptions = {
method: "GET",
headers: this.settings.baseHeaders,
hostname: this.settings.hostname,
path: "/v2/search/models",
queryParams: queryParams,
path: `/v2/search/${search.slug}`,
queryParams: parameters.getRequestParameters(),
timeoutSecs: this.settings.timeoutSecs,
};
const response: BaseHttpResponse = await sendRequestAndReadResponse(this.settings.dispatcher, options);
return this.#processResponse(response, SearchResponse);
return this.#processResponse(response, search.responseClass) as InstanceType<S["responseClass"]>;
}

/**
Expand All @@ -60,9 +62,10 @@ export class MindeeApiV2 {
async reqPostProductEnqueue(
product: typeof BaseProduct,
inputSource: InputSource,
params: BaseParameters
params: BaseProductParameters
): Promise<JobResponse> {
const form = params.getFormData();
const form = this.#paramsToFormData(params.getRequestParameters());

if (inputSource instanceof LocalInputSource) {
form.set("file", new Blob([inputSource.fileObject]), inputSource.filename);
} else {
Expand Down Expand Up @@ -157,6 +160,14 @@ export class MindeeApiV2 {
return this.#processResponse(response, product.responseClass) as InstanceType<P["responseClass"]>;
}

#paramsToFormData(params: Record<string, string>): FormData {
const form = new FormData();
for (const [key, value] of Object.entries(params)) {
form.set(key, value);
}
return form;
}

#processResponse<T extends BaseResponse>(
result: BaseHttpResponse,
responseClass: ResponseConstructor<T>,
Expand Down
3 changes: 2 additions & 1 deletion src/v2/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
export * as http from "./http/index.js";
export * as parsing from "./parsing/index.js";
export * as product from "./product/index.js";
export * as search from "./search/index.js";
export { Client } from "./client.js";
export {
JobResponse,
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";
26 changes: 13 additions & 13 deletions src/v2/parsing/inference/field/listField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ export class ListField extends BaseField {
*/
public items: Array<ListField | ObjectField | SimpleField>;

constructor(serverResponse: StringDict, indentLevel = 0) {
super(serverResponse, indentLevel);

if (!Array.isArray(serverResponse["items"])) {
throw new MindeeDeserializationError(
`Expected "items" to be an array in ${JSON.stringify(serverResponse)}.`
);
}
this.items = serverResponse["items"].map((item) => {
return createField(item, indentLevel + 1);
});
}

/**
* SimpleField items from the list.
*/
Expand Down Expand Up @@ -48,19 +61,6 @@ export class ListField extends BaseField {
return result;
}

constructor(serverResponse: StringDict, indentLevel = 0) {
super(serverResponse, indentLevel);

if (!Array.isArray(serverResponse["items"])) {
throw new MindeeDeserializationError(
`Expected "items" to be an array in ${JSON.stringify(serverResponse)}.`
);
}
this.items = serverResponse["items"].map((item) => {
return createField(item, indentLevel + 1);
});
}

/** Returns a readable representation of list items. */
toString(): string {
if (!this.items || this.items.length === 0) {
Expand Down
30 changes: 30 additions & 0 deletions src/v2/parsing/search/baseSearchResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { StringDict } from "@/parsing/index.js";
import { BaseResponse } from "@/v2/parsing/baseResponse.js";
import { PaginationMetadata } from "./paginationMetadata.js";

/**
* 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"]);
}

/**
* List of strings representing the search response.
*/
protected abstract bodyLines(): string[];

toString(): string {
const lines: string[] = this.bodyLines();
lines.push("Pagination Metadata", "###################");
lines.push(this.pagination.toString());
return lines.join("\n");
}
}
2 changes: 2 additions & 0 deletions src/v2/parsing/search/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ 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 { SearchRagDocument } from "./searchRagDocument.js";
24 changes: 24 additions & 0 deletions src/v2/parsing/search/searchModels.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { SearchModel } from "@/v2/parsing/search/searchModel.js";
import { StringDict } from "@/parsing/index.js";

export class SearchModels extends Array<SearchModel> {

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");
}

}
Loading