Provides two transcription options: 1. Browser Whisper (Offline, Batch) - RECOMMENDED - 100% offline, zero network calls - HIPAA-compliant, audio never leaves device - Highest accuracy (Whisper) - Processes after recording (batch mode) - Models self-hosted, bundled in v2 2. Web Speech API (Real-time, Streaming) - EXPERIMENTAL - Real-time transcription (see words as you speak) - Uses browser's built-in speech recognition - ⚠️ Sends audio to cloud (Chrome/Edge → Google) - ⚠️ NOT HIPAA-compliant - Requires user consent with clear warnings Features: - Settings UI for both options - Clear privacy warnings for Web Speech - Mutual exclusion (only one active at a time) - Browser detection shows which provider is used - Confirmation dialog before enabling Web Speech Use Cases: - Clinical/HIPAA: Use Browser Whisper only - Personal/Non-clinical: Can use Web Speech for real-time feedback - Maximum privacy: Browser Whisper (offline) - Maximum speed: Web Speech (if privacy not required) Implementation: - speechRecognition.js: Web Speech API wrapper - transcriptionSettings.js: Settings UI handler - Privacy info displayed per browser User can choose based on their privacy vs. speed preference.
223 lines
16 KiB
HTML
223 lines
16 KiB
HTML
<div class="module-header">
|
|
<h2><i class="fas fa-cog"></i> Settings</h2>
|
|
<p>Account security, integrations, and personal templates</p>
|
|
</div>
|
|
|
|
<div class="settings-page">
|
|
|
|
<!-- Voice Preferences (STT & TTS) -->
|
|
<div class="settings-section card" id="voice-preferences-section">
|
|
<h3><i class="fas fa-microphone-lines"></i> Voice Preferences</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Customize your speech-to-text model and text-to-speech voice. These settings apply to all your recording and read-aloud features.</p>
|
|
|
|
<div style="margin-bottom:16px;">
|
|
<label style="display:block;font-size:13px;font-weight:600;color:var(--g700);margin-bottom:6px;">Speech-to-Text Model (Transcription)</label>
|
|
<p style="font-size:12px;color:var(--g500);margin:4px 0 8px;">Choose the AI model for transcribing your audio recordings. More accurate models may be slower.</p>
|
|
<select id="stt-model-select" style="font-size:13px;padding:6px 10px;border:1px solid var(--g300);border-radius:6px;width:100%;max-width:400px;">
|
|
<option value="">Server default</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div style="margin-bottom:16px;">
|
|
<label style="display:block;font-size:13px;font-weight:600;color:var(--g700);margin-bottom:6px;">Text-to-Speech Voice (Read Aloud)</label>
|
|
<p style="font-size:12px;color:var(--g500);margin:4px 0 8px;">Choose the voice for the "Read Aloud" feature. Preview available after selection.</p>
|
|
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
|
|
<select id="tts-voice-select" style="font-size:13px;padding:6px 10px;border:1px solid var(--g300);border-radius:6px;flex:1;max-width:400px;">
|
|
<option value="">Server default</option>
|
|
</select>
|
|
<button id="btn-preview-voice" class="btn-sm btn-ghost"><i class="fas fa-play"></i> Preview</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="margin-top:12px;">
|
|
<button id="btn-save-voice-prefs" class="btn-sm btn-primary"><i class="fas fa-save"></i> Save Voice Preferences</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Browser Whisper -->
|
|
<div class="settings-section card" id="browser-whisper-section">
|
|
<h3><i class="fas fa-microchip"></i> Browser Transcription (Local Whisper)</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Transcribes audio entirely in your browser — no audio sent to any server. Powered by OpenAI Whisper running in WebAssembly. Model is downloaded once and cached locally.</p>
|
|
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px;">
|
|
<label style="font-size:13px;font-weight:600;">Enable browser transcription:</label>
|
|
<label style="display:flex;align-items:center;gap:6px;cursor:pointer;">
|
|
<input type="checkbox" id="browser-whisper-enabled" style="accent-color:var(--blue);width:16px;height:16px;">
|
|
<span style="font-size:13px;" id="browser-whisper-status">Off</span>
|
|
</label>
|
|
</div>
|
|
<div id="browser-whisper-model-row" style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px;">
|
|
<label style="font-size:13px;font-weight:600;">Model:</label>
|
|
<select id="browser-whisper-model" style="font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;">
|
|
<option value="Xenova/whisper-tiny.en">Tiny (~39MB) — fastest, ~2-3s</option>
|
|
<option value="Xenova/whisper-base.en">Base (~74MB) — balanced, ~3-5s</option>
|
|
<option value="Xenova/whisper-small.en">Small (~244MB) — best quality, ~6-10s</option>
|
|
</select>
|
|
<button id="btn-whisper-preload" class="btn-sm btn-ghost"><i class="fas fa-download"></i> Pre-download model</button>
|
|
</div>
|
|
<div id="browser-whisper-progress" style="display:none;font-size:12px;color:var(--g500);margin-top:4px;">
|
|
<i class="fas fa-spinner fa-spin"></i> <span id="browser-whisper-progress-text">Loading...</span>
|
|
</div>
|
|
<p style="font-size:12px;color:var(--g400);margin:8px 0 0;"><i class="fas fa-info-circle"></i> When enabled, overrides server transcription. Falls back to server if browser transcription fails.</p>
|
|
<p style="font-size:11px;color:var(--orange);margin:4px 0 0;display:none;" id="browser-whisper-csp-warning"><i class="fas fa-exclamation-triangle"></i> <strong>Network/Firewall Issue:</strong> If model download fails, check that <code>cdn.jsdelivr.net</code> and <code>huggingface.co</code> are not blocked. Server transcription will be used as fallback.</p>
|
|
</div>
|
|
|
|
<!-- Web Speech Recognition (Real-time Streaming) -->
|
|
<div class="settings-section card" id="web-speech-section" style="border-left:3px solid var(--orange);">
|
|
<h3><i class="fas fa-wave-square"></i> Real-Time Streaming Transcription</h3>
|
|
<div style="background:var(--orange-light);padding:12px;border-radius:6px;margin-bottom:12px;">
|
|
<p style="font-size:13px;color:var(--orange-dark);margin:0;"><i class="fas fa-exclamation-triangle"></i> <strong>Privacy Warning:</strong> Uses your browser's built-in speech recognition, which <strong>may send audio to cloud servers</strong> (Chrome/Edge send to Google). Only enable if you accept this trade-off for real-time transcription.</p>
|
|
</div>
|
|
<p style="font-size:13px;color:var(--g600);">See words appear as you speak (streaming). Overrides browser and server transcription when enabled. <strong>Not HIPAA-compliant</strong> in most browsers.</p>
|
|
|
|
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px;">
|
|
<label style="font-size:13px;font-weight:600;">Enable real-time streaming:</label>
|
|
<label style="display:flex;align-items:center;gap:6px;cursor:pointer;">
|
|
<input type="checkbox" id="web-speech-enabled" style="accent-color:var(--orange);width:16px;height:16px;">
|
|
<span style="font-size:13px;" id="web-speech-status">Off</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div id="web-speech-privacy-info" style="font-size:12px;color:var(--g500);padding:10px;background:var(--g50);border-radius:6px;margin-top:8px;">
|
|
<p style="margin:0 0 4px;font-weight:600;">Current Browser:</p>
|
|
<p style="margin:0;" id="web-speech-browser-info">Detecting...</p>
|
|
</div>
|
|
|
|
<p style="font-size:11px;color:var(--g400);margin:8px 0 0;"><i class="fas fa-info-circle"></i> <strong>Trade-off:</strong> Immediate transcription vs. privacy. For maximum privacy, use Browser Whisper (offline batch mode) or Server transcription with HIPAA-eligible provider.</p>
|
|
</div>
|
|
|
|
<!-- 2FA -->
|
|
<div class="settings-section card">
|
|
<h3><i class="fas fa-shield-halved"></i> Two-Factor Authentication</h3>
|
|
<p id="2fa-status">Status: Loading...</p>
|
|
<button id="btn-setup-2fa" class="btn-sm btn-primary">Enable 2FA</button>
|
|
<button id="btn-disable-2fa" class="btn-sm btn-ghost hidden">Disable 2FA</button>
|
|
<div id="2fa-setup" class="hidden">
|
|
<p>Scan this QR code with your authenticator app:</p>
|
|
<img id="2fa-qr" src="" alt="QR Code">
|
|
<p>Or enter manually: <code id="2fa-secret"></code></p>
|
|
<div class="form-group">
|
|
<label>Enter the 6-digit code to verify:</label>
|
|
<input type="text" id="2fa-verify-code" maxlength="6" placeholder="123456">
|
|
<button id="btn-verify-2fa" class="btn-sm btn-success">Verify & Enable</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Nextcloud -->
|
|
<div class="settings-section card">
|
|
<h3><i class="fas fa-cloud"></i> Nextcloud Integration</h3>
|
|
<p>Export generated documents to your Nextcloud.</p>
|
|
<div id="nc-status">Not connected</div>
|
|
<div class="form-group">
|
|
<label>Nextcloud URL</label>
|
|
<input type="text" id="nc-url" placeholder="https://cloud.example.com">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Username</label>
|
|
<input type="text" id="nc-user" placeholder="your-username">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>App Password</label>
|
|
<input type="password" id="nc-pass" placeholder="Generate in Nextcloud → Settings → Security">
|
|
<small>Go to Nextcloud → Settings → Security → Create new app password</small>
|
|
</div>
|
|
<button id="btn-nc-connect" class="btn-sm btn-primary">Connect</button>
|
|
<button id="btn-nc-disconnect" class="btn-sm btn-ghost hidden">Disconnect</button>
|
|
<div id="nc-webdav-path-section" class="hidden" style="margin-top:14px;padding-top:14px;border-top:1px solid var(--g100);">
|
|
<label style="display:block;font-size:12px;font-weight:600;color:var(--g600);margin-bottom:4px;">Learning Hub — Default Browse Path</label>
|
|
<small style="display:block;color:var(--g500);font-size:12px;margin-bottom:6px;">Folder opened first when picking files for AI content generation (e.g. <code>/Medical-Resources</code>)</small>
|
|
<div style="display:flex;gap:8px;">
|
|
<input type="text" id="nc-webdav-path" placeholder="/Medical-Resources" style="flex:1;font-size:13px;padding:6px 10px;border:1px solid var(--g300);border-radius:6px;">
|
|
<button id="btn-nc-save-path" class="btn-sm btn-primary">Save Path</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- My Templates / Memories -->
|
|
<div class="settings-section card">
|
|
<h3><i class="fas fa-book-medical"></i> My Templates</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Save reusable templates for physical exam, ROS, encounter format, etc. The AI will use these when generating notes. You can reference them by saying "use my normal physical exam" in dictation.</p>
|
|
<div style="margin-bottom:10px;display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
|
|
<select id="mem-category" style="font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;">
|
|
<option value="physical_exam">Physical Exam Template</option>
|
|
<option value="ros">Review of Systems Template</option>
|
|
<option value="encounter_format">Encounter Note Format</option>
|
|
<option value="family_history">Family History Format</option>
|
|
<option value="assessment_plan">Assessment & Plan Format</option>
|
|
<option value="template_soap">SOAP Note Template</option>
|
|
<option value="template_hpi">HPI Template</option>
|
|
<option value="template_wellvisit">Well Visit Template</option>
|
|
<option value="template_sickvisit">Sick Visit Template</option>
|
|
<option value="custom">Custom</option>
|
|
</select>
|
|
<input type="text" id="mem-name" style="font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;flex:1;min-width:150px;" placeholder="Template name (e.g. Normal PE)">
|
|
</div>
|
|
<textarea id="mem-content" rows="5" style="width:100%;font-size:12px;padding:8px;border:1px solid var(--g300);border-radius:6px;resize:vertical;box-sizing:border-box;" placeholder="Paste your template here. Example: HEENT: Normocephalic, atraumatic. Eyes: PERRL. Ears: TMs clear. Throat: clear..."></textarea>
|
|
<div style="margin-top:8px;display:flex;gap:8px;">
|
|
<button id="btn-mem-save" class="btn-sm btn-primary"><i class="fas fa-plus"></i> Add Template</button>
|
|
</div>
|
|
<div id="mem-list" style="margin-top:12px;display:flex;flex-direction:column;gap:6px;">
|
|
<p style="color:var(--g400);font-size:13px;">Loading templates...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Documents (S3) -->
|
|
<div class="settings-section card" id="documents-section">
|
|
<h3><i class="fas fa-file-arrow-up"></i> Documents</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Upload and manage documents via S3 storage (PDF, images, Word docs, text files). Max 10 MB per file.</p>
|
|
<div id="doc-upload-area" style="margin-bottom:12px;">
|
|
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
|
|
<input type="file" id="doc-file-input" accept=".pdf,.jpg,.jpeg,.png,.gif,.doc,.docx,.txt,.csv" style="font-size:13px;">
|
|
<input type="text" id="doc-description" placeholder="Description (optional)" style="font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;flex:1;min-width:150px;">
|
|
<button id="btn-doc-upload" class="btn-sm btn-primary"><i class="fas fa-upload"></i> Upload</button>
|
|
</div>
|
|
</div>
|
|
<div id="documents-list" style="display:flex;flex-direction:column;gap:6px;">
|
|
<p style="color:var(--g400);font-size:13px;">Loading...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- AI Corrections (Dragon-like memory) -->
|
|
<div class="settings-section card">
|
|
<h3><i class="fas fa-brain"></i> AI Learning (Corrections)</h3>
|
|
<p style="font-size:13px;color:var(--g600);">The AI automatically learns from your edits. When you modify AI-generated text and save, corrections are stored here and applied to future notes. Latest 20 per section.</p>
|
|
<div id="corrections-list" style="display:flex;flex-direction:column;gap:6px;">
|
|
<p style="color:var(--g400);font-size:13px;">Loading corrections...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Audio Backups -->
|
|
<div class="settings-section card">
|
|
<h3><i class="fas fa-microphone-lines"></i> Audio Backups</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Recordings are automatically backed up locally and kept for 24 hours. Retry transcription if it failed.</p>
|
|
<div id="audio-backups-list" style="display:flex;flex-direction:column;gap:6px;">
|
|
<p style="color:var(--g400);font-size:13px;">Loading...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Saved Encounters -->
|
|
<div class="settings-section card">
|
|
<h3><i class="fas fa-floppy-disk"></i> Saved Encounters</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Encounters are automatically deleted after 7 days per site policy.</p>
|
|
<div id="saved-enc-list" style="display:flex;flex-direction:column;gap:6px;">
|
|
<p style="color:var(--g400);font-size:13px;">Loading...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Compliance -->
|
|
<div class="settings-section card">
|
|
<h3><i class="fas fa-shield-halved"></i> Compliance & Usage</h3>
|
|
<div class="hipaa-info">
|
|
<p><strong>AWS Bedrock</strong> is available with a Business Associate Agreement (BAA) for HIPAA-eligible workloads.</p>
|
|
<ul>
|
|
<li>✅ All connections use HTTPS/TLS encryption</li>
|
|
<li>✅ Authentication with optional 2FA</li>
|
|
<li>✅ No patient data stored on server beyond session</li>
|
|
<li>✅ AWS Bedrock supports BAA for HIPAA compliance</li>
|
|
<li>✅ Azure OpenAI supports BAA for HIPAA compliance</li>
|
|
</ul>
|
|
<p><strong>Important:</strong> Check with your institution's guidelines and policies before use. This tool is not intended for production clinical use without proper organizational authorization and provider BAAs in place. Use with caution.</p>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|