pediatric-ai-scribe-v3/public/js/transcriptionSettings.js
Daniel 79994f4781 Replace all browser dialogs with modern modal, add OIDC admin UI
- Add reusable showConfirm() modal component (supports plain confirm,
  input prompt, danger styling, Enter key)
- Replace ALL 18 confirm() and prompt() calls across 8 JS files with
  showConfirm() modal: admin user actions, session revoke, document
  delete, template delete, milestone management, transcription settings
- Fix broken admin reset-password (btn was undefined in scope)
- Add OIDC/SSO configuration UI to Admin Panel (issuer, client ID/secret,
  button label, disable local auth toggle, callback URL display)
2026-04-09 02:43:23 +02:00

169 lines
6.7 KiB
JavaScript

// ============================================================
// TRANSCRIPTION SETTINGS — Browser Whisper + Web Speech API
// ============================================================
(function() {
var _inited = false;
document.addEventListener('tabChanged', function(e) {
if (e.detail.tab !== 'settings' || _inited) return;
_inited = true;
initTranscriptionSettings();
});
// Also init on direct page load
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
if (!_inited && document.getElementById('browser-whisper-enabled')) {
_inited = true;
initTranscriptionSettings();
}
}, 500);
});
} else {
setTimeout(function() {
if (!_inited && document.getElementById('browser-whisper-enabled')) {
_inited = true;
initTranscriptionSettings();
}
}, 500);
}
function initTranscriptionSettings() {
console.log('[TranscriptionSettings] Initializing...');
// ── Browser Whisper ──────────────────────────────────────
var whisperCheckbox = document.getElementById('browser-whisper-enabled');
var whisperStatus = document.getElementById('browser-whisper-status');
var whisperModel = document.getElementById('browser-whisper-model');
var whisperPreload = document.getElementById('btn-whisper-preload');
var whisperProgress = document.getElementById('browser-whisper-progress');
var whisperProgressText = document.getElementById('browser-whisper-progress-text');
if (whisperCheckbox && window.BrowserWhisper) {
whisperCheckbox.checked = BrowserWhisper.isEnabled();
whisperStatus.textContent = BrowserWhisper.isEnabled() ? 'On — audio stays on device' : 'Off';
if (whisperModel) {
whisperModel.value = BrowserWhisper.getModel();
}
whisperCheckbox.addEventListener('change', function() {
BrowserWhisper.setEnabled(whisperCheckbox.checked);
whisperStatus.textContent = whisperCheckbox.checked ? 'On — audio stays on device' : 'Off';
if (whisperCheckbox.checked) {
// Auto-preload on enable
BrowserWhisper.preload(function(file, pct) {
if (whisperProgress && whisperProgressText) {
if (pct >= 100) {
whisperProgress.style.display = 'none';
return;
}
whisperProgress.style.display = 'block';
whisperProgressText.textContent = file + (pct > 0 ? ' ' + pct + '%' : '');
}
});
}
});
if (whisperModel) {
whisperModel.addEventListener('change', function() {
BrowserWhisper.setModel(whisperModel.value);
});
}
if (whisperPreload) {
whisperPreload.addEventListener('click', function() {
if (!BrowserWhisper || !BrowserWhisper.isSupported()) {
showToast('Browser Whisper not supported', 'error');
return;
}
whisperPreload.disabled = true;
whisperPreload.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Downloading...';
whisperProgress.style.display = 'block';
whisperProgressText.textContent = 'Initializing...';
BrowserWhisper.setEnabled(true);
whisperCheckbox.checked = true;
whisperStatus.textContent = 'On — audio stays on device';
BrowserWhisper.preload(function(file, pct) {
if (pct >= 100) {
whisperProgress.style.display = 'none';
whisperPreload.disabled = false;
whisperPreload.innerHTML = '<i class="fas fa-download"></i> Pre-download model';
showToast('Whisper model ready!', 'success');
return;
}
whisperProgress.style.display = 'block';
whisperProgressText.textContent = file + (pct > 0 ? ' ' + pct + '%' : '');
});
});
}
}
// ── Web Speech Recognition ───────────────────────────────
var speechCheckbox = document.getElementById('web-speech-enabled');
var speechStatus = document.getElementById('web-speech-status');
var speechBrowserInfo = document.getElementById('web-speech-browser-info');
if (speechCheckbox && window.WebSpeechRecognition) {
speechCheckbox.checked = WebSpeechRecognition.isEnabled();
speechStatus.textContent = WebSpeechRecognition.isEnabled() ? 'On — real-time streaming' : 'Off';
// Show privacy info
if (speechBrowserInfo) {
var privacyInfo = WebSpeechRecognition.getPrivacyInfo();
speechBrowserInfo.innerHTML =
'<strong>Provider:</strong> ' + privacyInfo.provider + '<br>' +
'<strong>Privacy:</strong> ' + privacyInfo.privacy + '<br>' +
'<strong style="color:var(--orange);">⚠️ ' + privacyInfo.warning + '</strong>';
}
speechCheckbox.addEventListener('change', function() {
if (speechCheckbox.checked) {
// Show confirmation for privacy warning
showConfirm(
'WARNING: Real-time streaming uses your browser\'s speech recognition, ' +
'which may send audio to cloud servers (e.g., Google). ' +
'This is NOT HIPAA-compliant. ' +
'Only enable if you understand and accept this privacy trade-off.',
function() {
// Disable Browser Whisper if enabling Web Speech
if (whisperCheckbox && whisperCheckbox.checked) {
whisperCheckbox.checked = false;
BrowserWhisper.setEnabled(false);
whisperStatus.textContent = 'Off';
showToast('Browser Whisper disabled (Web Speech takes priority)', 'info');
}
WebSpeechRecognition.setEnabled(true);
speechStatus.textContent = 'On — real-time streaming';
},
{ danger: true, confirmText: 'Enable' }
);
// Revert checkbox until confirmed
speechCheckbox.checked = false;
return;
}
WebSpeechRecognition.setEnabled(false);
speechStatus.textContent = 'Off';
});
// If not supported, disable and show message
if (!WebSpeechRecognition.isSupported()) {
speechCheckbox.disabled = true;
speechStatus.textContent = 'Not supported in this browser';
if (speechBrowserInfo) {
speechBrowserInfo.innerHTML = '<strong style="color:var(--red);">Not supported</strong> - Web Speech API not available in this browser.';
}
}
}
console.log('✅ Transcription settings initialized');
}
})();