Feature audit - Settings claimed you could reference a template by saying "use my normal physical exam" in dictation. No phrase handling exists anywhere, and the prompt says the opposite: "Never copy clinical content from a template — only formatting and structure." So a template can never supply findings. The text now says what happens, and keeps the true privacy statement that only template categories go to the AI (Custom is filtered out in /memories/context by AI_CONTEXT_CATEGORIES). - Templates themselves are real: CRUD plus /memories/context, injected as style hints by hpi, soap, sickVisit, wellVisit, edEncounters and hospitalCourse, behind the `memories` feature flag. Docs - docs/CLINICAL_ASSISTANT.md listed six settings and offered `deepl`, which no longer exists in the code. The table now covers all seventeen keys the server reads, with their fallbacks, plus how a model reaches a user. Testing - Every test file's stdout is now pure TAP, which is the stream node:test parses results from. Three sources: a leftover debug console.log dumping 600 characters of HTML, page modules logging into a JSDOM without a virtual console, and the server startup banners. The banners are guarded by NODE_TEST_CONTEXT, set only inside node:test children, so production and `node server.js` output is unchanged (verified both ways). - Three consecutive full-suite runs at 671/671. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
222 lines
16 KiB
HTML
222 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 data-feature="read_aloud" 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>
|
|
|
|
<!-- 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 server transcription with a HIPAA-eligible provider.</p>
|
|
</div>
|
|
|
|
<!-- Change Password — hidden by default; unhidden only for users with a real password -->
|
|
<div class="settings-section card" id="change-password-section" style="display:none;">
|
|
<h3><i class="fas fa-key"></i> Change Password</h3>
|
|
<div class="form-group" style="max-width:340px;">
|
|
<label>Current Password</label>
|
|
<input type="password" id="pw-current" placeholder="Enter current password">
|
|
</div>
|
|
<div class="form-group" style="max-width:340px;">
|
|
<label>New Password (8+ characters)</label>
|
|
<input type="password" id="pw-new" minlength="8" placeholder="Enter new password">
|
|
</div>
|
|
<div class="form-group" style="max-width:340px;">
|
|
<label>Confirm New Password</label>
|
|
<input type="password" id="pw-confirm" minlength="8" placeholder="Confirm new password">
|
|
</div>
|
|
<button id="btn-change-password" class="btn-sm btn-primary"><i class="fas fa-check"></i> Change Password</button>
|
|
<span id="pw-change-status" style="font-size:13px;margin-left:8px;"></span>
|
|
</div>
|
|
|
|
<!-- 2FA — hidden by default; unhidden only for users with a real password (SSO users use their IdP's MFA) -->
|
|
<div class="settings-section card" id="2fa-section" style="display:none;">
|
|
<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" style="color:var(--red);">Disable 2FA</button>
|
|
<div id="2fa-backup-info"></div>
|
|
<div id="2fa-disable-confirm" class="hidden" style="margin-top:10px;padding:12px;background:var(--g50);border-radius:8px;border:1px solid var(--g200);max-width:340px;">
|
|
<div class="form-group" style="margin-bottom:8px;">
|
|
<label>Enter your password to confirm:</label>
|
|
<input type="password" id="2fa-disable-password" placeholder="Password">
|
|
</div>
|
|
<div style="display:flex;gap:6px;">
|
|
<button id="btn-disable-2fa-confirm" class="btn-sm btn-primary" style="background:var(--red);border-color:var(--red);">Confirm Disable</button>
|
|
<button id="btn-disable-2fa-cancel" class="btn-sm btn-ghost">Cancel</button>
|
|
</div>
|
|
</div>
|
|
<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>
|
|
|
|
<!-- Active Sessions — hidden for SSO-only users (revoke can't stick against an active IdP session) -->
|
|
<div class="settings-section card" id="sessions-section" style="display:none;">
|
|
<h3><i class="fas fa-desktop"></i> Active Sessions</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Devices where you are currently logged in. Revoke any session to immediately log that device out.</p>
|
|
<div style="margin-bottom:10px;">
|
|
<button id="btn-revoke-all-sessions" class="btn-sm btn-ghost" style="color:var(--red);font-size:12px;"><i class="fas fa-ban"></i> Revoke All Other Sessions</button>
|
|
</div>
|
|
<div id="sessions-list" style="display:flex;flex-direction:column;gap:6px;">
|
|
<p style="color:var(--g400);font-size:13px;">Loading sessions...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Nextcloud -->
|
|
<div class="settings-section card" data-feature="nextcloud">
|
|
<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" data-feature="memories">
|
|
<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. Only template categories are sent to AI when generating notes — anything saved as <strong>Custom</strong> is never sent. Templates go out with Encounter HPI, Dictation HPI, SOAP, Sick Visit, Well Visit, ED Encounter and Hospital Course, and shape how a note is laid out and worded. The AI is told never to copy clinical content out of a template, so a template cannot supply findings you did not dictate: say them instead, for example “normal cardiac exam”, and they are documented.</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="template_ed">ED Template</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)">
|
|
<a href="/template-guide.md" download="ped-ai-template-guide.md" class="btn-sm btn-ghost" style="text-decoration:none;"><i class="fas fa-download"></i> Template Guide</a>
|
|
</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>
|
|
|
|
<!-- 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>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>
|