From 2351f590b517c2e839ab356a73f6cf5e2056c8ba Mon Sep 17 00:00:00 2001 From: ztimson Date: Sun, 14 Dec 2025 09:27:07 -0500 Subject: [PATCH] Removed ASR file intermediary --- package.json | 2 +- src/ai.ts | 29 +++++++++++++++++------------ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 2ef5b86..6c47482 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ztimson/ai-utils", - "version": "0.1.13", + "version": "0.1.14", "description": "AI Utility library", "author": "Zak Timson", "license": "MIT", diff --git a/src/ai.ts b/src/ai.ts index ba4160d..6934e2e 100644 --- a/src/ai.ts +++ b/src/ai.ts @@ -1,9 +1,9 @@ -import {$} from '@ztimson/node-utils'; import {createWorker} from 'tesseract.js'; import {LLM, LLMOptions} from './llm'; import fs from 'node:fs/promises'; import Path from 'node:path'; import * as tf from '@tensorflow/tfjs'; +import {spawn} from 'node:child_process'; export type AiOptions = LLMOptions & { whisper?: { @@ -13,8 +13,6 @@ export type AiOptions = LLMOptions & { model: string; /** Path to models */ path: string; - /** Path to storage location for temporary files */ - temp?: string; } } @@ -40,16 +38,23 @@ export class Ai { * @param model Whisper model * @returns {Promise} Extracted text */ - async asr(path: string, model: string = this.whisperModel): Promise { + asr(path: string, model: string = this.whisperModel): {abort: () => void, response: Promise} { if(!this.options.whisper?.binary) throw new Error('Whisper not configured'); - const m = await this.downloadAsrModel(model); - const name = Math.random().toString(36).substring(2, 10) + '-' + path.split('/').pop() + '.txt'; - const output = Path.join(this.options.whisper.temp || '/tmp', name); - console.log('ASR: ' + this.options.whisper.model + ' -> ' + this.whisperModel); - console.log(`rm -f ${output} && ${this.options.whisper.binary} -nt -np -m ${m} -f ${path} -otxt -of ${output}`); - await $`rm -f ${output} && ${this.options.whisper.binary} -nt -np -m ${m} -f ${path} -otxt -of ${output}`; - return fs.readFile(output, 'utf-8').then(text => text?.trim() || null) - .finally(() => fs.rm(output, {force: true}).catch(() => {})); + let abort: any = () => {}; + const response = new Promise((resolve, reject) => { + this.downloadAsrModel(model).then(m => { + let output = ''; + const proc = spawn(this.options.whisper?.binary, ['-nt', '-np', '-m', m, '-f', path], {stdio: ['ignore', 'pipe', 'ignore']}); + abort = () => proc.kill('SIGTERM'); + proc.on('error', (err: Error) => reject(err)); + proc.stdout.on('data', (data: Buffer) => output += data.toString()); + proc.on('close', (code: number) => { + if(code === 0) resolve(output.trim() || null); + else reject(new Error(`Exit code ${code}`)); + }); + }); + }); + return {response, abort}; } /**