pediatric-ai-scribe-v3/public/js/whisperWorker.js
ifedan-ed 88036a45c4
Some checks failed
Build TWA APK / build-apk (push) Has been cancelled
Build & Push Docker Image / build (push) Has been cancelled
v15.1: CRITICAL FIX - TTS Preview + Browser Whisper actually working now
ROOT CAUSES FOUND AND FIXED:
1. TTS Preview not working: voicePreferences.js listening for wrong event
   - Was: 'tab-loaded' (never dispatched)
   - Now: 'tabChanged' (correct event name used by app.js)
   - Added immediate init if page already loaded
   - Added 500ms delay for DOM readiness

2. Browser Whisper CDN blocked: CSP too restrictive
   - Added 'unsafe-eval' to scriptSrc (required by transformers.js)
   - Added cdn.jsdelivr.net to connectSrc (worker importScripts)
   - Added childSrc directive for worker script loading
   - Better error messages in worker

3. Worker loading errors: Now logged with specific reasons
   - importScripts wrapped in try-catch
   - Posts error message to main thread
   - Verifies transformers object exists after load

Testing:
- TTS Preview should now work when clicking Settings tab
- Browser Whisper should load from CDN (or show specific error)
- Console logs will show exact init sequence
2026-03-31 16:00:10 +00:00

97 lines
3.4 KiB
JavaScript

// ============================================================
// WHISPER WORKER — runs @xenova/transformers in a Web Worker
// Audio never leaves the device. Model cached in IndexedDB.
// ============================================================
console.log('[WhisperWorker] Starting worker initialization');
console.log('[WhisperWorker] Attempting to load transformers from CDN...');
try {
importScripts('https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2');
console.log('[WhisperWorker] Transformers library loaded successfully');
} catch (err) {
console.error('[WhisperWorker] Failed to load transformers library:', err);
self.postMessage({
type: 'error',
message: 'Failed to load transformers library. Check network/firewall: ' + err.message
});
throw err;
}
var T = self.transformers || transformers;
if (!T) {
console.error('[WhisperWorker] Transformers object not found after import');
throw new Error('Transformers library did not initialize');
}
T.env.allowLocalModels = false;
T.env.useBrowserCache = true;
console.log('[WhisperWorker] Transformers configured');
var _pipe = null;
var _loadedModel = null;
async function load(modelName) {
if (_pipe && _loadedModel === modelName) {
console.log('[WhisperWorker] Model already loaded:', modelName);
return;
}
console.log('[WhisperWorker] Loading model:', modelName);
self.postMessage({ type: 'loading', model: modelName });
try {
_pipe = await T.pipeline('automatic-speech-recognition', modelName, {
progress_callback: function(p) {
console.log('[WhisperWorker] Progress:', p.status, p.file, p.progress);
if (p.status === 'downloading' || p.status === 'progress') {
self.postMessage({ type: 'progress', file: p.file || '', progress: Math.round(p.progress || 0) });
}
if (p.status === 'done' || p.status === 'ready') {
self.postMessage({ type: 'progress', file: p.file || '', progress: 100 });
}
}
});
_loadedModel = modelName;
console.log('[WhisperWorker] Model loaded successfully');
self.postMessage({ type: 'ready', model: modelName });
} catch (err) {
console.error('[WhisperWorker] Load error:', err);
self.postMessage({ type: 'error', message: 'Model load failed: ' + err.message });
}
}
self.addEventListener('message', async function(e) {
var d = e.data;
console.log('[WhisperWorker] Message received:', d.type);
if (d.type === 'load') {
try {
await load(d.model || 'Xenova/whisper-tiny.en');
} catch(err) {
console.error('[WhisperWorker] Load error:', err);
self.postMessage({ type: 'error', message: 'Load failed: ' + err.message });
}
return;
}
if (d.type === 'transcribe') {
try {
await load(d.model || 'Xenova/whisper-tiny.en');
console.log('[WhisperWorker] Starting transcription...');
var result = await _pipe(d.audio, {
language: 'english',
task: 'transcribe',
chunk_length_s: 30,
stride_length_s: 5,
return_timestamps: false
});
console.log('[WhisperWorker] Transcription complete');
self.postMessage({ type: 'result', text: result.text.trim() });
} catch(err) {
console.error('[WhisperWorker] Transcribe error:', err);
self.postMessage({ type: 'error', message: 'Transcription failed: ' + err.message });
}
}
});
// Log worker startup
console.log('[WhisperWorker] Worker initialized');