Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Clinical Note Scribe</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> | |
| <style> | |
| *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } | |
| :root { | |
| --bg: #0f1117; | |
| --surface: #1a1d27; | |
| --surface-2: #242836; | |
| --border: #2e3345; | |
| --text: #e4e6ef; | |
| --text-muted: #8b8fa3; | |
| --accent: #4f8cff; | |
| --accent-glow: rgba(79, 140, 255, 0.15); | |
| --green: #34d399; | |
| --red: #f87171; | |
| --yellow: #fbbf24; | |
| --radius: 10px; | |
| --font: 'Inter', -apple-system, sans-serif; | |
| } | |
| body { | |
| font-family: var(--font); | |
| background: var(--bg); | |
| color: var(--text); | |
| min-height: 100vh; | |
| line-height: 1.5; | |
| } | |
| /* Header */ | |
| .header { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 16px 28px; | |
| border-bottom: 1px solid var(--border); | |
| background: var(--surface); | |
| } | |
| .header h1 { | |
| font-size: 18px; | |
| font-weight: 600; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .header h1 span { font-size: 22px; } | |
| .header-right { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .status-badge { | |
| font-size: 12px; | |
| padding: 4px 10px; | |
| border-radius: 20px; | |
| font-weight: 500; | |
| } | |
| .status-badge.idle { background: var(--surface-2); color: var(--text-muted); } | |
| .status-badge.active { background: rgba(52,211,153,0.15); color: var(--green); } | |
| .status-badge.done { background: rgba(79,140,255,0.15); color: var(--accent); } | |
| /* Layout */ | |
| .layout { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 0; | |
| height: calc(100vh - 57px); | |
| } | |
| .panel { | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| } | |
| .panel-left { border-right: 1px solid var(--border); } | |
| .panel-section { | |
| padding: 16px 20px; | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .panel-section.resizable { | |
| resize: vertical; | |
| overflow-y: auto; | |
| overflow-x: hidden; | |
| min-height: 80px; | |
| max-height: 250px; | |
| } | |
| .panel-section-title { | |
| font-size: 11px; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| letter-spacing: 0.8px; | |
| color: var(--text-muted); | |
| margin-bottom: 10px; | |
| } | |
| .scrollable { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 16px 20px; | |
| } | |
| .scrollable::-webkit-scrollbar { width: 6px; } | |
| .scrollable::-webkit-scrollbar-track { background: transparent; } | |
| .scrollable::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; } | |
| /* Controls */ | |
| .controls { | |
| display: flex; | |
| gap: 8px; | |
| flex-wrap: wrap; | |
| align-items: center; | |
| } | |
| select, input, textarea { | |
| font-family: var(--font); | |
| font-size: 13px; | |
| background: var(--surface-2); | |
| border: 1px solid var(--border); | |
| color: var(--text); | |
| border-radius: 6px; | |
| padding: 7px 10px; | |
| outline: none; | |
| transition: border-color 0.15s; | |
| } | |
| select:focus, input:focus, textarea:focus { | |
| border-color: var(--accent); | |
| } | |
| textarea { | |
| width: 100%; | |
| resize: vertical; | |
| min-height: 80px; | |
| } | |
| .btn { | |
| font-family: var(--font); | |
| font-size: 13px; | |
| font-weight: 500; | |
| padding: 7px 16px; | |
| border: none; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| transition: all 0.15s; | |
| } | |
| .btn:disabled { opacity: 0.4; cursor: not-allowed; } | |
| .btn-primary { background: var(--accent); color: #fff; } | |
| .btn-primary:hover:not(:disabled) { background: #3d7ae8; } | |
| .btn-secondary { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); } | |
| .btn-secondary:hover:not(:disabled) { background: var(--border); } | |
| .btn-green { background: var(--green); color: #0f1117; } | |
| .btn-green:hover:not(:disabled) { background: #2bc48d; } | |
| /* Transcript */ | |
| .transcript-box { | |
| font-size: 13px; | |
| white-space: pre-wrap; | |
| color: var(--text); | |
| line-height: 1.7; | |
| } | |
| .transcript-box .speaker-doctor { color: var(--accent); font-weight: 500; } | |
| .transcript-box .speaker-patient { color: var(--green); font-weight: 500; } | |
| /* Context cards */ | |
| .context-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); | |
| gap: 8px; | |
| } | |
| .context-card { | |
| background: var(--surface-2); | |
| border-radius: 8px; | |
| padding: 10px 12px; | |
| } | |
| .context-card .label { | |
| font-size: 10px; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| color: var(--text-muted); | |
| margin-bottom: 3px; | |
| } | |
| .context-card .value { | |
| font-size: 13px; | |
| color: var(--text); | |
| } | |
| /* SOAP Draft */ | |
| .soap-grid { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 10px; | |
| } | |
| .soap-card { | |
| background: var(--surface-2); | |
| border-radius: 8px; | |
| padding: 12px 14px; | |
| border-left: 3px solid var(--border); | |
| } | |
| .soap-card.s { border-left-color: #60a5fa; } | |
| .soap-card.o { border-left-color: #34d399; } | |
| .soap-card.a { border-left-color: #fbbf24; } | |
| .soap-card.p { border-left-color: #c084fc; } | |
| .soap-card .soap-label { | |
| font-size: 11px; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| margin-bottom: 6px; | |
| } | |
| .soap-card.s .soap-label { color: #60a5fa; } | |
| .soap-card.o .soap-label { color: #34d399; } | |
| .soap-card.a .soap-label { color: #fbbf24; } | |
| .soap-card.p .soap-label { color: #c084fc; } | |
| .soap-card .soap-text { | |
| font-size: 13px; | |
| color: var(--text-muted); | |
| line-height: 1.6; | |
| } | |
| /* Reward bar */ | |
| .reward-bar { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| padding: 10px 0; | |
| } | |
| .reward-bar .score-value { | |
| font-size: 28px; | |
| font-weight: 700; | |
| font-variant-numeric: tabular-nums; | |
| } | |
| .reward-meter { | |
| flex: 1; | |
| height: 8px; | |
| background: var(--surface-2); | |
| border-radius: 4px; | |
| overflow: hidden; | |
| } | |
| .reward-meter-fill { | |
| height: 100%; | |
| border-radius: 4px; | |
| background: linear-gradient(90deg, var(--accent), var(--green)); | |
| transition: width 0.4s ease; | |
| } | |
| /* Action form */ | |
| .action-form { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 10px; | |
| } | |
| .action-row { | |
| display: flex; | |
| gap: 8px; | |
| align-items: flex-start; | |
| } | |
| .action-row select { min-width: 160px; } | |
| /* Log */ | |
| .log-container { | |
| font-size: 12px; | |
| font-family: 'SF Mono', 'Fira Code', monospace; | |
| color: var(--text-muted); | |
| height: 120px; | |
| min-height: 60px; | |
| overflow-y: auto; | |
| resize: vertical; | |
| padding: 8px 0; | |
| } | |
| .log-entry { | |
| padding: 2px 0; | |
| border-bottom: 1px solid rgba(46, 51, 69, 0.4); | |
| } | |
| .log-entry .log-time { color: var(--border); margin-right: 8px; } | |
| .log-entry.error { color: var(--red); } | |
| .log-entry.success { color: var(--green); } | |
| /* Empty state */ | |
| .empty-state { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| height: 100%; | |
| color: var(--text-muted); | |
| text-align: center; | |
| gap: 12px; | |
| } | |
| .empty-state .icon { font-size: 36px; opacity: 0.5; } | |
| .empty-state p { font-size: 14px; max-width: 280px; } | |
| /* Responsive Design */ | |
| @media (max-width: 768px) { | |
| .layout { | |
| display: flex; | |
| flex-direction: column; | |
| height: auto; | |
| } | |
| .panel-left { | |
| border-right: none; | |
| border-bottom: 2px solid var(--border); | |
| min-height: 60vh; | |
| } | |
| .panel { | |
| overflow: visible; | |
| } | |
| .scrollable { | |
| overflow-y: visible; | |
| } | |
| #soapInputs > div { | |
| grid-template-columns: 1fr ; | |
| } | |
| .soap-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| .header h1 span { font-size: 18px; } | |
| .header h1 { font-size: 15px; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header class="header"> | |
| <h1><span>π₯</span> Clinical Note Scribe</h1> | |
| <div class="header-right"> | |
| <span class="status-badge idle" id="statusBadge">Idle</span> | |
| </div> | |
| </header> | |
| <div class="layout"> | |
| <!-- Left Panel: Transcript + Context --> | |
| <div class="panel panel-left"> | |
| <div class="panel-section"> | |
| <div class="controls"> | |
| <select id="taskSelect"> | |
| <option value="easy_routine_checkup">π’ Easy β Routine Check-Up</option> | |
| <option value="medium_chronic_disease_followup">π‘ Medium β Chronic Follow-Up</option> | |
| <option value="hard_complex_er_visit">π΄ Hard β Complex ER Visit</option> | |
| </select> | |
| <button class="btn btn-primary" id="resetBtn">Reset</button> | |
| </div> | |
| </div> | |
| <div class="panel-section resizable" id="contextSection" style="display:none;"> | |
| <div class="panel-section-title">Patient Context</div> | |
| <div class="context-grid" id="contextGrid"></div> | |
| </div> | |
| <div class="scrollable" id="transcriptArea"> | |
| <div class="empty-state"> | |
| <div class="icon">π</div> | |
| <p>Select a task and click <strong>Reset</strong> to load the transcript.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Right Panel: Actions + Draft + Reward --> | |
| <div class="panel"> | |
| <div class="panel-section resizable" id="actionSection" style="display:none;"> | |
| <div class="panel-section-title">Action</div> | |
| <div class="action-form"> | |
| <div class="action-row"> | |
| <select id="actionType"> | |
| <option value="submit_note">Submit Note</option> | |
| <option value="revise_section">Revise Section</option> | |
| <option value="request_clarify">Request Clarify</option> | |
| </select> | |
| <select id="sectionSelect" style="display:none;"> | |
| <option value="S">Subjective</option> | |
| <option value="O">Objective</option> | |
| <option value="A">Assessment</option> | |
| <option value="P">Plan</option> | |
| </select> | |
| <button class="btn btn-green" id="stepBtn">Send</button> | |
| </div> | |
| <div id="soapInputs"> | |
| <div style="display:grid; grid-template-columns:1fr 1fr; gap:8px;"> | |
| <textarea id="inputS" placeholder="Subjective..." rows="3"></textarea> | |
| <textarea id="inputO" placeholder="Objective..." rows="3"></textarea> | |
| <textarea id="inputA" placeholder="Assessment..." rows="3"></textarea> | |
| <textarea id="inputP" placeholder="Plan..." rows="3"></textarea> | |
| </div> | |
| </div> | |
| <div id="reviseInput" style="display:none;"> | |
| <textarea id="inputRevision" placeholder="Revision text..." rows="3"></textarea> | |
| </div> | |
| <div id="clarifyInput" style="display:none;"> | |
| <input id="inputClarify" type="text" placeholder="Your question..." style="width:100%;"> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="panel-section resizable" id="rewardSection" style="display:none;"> | |
| <div class="panel-section-title">Reward</div> | |
| <div class="reward-bar"> | |
| <div class="score-value" id="scoreValue">0.00</div> | |
| <div class="reward-meter"> | |
| <div class="reward-meter-fill" id="rewardFill" style="width:0%"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="scrollable" id="draftArea"> | |
| <div class="empty-state" id="draftEmpty"> | |
| <div class="icon">π</div> | |
| <p>Your SOAP note draft will appear here after you submit or revise.</p> | |
| </div> | |
| <div id="soapDraft" style="display:none;"> | |
| <div class="panel-section-title" style="margin-bottom:12px;">Current Draft</div> | |
| <div class="soap-grid" id="soapGrid"></div> | |
| </div> | |
| </div> | |
| <div class="panel-section" style="border-top:1px solid var(--border); border-bottom:none;"> | |
| <div class="panel-section-title">Log</div> | |
| <div class="log-container" id="logContainer"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="/static/app.js"></script> | |
| </body> | |
| </html> | |