diff --git a/public/js/voicePreferences.js b/public/js/voicePreferences.js index 09f5086..2e4ff63 100644 --- a/public/js/voicePreferences.js +++ b/public/js/voicePreferences.js @@ -5,24 +5,37 @@ (function() { var _inited = false; - window.addEventListener('tab-loaded', function(e) { + // Listen for tab changes (correct event name is 'tabChanged' not 'tab-loaded') + document.addEventListener('tabChanged', function(e) { if (e.detail.tab !== 'settings' || _inited) return; _inited = true; - console.log('[VoicePrefs] Initializing...'); - initVoicePreferences(); + console.log('[VoicePrefs] Initializing on settings tab load...'); + // Small delay to ensure DOM is ready + setTimeout(function() { + initVoicePreferences(); + }, 100); }); - // Also init on DOMContentLoaded as backup + // Also init on DOMContentLoaded as backup for direct page load if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { setTimeout(function() { if (!_inited && document.getElementById('btn-preview-voice')) { - console.log('[VoicePrefs] Init via DOMContentLoaded'); + console.log('[VoicePrefs] Init via DOMContentLoaded (direct settings page load)'); _inited = true; initVoicePreferences(); } - }, 1000); + }, 500); }); + } else { + // Page already loaded, init immediately if on settings + setTimeout(function() { + if (!_inited && document.getElementById('btn-preview-voice')) { + console.log('[VoicePrefs] Init immediate (page already loaded)'); + _inited = true; + initVoicePreferences(); + } + }, 500); } function initVoicePreferences() { diff --git a/public/js/whisperWorker.js b/public/js/whisperWorker.js index b423475..79e33fe 100644 --- a/public/js/whisperWorker.js +++ b/public/js/whisperWorker.js @@ -3,11 +3,29 @@ // Audio never leaves the device. Model cached in IndexedDB. // ============================================================ -importScripts('https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2'); +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; diff --git a/server.js b/server.js index 5c286b1..d090393 100644 --- a/server.js +++ b/server.js @@ -21,7 +21,8 @@ app.use(helmet({ defaultSrc: ["'self'"], // 'wasm-unsafe-eval' required for WebAssembly (Whisper in-browser transcription) // cdn.jsdelivr.net required for @xenova/transformers worker script - scriptSrc: ["'self'", "'wasm-unsafe-eval'", 'https://cdn.jsdelivr.net'], + // 'unsafe-eval' needed for transformers.js dynamic imports in worker + scriptSrc: ["'self'", "'wasm-unsafe-eval'", "'unsafe-eval'", 'https://cdn.jsdelivr.net'], scriptSrcAttr: ["'none'"], styleSrc: ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com', 'https://cdnjs.cloudflare.com'], fontSrc: ["'self'", 'https://fonts.gstatic.com', 'https://cdnjs.cloudflare.com'], @@ -29,8 +30,12 @@ app.use(helmet({ mediaSrc: ["'self'", 'blob:'], connectSrc: ["'self'", 'https://cdnjs.cloudflare.com', 'https://fonts.googleapis.com', 'https://fonts.gstatic.com', 'https://www.google.com', 'wss://www.google.com', 'https://clinicaltables.nlm.nih.gov', // HuggingFace CDN for Whisper model downloads - 'https://huggingface.co', 'https://cdn-lfs.huggingface.co', 'https://cdn-lfs-us-1.huggingface.co', 'https://cdn-lfs-us-2.huggingface.co'], + 'https://huggingface.co', 'https://cdn-lfs.huggingface.co', 'https://cdn-lfs-us-1.huggingface.co', 'https://cdn-lfs-us-2.huggingface.co', + // jsdelivr for worker importScripts + 'https://cdn.jsdelivr.net'], workerSrc: ["'self'", 'blob:'], + // Allow workers to load scripts from jsdelivr + childSrc: ["'self'", 'blob:', 'https://cdn.jsdelivr.net'], frameSrc: ["'none'"], objectSrc: ["'none'"], }