diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-01-31 22:19:11 +0100 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-01-31 22:19:11 +0100 |
| commit | f820d9a8948b97460ebdfdaa6b42b6d510e2b3cf (patch) | |
| tree | 460b4cd9ac403fe5591bb0b5b4064e1662d08077 /apps/web/src/services/transcription/index.ts | |
| parent | 7878c8bb7b83bce568ced990903b8195a9dd4605 (diff) | |
| download | opencut-f820d9a8948b97460ebdfdaa6b42b6d510e2b3cf.tar.gz | |
refactor services structure
Diffstat (limited to 'apps/web/src/services/transcription/index.ts')
| -rw-r--r-- | apps/web/src/services/transcription/index.ts | 186 |
1 files changed, 0 insertions, 186 deletions
diff --git a/apps/web/src/services/transcription/index.ts b/apps/web/src/services/transcription/index.ts deleted file mode 100644 index 37c650da..00000000 --- a/apps/web/src/services/transcription/index.ts +++ /dev/null @@ -1,186 +0,0 @@ -import type { - TranscriptionResult, - TranscriptionProgress, - TranscriptionModelId, -} from "@/types/transcription"; -import { - DEFAULT_TRANSCRIPTION_MODEL, - TRANSCRIPTION_MODELS, -} from "@/constants/transcription-constants"; -import type { WorkerMessage, WorkerResponse } from "./worker"; -import type { LanguageCode } from "@/types/language"; - -type ProgressCallback = (progress: TranscriptionProgress) => void; - -class TranscriptionService { - private worker: Worker | null = null; - private currentModelId: TranscriptionModelId | null = null; - private isInitialized = false; - private isInitializing = false; - - async transcribe({ - audioData, - language, - modelId = DEFAULT_TRANSCRIPTION_MODEL, - onProgress, - }: { - audioData: Float32Array; - language?: LanguageCode; - modelId?: TranscriptionModelId; - onProgress?: ProgressCallback; - }): Promise<TranscriptionResult> { - await this.ensureWorker({ modelId, onProgress }); - - return new Promise((resolve, reject) => { - if (!this.worker) { - reject(new Error("Worker not initialized")); - return; - } - - const handleMessage = (event: MessageEvent<WorkerResponse>) => { - const response = event.data; - - switch (response.type) { - case "transcribe-progress": - onProgress?.({ - status: "transcribing", - progress: response.progress, - message: "Transcribing audio...", - }); - break; - - case "transcribe-complete": - this.worker?.removeEventListener("message", handleMessage); - resolve({ - text: response.text, - segments: response.segments, - language, - }); - break; - - case "transcribe-error": - this.worker?.removeEventListener("message", handleMessage); - reject(new Error(response.error)); - break; - - case "cancelled": - this.worker?.removeEventListener("message", handleMessage); - reject(new Error("Transcription cancelled")); - break; - } - }; - - this.worker.addEventListener("message", handleMessage); - - this.worker.postMessage({ - type: "transcribe", - audio: audioData, - language, - } satisfies WorkerMessage); - }); - } - - cancel() { - this.worker?.postMessage({ type: "cancel" } satisfies WorkerMessage); - } - - private async ensureWorker({ - modelId, - onProgress, - }: { - modelId: TranscriptionModelId; - onProgress?: ProgressCallback; - }): Promise<void> { - const needsNewModel = this.currentModelId !== modelId; - - if (this.worker && this.isInitialized && !needsNewModel) { - return; - } - - if (this.isInitializing && !needsNewModel) { - await this.waitForInit(); - return; - } - - this.terminate(); - this.isInitializing = true; - this.isInitialized = false; - - const model = TRANSCRIPTION_MODELS.find((m) => m.id === modelId); - if (!model) { - throw new Error(`Unknown model: ${modelId}`); - } - - this.worker = new Worker(new URL("./worker.ts", import.meta.url), { - type: "module", - }); - - return new Promise((resolve, reject) => { - if (!this.worker) { - reject(new Error("Failed to create worker")); - return; - } - - const handleMessage = (event: MessageEvent<WorkerResponse>) => { - const response = event.data; - - switch (response.type) { - case "init-progress": - onProgress?.({ - status: "loading-model", - progress: response.progress, - message: `Loading ${model.name} model...`, - }); - break; - - case "init-complete": - this.worker?.removeEventListener("message", handleMessage); - this.isInitialized = true; - this.isInitializing = false; - this.currentModelId = modelId; - resolve(); - break; - - case "init-error": - this.worker?.removeEventListener("message", handleMessage); - this.isInitializing = false; - this.terminate(); - reject(new Error(response.error)); - break; - } - }; - - this.worker.addEventListener("message", handleMessage); - - this.worker.postMessage({ - type: "init", - modelId: model.huggingFaceId, - } satisfies WorkerMessage); - }); - } - - private waitForInit(): Promise<void> { - return new Promise((resolve) => { - const checkInit = () => { - if (this.isInitialized) { - resolve(); - } else if (!this.isInitializing) { - resolve(); - } else { - setTimeout(checkInit, 100); - } - }; - checkInit(); - }); - } - - terminate() { - this.worker?.terminate(); - this.worker = null; - this.isInitialized = false; - this.isInitializing = false; - this.currentModelId = null; - } -} - -export const transcriptionService = new TranscriptionService(); |
