Spaces:
Running
Running
Download asr-worker.js from CyberMax-tools/clipwhit: direct link, hf CLI and curl.
- Browser
- Download file 2.36 kB
-
https://huggingface.co/spaces/CyberMax-tools/clipwhit/resolve/main/asr-worker.js
- Command line
-
hf download hf://spaces/CyberMax-tools/clipwhit/asr-worker.js
-
curl -L -o asr-worker.js https://huggingface.co/spaces/CyberMax-tools/clipwhit/resolve/main/asr-worker.js
2.36 kB
| // Clipwhit speech-to-text worker: Whisper in the browser with transformers.js (WebGPU when available, else WASM). | |
| // Audio arrives as 16 kHz mono Float32Array; nothing is uploaded. © 2026 CyberMax. All rights reserved. | |
| import { pipeline, WhisperTextStreamer, env } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@4.3.0'; | |
| env.allowLocalModels = false; | |
| let asr = null, loadedKey = null; | |
| async function load(model, device, post) { | |
| const key = `${model}|${device}`; | |
| if (asr && loadedKey === key) return asr; | |
| if (asr) { try { await asr.dispose(); } catch {} asr = null; loadedKey = null; } | |
| const dtype = device === 'webgpu' ? { encoder_model: 'fp32', decoder_model_merged: 'q4' } : 'q8'; | |
| asr = await pipeline('automatic-speech-recognition', model, { | |
| device, dtype, | |
| progress_callback: (p) => post({ type: 'load', file: p.file, loaded: p.loaded, total: p.total }), | |
| }); | |
| loadedKey = key; | |
| return asr; | |
| } | |
| self.onmessage = async ({ data }) => { | |
| if (data?.type !== 'run') return; | |
| const post = (m) => self.postMessage(m); | |
| try { | |
| let device = data.device, p; | |
| try { p = await load(data.model, device, post); } catch (e) { | |
| if (device !== 'webgpu') throw e; | |
| post({ type: 'info', message: 'WebGPU could not start; using the CPU instead.' }); | |
| device = 'wasm'; | |
| p = await load(data.model, device, post); | |
| } | |
| post({ type: 'ready', device }); | |
| const english = /\.en$/.test(data.model); | |
| const opts = { chunk_length_s: 30, stride_length_s: 5, return_timestamps: true, ...(english ? {} : { language: data.language || null, task: 'transcribe' }) }; | |
| let done = 0, out; | |
| try { | |
| const time_precision = p.processor.feature_extractor.config.chunk_length / p.model.config.max_source_positions; | |
| const streamer = new WhisperTextStreamer(p.tokenizer, { | |
| time_precision, skip_prompt: true, | |
| callback_function: (text) => post({ type: 'partial', text }), | |
| on_finalize: () => post({ type: 'chunk', done: ++done }), | |
| }); | |
| out = await p(data.audio, { ...opts, streamer }); | |
| } catch (e) { | |
| if (!/stream/i.test(String(e?.message || e))) throw e; | |
| out = await p(data.audio, opts); | |
| } | |
| post({ type: 'done', chunks: out.chunks || [], text: out.text, device }); | |
| } catch (e) { | |
| post({ type: 'error', message: String(e?.message || e) }); | |
| } | |
| }; | |