Voice-AI-Agent / frontend /index.html
rakib72642's picture
added communication full layer
5dabf9d
raw
history blame
11.1 kB
<!DOCTYPE html>
<html lang="bn">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>DAA — ডাক্তার অ্যাপয়েন্টমেন্ট সহকারী</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="style.css" />
</head>
<body>
<!-- ── Ambient background ── -->
<div class="bg-orb orb-1"></div>
<div class="bg-orb orb-2"></div>
<div class="bg-orb orb-3"></div>
<!-- ══════════════════════════════════════════════════════════════
INIT OVERLAY — shown until WS ready + animations done
Hard 8 s failsafe closes overlay if backend is slow.
══════════════════════════════════════════════════════════════ -->
<div id="init-overlay" class="init-overlay">
<div class="init-card">
<div class="init-logo">
<svg width="56" height="56" viewBox="0 0 56 56" fill="none">
<circle cx="28" cy="28" r="26" stroke="url(#g1)" stroke-width="2"/>
<path d="M18 28 Q28 16 38 28 Q28 40 18 28Z" fill="url(#g2)" opacity="0.9"/>
<defs>
<linearGradient id="g1" x1="0" y1="0" x2="56" y2="56">
<stop offset="0%" stop-color="#22d3ee"/><stop offset="100%" stop-color="#818cf8"/>
</linearGradient>
<linearGradient id="g2" x1="0" y1="0" x2="56" y2="56">
<stop offset="0%" stop-color="#22d3ee"/><stop offset="100%" stop-color="#818cf8"/>
</linearGradient>
</defs>
</svg>
</div>
<h2 class="init-title">AI Voice Assistant</h2>
<p class="init-subtitle">বাংলা ভয়েস সহকারী</p>
<div class="init-stages">
<div class="stage" id="stage-1">
<div class="stage-dot"></div>
<span>AI Engine শুরু হচ্ছে…</span>
<div class="stage-check"></div>
</div>
<div class="stage" id="stage-2">
<div class="stage-dot"></div>
<span>Speech Recognition মডেল লোড হচ্ছে…</span>
<div class="stage-check"></div>
</div>
<div class="stage" id="stage-3">
<div class="stage-dot"></div>
<span>GPU Warmup চলছে…</span>
<div class="stage-check"></div>
</div>
<div class="stage" id="stage-4">
<div class="stage-dot"></div>
<span>Voice Pipeline প্রস্তুত হচ্ছে…</span>
<div class="stage-check"></div>
</div>
</div>
<div class="init-bar-wrap">
<div class="init-bar" id="init-bar"></div>
</div>
<p class="init-status" id="init-status">সংযোগ স্থাপন করা হচ্ছে…</p>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════
MAIN APP
FIX-7: Hidden via .app CSS class (not inline opacity:0) to
prevent FOUC. JS adds class "visible" after init closes.
══════════════════════════════════════════════════════════════ -->
<div class="app" id="app">
<!-- ── Sidebar ── -->
<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>DAA Assistant</span>
</div>
<button class="sidebar-toggle" id="sidebar-toggle" title="Toggle sidebar"></button>
</div>
<!-- System Status -->
<div class="status-panel">
<div class="status-row">
<span class="status-label">System</span>
<span class="status-badge badge-green" id="sys-status">Ready</span>
</div>
<div class="status-row">
<span class="status-label">STT</span>
<span class="status-badge badge-green" id="stt-status">Online</span>
</div>
<div class="status-row">
<span class="status-label">LLM</span>
<span class="status-badge badge-green" id="llm-status">Gemini 2.0</span>
</div>
<div class="status-row">
<span class="status-label">TTS</span>
<span class="status-badge badge-green" id="tts-status">Edge TTS</span>
</div>
</div>
<div class="sidebar-divider"></div>
<!-- Latency Dashboard -->
<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>
<!-- Voice Settings -->
<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 class="setting-row">
<label>TTS Voice</label>
<select id="s-voice" class="setting-select">
<option value="bn-BD-NabanitaNeural">Nabanita (Female)</option>
<option value="bn-BD-PradeepNeural">Pradeep (Male)</option>
<option value="bn-IN-BashkarNeural">Bashkar (IN Male)</option>
<option value="bn-IN-TanishaaNeural">Tanishaa (IN Female)</option>
</select>
</div>
</div>
<div class="sidebar-divider"></div>
<!-- Audio Queue -->
<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 area ── -->
<main class="main">
<!-- Top bar -->
<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="clear-btn" id="clear-btn" title="Clear conversation">↺ Clear</button>
</div>
</header>
<!-- Chat -->
<div id="chat-box"></div>
<!-- Voice visualizer — shown only while mic is active -->
<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>
<!-- Controls -->
<footer class="controls">
<div class="text-row">
<!-- FIX-4: textarea is created by script.js to replace this input,
keeping HTML clean while gaining auto-resize + shift-enter -->
<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">Voice শুরু করুন</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="script.js"></script>
</body>
</html>