43 lines
1.1 KiB
TypeScript
43 lines
1.1 KiB
TypeScript
import {createWorker} from 'tesseract.js';
|
|
import {AbortablePromise, Ai} from './ai.ts';
|
|
|
|
export class Vision {
|
|
|
|
constructor(private ai: Ai) {}
|
|
|
|
/**
|
|
* Convert image to text using Optical Character Recognition
|
|
* @param {string} path Path to image
|
|
* @returns {AbortablePromise<string | null>} Promise of extracted text with abort method
|
|
*/
|
|
ocr(path: string): AbortablePromise<string | null> {
|
|
let worker: any;
|
|
let reject: (err: any) => void;
|
|
|
|
const handler = (err: Error) => {
|
|
if(err.stack?.includes('tesseract.js')) {
|
|
process.off('uncaughtException', handler);
|
|
reject?.(err);
|
|
return;
|
|
}
|
|
throw err;
|
|
};
|
|
process.on('uncaughtException', handler);
|
|
|
|
const p = (async () => {
|
|
worker = await createWorker(this.ai.options.ocr || 'eng', 2, {cachePath: this.ai.options.path});
|
|
return await new Promise<string | null>((res, rej) => {
|
|
reject = rej;
|
|
worker.recognize(path)
|
|
.then(({data}: any) => res(data.text.trim() || null))
|
|
.catch(rej);
|
|
});
|
|
})().finally(() => {
|
|
process.off('uncaughtException', handler);
|
|
worker?.terminate();
|
|
});
|
|
|
|
return Object.assign(p, {abort: () => worker?.terminate()});
|
|
}
|
|
}
|