diff --git a/lib/package-lock.json b/lib/package-lock.json index cd8408c..2172eb5 100644 --- a/lib/package-lock.json +++ b/lib/package-lock.json @@ -20,7 +20,7 @@ "rollup-plugin-web-worker-loader": "^1.6.0", "ts-loader": "^8.0.17", "tslib": "^2.1.0", - "typescript": "^4.1.5", + "typescript": "4.6.2", "worker-loader": "^3.0.8" } }, @@ -860,9 +860,9 @@ "dev": true }, "node_modules/typescript": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", - "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", + "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -1586,9 +1586,9 @@ "dev": true }, "typescript": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", - "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", + "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", "dev": true }, "universalify": { diff --git a/lib/package.json b/lib/package.json index 1bb11d5..24c230e 100644 --- a/lib/package.json +++ b/lib/package.json @@ -33,7 +33,7 @@ "rollup-plugin-web-worker-loader": "^1.6.0", "ts-loader": "^8.0.17", "tslib": "^2.1.0", - "typescript": "^4.1.5", + "typescript": "^4.6.2", "worker-loader": "^3.0.8" } } diff --git a/lib/src/interfaces.ts b/lib/src/interfaces.ts index 31865e4..eb8caa2 100644 --- a/lib/src/interfaces.ts +++ b/lib/src/interfaces.ts @@ -94,11 +94,13 @@ export interface ServerMessageLoadResult { export interface ServerMessageError { event: "error"; + recognizerId?: string; error: string; } export interface ServerMessageResult { event: "result"; + recognizerId: string; result: { result: Array<{ conf: number; @@ -111,6 +113,7 @@ export interface ServerMessageResult { } export interface ServerMessagePartialResult { event: "partialresult"; + recognizerId: string; result: { partial: string; }; @@ -127,19 +130,20 @@ export namespace ModelMessage { } export type RecognizerMessage = | ServerMessagePartialResult - | ServerMessageResult; + | ServerMessageResult + | ServerMessageError; export type RecognizerEvent = RecognizerMessage["event"]; export type ServerMessage = ModelMessage | RecognizerMessage; export namespace ServerMessage { - export function isRecognizerMessage(message: ServerMessage): boolean { - return ["result", "partialresult"].includes(message.event); + export function isRecognizerMessage(message: ServerMessage): message is RecognizerMessage { + return ["result", "partialresult"].includes(message.event) || Reflect.has(message, 'recognizerId'); } export function isResult(message: any): message is ServerMessageResult { - return message?.result?.text != null; + return message?.result?.text != null || message?.result?.result != null; } export function isPartialResult( diff --git a/lib/src/model.ts b/lib/src/model.ts index e206214..e9c74cb 100644 --- a/lib/src/model.ts +++ b/lib/src/model.ts @@ -22,6 +22,7 @@ export class Model extends EventTarget { private _ready: boolean = false; private messagePort: MessagePort; private logger: Logger = new Logger(); + private recognizers = new Map(); constructor(private modelUrl: string, logLevel: number = 0) { super(); @@ -51,7 +52,7 @@ export class Model extends EventTarget { private postMessage( message: T, - options?: PostMessageOptions + options?: StructuredSerializeOptions ) { this.worker.postMessage(message, options); } @@ -63,7 +64,16 @@ export class Model extends EventTarget { this._ready = message.result; } - this.dispatchEvent(new CustomEvent(message.event, { detail: message })); + const event = new CustomEvent(message.event, { detail: message }); + if (ServerMessage.isRecognizerMessage(message) && message.recognizerId) { + const recognizer = this.recognizers.get(message.recognizerId); + if (recognizer) { + recognizer.dispatchEvent(event); + return; + } + } + + this.dispatchEvent(event); } } @@ -115,6 +125,14 @@ export class Model extends EventTarget { ); } + public registerRecognizer(recognizer: KaldiRecognizer) { + this.recognizers.set(recognizer.id, recognizer); + } + + public unregisterRecognizer(recognizerId: string) { + this.recognizers.delete(recognizerId); + } + /** * KaldiRecognizer anonymous class */ @@ -129,6 +147,9 @@ export class Model extends EventTarget { "Cannot create KaldiRecognizer. Model is either not ready or has been terminated" ); } + + model.registerRecognizer(this); + model.postMessage({ action: "create", recognizerId: this.id, @@ -141,10 +162,8 @@ export class Model extends EventTarget { event: RecognizerEvent, listener: (message: RecognizerMessage) => void ) { - model.addEventListener(event, (event: any) => { - if (event.detail && ServerMessage.isRecognizerMessage(event.detail)) { - listener(event.detail); - } + this.addEventListener(event, (event: any) => { + listener(event?.detail); }); } @@ -193,6 +212,8 @@ export class Model extends EventTarget { } public remove(): void { + model.unregisterRecognizer(this.id); + model.postMessage({ action: "remove", recognizerId: this.id, diff --git a/lib/src/worker.ts b/lib/src/worker.ts index d35e819..3aced0f 100644 --- a/lib/src/worker.ts +++ b/lib/src/worker.ts @@ -43,6 +43,7 @@ export class RecognizerWorker { if (!modelUrl) { ctx.postMessage({ + event: "error", error: "Missing modelUrl parameter", }); } @@ -53,7 +54,7 @@ export class RecognizerWorker { }) .catch((error) => { this.logger.error(error); - ctx.postMessage({ error: error.message }); + ctx.postMessage({ event: "error", error: error.message }); }); return; @@ -69,7 +70,7 @@ export class RecognizerWorker { .then((result) => { ctx.postMessage(result); }) - .catch((error) => ctx.postMessage({ event: "error", error })); + .catch((error) => ctx.postMessage({ event: "error", recognizerId: message.recognizerId, error: error.message })); return; } @@ -78,7 +79,7 @@ export class RecognizerWorker { .then((result) => { ctx.postMessage(result); }) - .catch((error) => ctx.postMessage({ event: "error", error })); + .catch((error) => ctx.postMessage({ event: "error", recognizerId: message.recognizerId, error: error.message })); return; } @@ -87,7 +88,7 @@ export class RecognizerWorker { .then((result) => { ctx.postMessage(result); }) - .catch((error) => ctx.postMessage({ event: "error", error })); + .catch((error) => ctx.postMessage({ event: "error", recognizerId: message.recognizerId, error: error.message })); return; } @@ -96,7 +97,7 @@ export class RecognizerWorker { return; } - ctx.postMessage({ error: `Unknown message ${JSON.stringify(message)}` }); + ctx.postMessage({ event: "error", error: `Unknown message ${JSON.stringify(message)}` }); } private async load(modelUrl: string): Promise { @@ -110,6 +111,7 @@ export class RecognizerWorker { }) .catch((e) => { this.logger.error(e); + reject(e); }) ) .then(() => { @@ -196,9 +198,7 @@ export class RecognizerWorker { } catch (error) { const errorMsg = `Recognizer (id: ${recognizerId}): Could not be created due to: ${error}\n${(error as Error)?.stack}`; this.logger.error(errorMsg); - return { - error: errorMsg, - }; + throw new Error(errorMsg); } } @@ -242,10 +242,8 @@ export class RecognizerWorker { ); if (!this.recognizers.has(recognizerId)) { - this.logger.warn(`Recognizer not ready, ignoring`); - return { - error: `Recognizer (id: ${recognizerId}): Not ready`, - }; + this.logger.error(`Recognizer (id: ${recognizerId}) not ready, ignoring`); + throw new Error(`Recognizer (id: ${recognizerId}): Not ready`); } let recognizer = this.recognizers.get(recognizerId)!; @@ -275,9 +273,7 @@ export class RecognizerWorker { if (recognizer.buffAddr == null) { const error = `Recognizer (id: ${recognizer.id}): Could not allocate buffer`; this.logger.error(error); - return { - error - }; + throw new Error(error); } this.Vosk.HEAPF32.set(data, recognizer.buffAddr / data.BYTES_PER_ELEMENT); @@ -327,7 +323,11 @@ export class RecognizerWorker { private async terminate() { for (const recognizer of this.recognizers.values()) { - await this.removeRecognizer(recognizer.id); + try { + await this.removeRecognizer(recognizer.id); + } catch (error) { + this.logger.warn(`Recognizer (id: ${recognizer.id}) could not be removed. Ignoring as we are terminating.`) + } } this.model.delete(); close();