- 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)
169 lines
6.7 KiB
JavaScript
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');
|
|
}
|
|
|
|
})();
|