| <!DOCTYPE html> |
| <html lang="bn"> |
| <head> |
| <meta charset="UTF-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
| <title>Hospital Assistant</title> |
| <link rel="preconnect" href="https://fonts.googleapis.com"> |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
| <link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=JetBrains+Mono:wght@300;400&family=Hind+Siliguri:wght@300;400;500;600&display=swap" rel="stylesheet"> |
| <link rel="stylesheet" href="/static/style.css" /> |
| </head> |
| <body> |
|
|
| <div class="app" id="app"> |
|
|
| |
| <aside class="sidebar" id="sidebar"> |
| <div class="sidebar-header"> |
| <div class="brand"> |
| <svg width="28" height="28" viewBox="0 0 56 56" fill="none"> |
| <circle cx="28" cy="28" r="26" stroke="url(#gs1)" stroke-width="2"/> |
| <path d="M18 28 Q28 16 38 28 Q28 40 18 28Z" fill="url(#gs2)" opacity="0.9"/> |
| <defs> |
| <linearGradient id="gs1" x1="0" y1="0" x2="56" y2="56"> |
| <stop offset="0%" stop-color="#22d3ee"/><stop offset="100%" stop-color="#818cf8"/> |
| </linearGradient> |
| <linearGradient id="gs2" x1="0" y1="0" x2="56" y2="56"> |
| <stop offset="0%" stop-color="#22d3ee"/><stop offset="100%" stop-color="#818cf8"/> |
| </linearGradient> |
| </defs> |
| </svg> |
| <span>Hospital Assistant</span> |
| </div> |
| <button class="sidebar-toggle" id="sidebar-toggle" title="Toggle sidebar">‹</button> |
| </div> |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| <div class="sidebar-divider"></div> |
|
|
| |
| <div class="dash-section"> |
| <div class="dash-title">⚡ Latency Dashboard</div> |
| <div class="metric-grid"> |
| <div class="metric-card"> |
| <div class="metric-val" id="m-stt">—</div> |
| <div class="metric-label">STT (ms)</div> |
| </div> |
| <div class="metric-card"> |
| <div class="metric-val" id="m-llm">—</div> |
| <div class="metric-label">LLM (ms)</div> |
| </div> |
| <div class="metric-card"> |
| <div class="metric-val" id="m-tts">—</div> |
| <div class="metric-label">TTS (ms)</div> |
| </div> |
| <div class="metric-card"> |
| <div class="metric-val" id="m-total">—</div> |
| <div class="metric-label">Total (ms)</div> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="sidebar-divider"></div> |
|
|
| |
| <div class="dash-section"> |
| <div class="dash-title">🎛️ Voice Settings</div> |
| <div class="setting-row"> |
| <label>Silence Threshold</label> |
| <div class="slider-wrap"> |
| <input type="range" id="s-threshold" min="-60" max="-20" value="-32" step="1"> |
| <span id="s-threshold-val">-32 dB</span> |
| </div> |
| </div> |
| <div class="setting-row"> |
| <label>Silence Timeout</label> |
| <div class="slider-wrap"> |
| <input type="range" id="s-timeout" min="300" max="2000" value="900" step="50"> |
| <span id="s-timeout-val">900 ms</span> |
| </div> |
| </div> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| </div> |
|
|
| <div class="sidebar-divider"></div> |
|
|
| |
| <div class="dash-section"> |
| <div class="dash-title">📊 Audio Stream</div> |
| <div class="queue-vis" id="queue-vis"> |
| <div class="queue-bar" style="height:4px"></div> |
| <div class="queue-bar" style="height:4px"></div> |
| <div class="queue-bar" style="height:4px"></div> |
| <div class="queue-bar" style="height:4px"></div> |
| <div class="queue-bar" style="height:4px"></div> |
| <div class="queue-bar" style="height:4px"></div> |
| <div class="queue-bar" style="height:4px"></div> |
| <div class="queue-bar" style="height:4px"></div> |
| </div> |
| <div class="queue-label">Chunks in flight: <span id="chunks-count">0</span></div> |
| </div> |
| </aside> |
|
|
| |
| <main class="main"> |
|
|
| |
| <header class="topbar"> |
| <div class="topbar-left"> |
| <button class="mobile-menu-btn" id="mobile-menu-btn">☰</button> |
| <div class="topbar-state"> |
| <div class="state-dot" id="state-dot"></div> |
| <span id="state-label">প্রস্তুত</span> |
| </div> |
| </div> |
| <div class="topbar-center"> |
| <span class="topbar-title">🏥 ডাক্তার অ্যাপয়েন্টমেন্ট সহকারী</span> |
| </div> |
| <div class="topbar-right"> |
| <button class="brain-btn" id="brain-mode-btn" title="Brain mode" aria-pressed="false" aria-label="Brain mode"> |
| <svg viewBox="0 0 24 24" aria-hidden="true"> |
| <path d="M8.5 5.5c-1.7 0-3 1.4-3 3.1 0 .8.3 1.5.8 2.1-1.1.5-1.8 1.5-1.8 2.8 0 1.7 1.4 3.1 3.1 3.1h.3c.2 1.3 1.4 2.3 2.8 2.3.9 0 1.8-.4 2.3-1.1.5.7 1.4 1.1 2.3 1.1 1.4 0 2.6-1 2.8-2.3h.3c1.7 0 3.1-1.4 3.1-3.1 0-1.2-.7-2.3-1.8-2.8.5-.6.8-1.3.8-2.1 0-1.7-1.3-3.1-3-3.1-.6 0-1.2.2-1.7.5-.5-1.1-1.5-1.8-2.7-1.8-1.2 0-2.2.7-2.7 1.8-.5-.3-1.1-.5-1.7-.5Z"/> |
| <path d="M7.6 8.4 9.8 11M16.4 8.4 14.2 11M6.8 13.4 9.4 13.8M17.2 13.4 14.6 13.8M10.1 15.8 12 17.5 13.9 15.8"/> |
| <circle cx="10" cy="11" r="0.8"/> |
| <circle cx="14" cy="11" r="0.8"/> |
| <circle cx="12" cy="13.8" r="0.9"/> |
| </svg> |
| </button> |
| <button class="clear-btn" id="clear-btn" title="Clear conversation">↺ Clear</button> |
| </div> |
| </header> |
|
|
| <div class="voice-caption" id="voice-caption" aria-live="polite"></div> |
|
|
| |
| <div id="chat-box"></div> |
|
|
| |
| <section class="brain-stage" id="brain-stage" aria-hidden="true"> |
| <div class="brain-shell"> |
| <div class="brain-bubbles" aria-hidden="true"> |
| <div class="brain-bubble brain-bubble-stt" id="brain-bubble-stt"> |
| <div class="brain-bubble-label">You</div> |
| <div class="brain-bubble-text" id="brain-bubble-stt-text">Listening…</div> |
| </div> |
| <div class="brain-bubble brain-bubble-tts" id="brain-bubble-tts"> |
| <div class="brain-bubble-label">AI</div> |
| <div class="brain-bubble-text" id="brain-bubble-tts-text">Waiting…</div> |
| </div> |
| </div> |
| <div class="brain-scan" aria-hidden="true"></div> |
| <div class="brain-pulse pulse-a" aria-hidden="true"></div> |
| <div class="brain-pulse pulse-b" aria-hidden="true"></div> |
| <div class="brain-pulse pulse-c" aria-hidden="true"></div> |
| <svg class="brain-svg" viewBox="0 0 960 620" role="presentation" aria-hidden="true"> |
| <defs> |
| <linearGradient id="brainGlow" x1="0" y1="0" x2="1" y2="1"> |
| <stop offset="0%" stop-color="#0ea5e9"/> |
| <stop offset="50%" stop-color="#8b5cf6"/> |
| <stop offset="100%" stop-color="#22c55e"/> |
| </linearGradient> |
| <filter id="brainBlur" x="-20%" y="-20%" width="140%" height="140%"> |
| <feGaussianBlur stdDeviation="8"/> |
| </filter> |
| </defs> |
| <g class="brain-net"> |
| <path class="brain-wire wire-a" d="M190 330C280 190 380 150 480 150s200 40 290 180"/> |
| <path class="brain-wire wire-b" d="M160 250C250 180 350 160 480 160s230 20 340 130"/> |
| <path class="brain-wire wire-c" d="M160 390C250 460 360 480 480 480s220-20 340-140"/> |
| <path class="brain-wire wire-d" d="M220 180C290 240 360 260 480 260s190-20 260-80"/> |
| <path class="brain-wire wire-e" d="M220 440C300 380 390 350 480 350s170 30 260 100"/> |
| <circle class="brain-node node-1" cx="190" cy="330" r="9"/> |
| <circle class="brain-node node-2" cx="300" cy="220" r="7"/> |
| <circle class="brain-node node-3" cx="410" cy="180" r="8"/> |
| <circle class="brain-node node-4" cx="480" cy="150" r="10"/> |
| <circle class="brain-node node-5" cx="560" cy="185" r="7"/> |
| <circle class="brain-node node-6" cx="670" cy="240" r="9"/> |
| <circle class="brain-node node-7" cx="760" cy="330" r="10"/> |
| <circle class="brain-node node-8" cx="660" cy="430" r="8"/> |
| <circle class="brain-node node-9" cx="520" cy="485" r="9"/> |
| <circle class="brain-node node-10" cx="360" cy="455" r="7"/> |
| <circle class="brain-node node-11" cx="260" cy="390" r="8"/> |
| <circle class="brain-node node-12" cx="300" cy="280" r="6"/> |
| </g> |
| <path class="brain-outline" d="M332 144c33-44 87-70 148-70 52 0 99 18 135 48 31 26 50 57 58 91 61 18 105 72 105 135 0 60-37 111-90 131-11 67-73 117-146 117-41 0-78-15-108-40-25 12-53 18-83 18-85 0-154-58-166-139-46-15-79-56-79-105 0-60 42-110 99-127 10-20 23-39 37-59 25-37 61-63 90-70z"/> |
| <circle class="brain-core" cx="480" cy="310" r="62" filter="url(#brainBlur)"/> |
| <circle class="brain-core ring" cx="480" cy="310" r="88"/> |
| </svg> |
| </div> |
| </section> |
|
|
| |
| <div class="voice-visualizer" id="voice-viz"> |
| <div class="viz-bar"></div><div class="viz-bar"></div><div class="viz-bar"></div> |
| <div class="viz-bar"></div><div class="viz-bar"></div><div class="viz-bar"></div> |
| <div class="viz-bar"></div><div class="viz-bar"></div><div class="viz-bar"></div> |
| <div class="viz-bar"></div><div class="viz-bar"></div><div class="viz-bar"></div> |
| <div class="viz-bar"></div><div class="viz-bar"></div><div class="viz-bar"></div> |
| </div> |
|
|
| |
| <footer class="controls"> |
| <div class="text-row"> |
| |
| |
| <input |
| type="text" |
| id="text-input" |
| placeholder="বার্তা লিখুন… (Enter পাঠান · Shift+Enter নতুন লাইন)" |
| autocomplete="off" |
| /> |
| <button id="send-btn" title="Send"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" |
| stroke="currentColor" stroke-width="2"> |
| <line x1="22" y1="2" x2="11" y2="13"/> |
| <polygon points="22 2 15 22 11 13 2 9 22 2"/> |
| </svg> |
| </button> |
| </div> |
| <div class="voice-row"> |
| <button id="mic-btn" class="mic-btn mic-off"> |
| <span class="mic-icon">🎤</span> |
| <span class="mic-label">Start</span> |
| </button> |
| <button id="stop-btn" class="stop-btn" title="Stop AI speech"> |
| <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"> |
| <rect x="4" y="4" width="16" height="16" rx="2"/> |
| </svg> |
| Stop |
| </button> |
| </div> |
| </footer> |
| </main> |
| </div> |
|
|
| <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> |
| <script src="/static/script.js"></script> |
| </body> |
| </html> |
|
|