v15: Fix TTS preview + Browser Whisper preload with extensive debugging
BREAKING FIXES: - TTS Preview: Added event.preventDefault(), console logging, proper init check - Browser Whisper: Complete console logging pipeline, error handling, progress tracking - Voice Preferences: DOMContentLoaded fallback, explicit button click handlers - Whisper Worker: Console logs at every step, better error messages Debugging Features: - Console logs show: button clicks, init events, progress updates, errors - Progress tracking: [WhisperWorker] Progress: model.bin 47% - Error messages: Specific failure reasons (not generic failures) - Timeout warnings: 30s check for stuck downloads Audio Backup Confirmed: - Deletes immediately on successful transcription (line 621-624 app.js) - NOT after 24 hours - 24h is server retention limit for failed transcriptions - User was correct - this is working as designed How to Debug: 1. Open DevTools → Console (F12) 2. Click button 3. Watch for [VoicePrefs] or [BrowserWhisper] logs 4. Check Network tab for actual downloads 5. Report what you see in console
This commit is contained in:
parent
42daff2343
commit
d96a008dfe
6 changed files with 107 additions and 33 deletions
|
|
@ -1,6 +1,6 @@
|
|||
services:
|
||||
pediatric-scribe:
|
||||
image: danielonyejesi/pediatric-ai-scribe-v3:v14
|
||||
image: danielonyejesi/pediatric-ai-scribe-v3:v15
|
||||
ports:
|
||||
- "3552:3000"
|
||||
env_file:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "pediatric-ai-scribe",
|
||||
"version": "14.0.0",
|
||||
"version": "15.0.0",
|
||||
"description": "AI-powered pediatric clinical documentation platform",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -202,32 +202,54 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
});
|
||||
|
||||
if (pre) {
|
||||
pre.addEventListener('click', function() {
|
||||
if (!prog || !pt) return;
|
||||
pre.addEventListener('click', function(e) {
|
||||
console.log('[BrowserWhisper] Pre-download button clicked!');
|
||||
e.preventDefault();
|
||||
|
||||
if (!prog || !pt) {
|
||||
console.error('[BrowserWhisper] Progress elements not found');
|
||||
showToast('UI elements missing - check page load', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!BrowserWhisper || !BrowserWhisper.isSupported()) {
|
||||
console.error('[BrowserWhisper] Not supported');
|
||||
showToast('Browser Whisper not supported in this browser', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[BrowserWhisper] Starting preload...');
|
||||
prog.style.display = 'block';
|
||||
pt.textContent = 'Starting download...';
|
||||
pt.textContent = 'Initializing...';
|
||||
|
||||
BrowserWhisper.setEnabled(true);
|
||||
chk.checked = true;
|
||||
stat.textContent = 'On — audio stays on device';
|
||||
|
||||
// Set timeout in case it gets stuck
|
||||
var timeout = setTimeout(function() {
|
||||
console.warn('[BrowserWhisper] Preload timeout - may still be downloading in background');
|
||||
showToast('Download taking longer than expected. Check browser console for progress.', 'warning');
|
||||
}, 30000); // 30 second warning
|
||||
console.warn('[BrowserWhisper] 30s elapsed - still downloading, check Network tab');
|
||||
showToast('Download in progress - check browser console', 'info');
|
||||
}, 30000);
|
||||
|
||||
BrowserWhisper.preload(function(file, pct) {
|
||||
console.log('[BrowserWhisper] Progress:', file, pct + '%');
|
||||
if (pct >= 100) {
|
||||
clearTimeout(timeout);
|
||||
prog.style.display = 'none';
|
||||
showToast('Whisper model ready', 'success');
|
||||
return;
|
||||
}
|
||||
prog.style.display = 'block';
|
||||
pt.textContent = file + (pct > 0 ? ' ' + pct + '%' : '');
|
||||
});
|
||||
try {
|
||||
BrowserWhisper.preload(function(file, pct) {
|
||||
console.log('[BrowserWhisper] Progress:', file, pct + '%');
|
||||
if (pct >= 100) {
|
||||
clearTimeout(timeout);
|
||||
prog.style.display = 'none';
|
||||
showToast('Whisper model ready!', 'success');
|
||||
return;
|
||||
}
|
||||
prog.style.display = 'block';
|
||||
pt.textContent = file + (pct > 0 ? ' ' + pct + '%' : '');
|
||||
});
|
||||
} catch (err) {
|
||||
clearTimeout(timeout);
|
||||
console.error('[BrowserWhisper] Preload error:', err);
|
||||
prog.style.display = 'none';
|
||||
showToast('Preload failed: ' + err.message, 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,23 +8,49 @@
|
|||
window.addEventListener('tab-loaded', function(e) {
|
||||
if (e.detail.tab !== 'settings' || _inited) return;
|
||||
_inited = true;
|
||||
console.log('[VoicePrefs] Initializing...');
|
||||
initVoicePreferences();
|
||||
});
|
||||
|
||||
// Also init on DOMContentLoaded as backup
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
setTimeout(function() {
|
||||
if (!_inited && document.getElementById('btn-preview-voice')) {
|
||||
console.log('[VoicePrefs] Init via DOMContentLoaded');
|
||||
_inited = true;
|
||||
initVoicePreferences();
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
function initVoicePreferences() {
|
||||
console.log('[VoicePrefs] initVoicePreferences called');
|
||||
|
||||
loadVoiceOptions();
|
||||
loadUserPreferences();
|
||||
|
||||
// Save button
|
||||
var btnSave = document.getElementById('btn-save-voice-prefs');
|
||||
if (btnSave) {
|
||||
console.log('[VoicePrefs] Save button found, adding listener');
|
||||
btnSave.addEventListener('click', saveVoicePreferences);
|
||||
} else {
|
||||
console.warn('[VoicePrefs] Save button NOT found');
|
||||
}
|
||||
|
||||
// Preview button
|
||||
var btnPreview = document.getElementById('btn-preview-voice');
|
||||
if (btnPreview) {
|
||||
btnPreview.addEventListener('click', previewVoice);
|
||||
console.log('[VoicePrefs] Preview button found, adding listener');
|
||||
btnPreview.addEventListener('click', function(e) {
|
||||
console.log('[VoicePrefs] Preview button clicked!');
|
||||
e.preventDefault();
|
||||
previewVoice();
|
||||
});
|
||||
} else {
|
||||
console.warn('[VoicePrefs] Preview button NOT found');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,31 +13,52 @@ var _pipe = null;
|
|||
var _loadedModel = null;
|
||||
|
||||
async function load(modelName) {
|
||||
if (_pipe && _loadedModel === modelName) return;
|
||||
if (_pipe && _loadedModel === modelName) {
|
||||
console.log('[WhisperWorker] Model already loaded:', modelName);
|
||||
return;
|
||||
}
|
||||
console.log('[WhisperWorker] Loading model:', modelName);
|
||||
self.postMessage({ type: 'loading', model: modelName });
|
||||
_pipe = await T.pipeline('automatic-speech-recognition', modelName, {
|
||||
progress_callback: function(p) {
|
||||
if (p.status === 'downloading' || p.status === 'progress') {
|
||||
self.postMessage({ type: 'progress', file: p.file || '', progress: Math.round(p.progress || 0) });
|
||||
|
||||
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;
|
||||
self.postMessage({ type: 'ready', model: modelName });
|
||||
});
|
||||
_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) { self.postMessage({ type: 'error', message: err.message }); }
|
||||
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',
|
||||
|
|
@ -45,9 +66,14 @@ self.addEventListener('message', async function(e) {
|
|||
stride_length_s: 5,
|
||||
return_timestamps: false
|
||||
});
|
||||
console.log('[WhisperWorker] Transcription complete');
|
||||
self.postMessage({ type: 'result', text: result.text.trim() });
|
||||
} catch(err) {
|
||||
self.postMessage({ type: 'error', message: err.message });
|
||||
console.error('[WhisperWorker] Transcribe error:', err);
|
||||
self.postMessage({ type: 'error', message: 'Transcription failed: ' + err.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Log worker startup
|
||||
console.log('[WhisperWorker] Worker initialized');
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ app.get('/api/models', async (req, res) => {
|
|||
const { activeProvider } = require('./src/utils/ai');
|
||||
app.get('/api/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'running', version: '13.0.0', provider: activeProvider,
|
||||
status: 'running', version: '15.0.0', provider: activeProvider,
|
||||
timestamp: new Date().toISOString(),
|
||||
openrouter: process.env.OPENROUTER_API_KEY ? 'configured' : 'missing',
|
||||
bedrock: process.env.AWS_BEDROCK_REGION ? 'configured' : 'not configured',
|
||||
|
|
|
|||
Loading…
Reference in a new issue