- satellite.py: разделён _runtime_volume на _runtime_mic_volume и _runtime_snd_volume - satellite.py: добавлены команды start_recording/stop_recording (WAV через base64) - satellite.py: метод _create_wav_from_buffer() для создания WAV из буфера - web-client: добавлен слайдер громкости микрофона (MIC+/MIC-) - web-client: добавлены кнопки записи и воспроизведения аудио - web-client: улучшенный лог событий и отладочные console.log - docs: websocket-server-plan.md сокращён с 1205 до ~80 строк Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
128 lines
5.2 KiB
HTML
128 lines
5.2 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||
<title>NOVA Voice Assistant</title>
|
||
<link rel="stylesheet" href="styles.css">
|
||
<script src="script.js" defer></script>
|
||
</head>
|
||
<body>
|
||
<div class="app-container">
|
||
<!-- Верхняя панель -->
|
||
<header class="app-header">
|
||
<div class="logo">
|
||
<span class="logo-icon">🎙️</span>
|
||
<span class="logo-text">NOVA Assistant</span>
|
||
</div>
|
||
<div class="connection-status">
|
||
<div class="led" id="statusLed"></div>
|
||
<span class="status-text" id="statusLabel">disconnected</span>
|
||
<button id="connectBtn" class="btn-outline">⟳ Connect</button>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Блок настроек WebSocket -->
|
||
<div class="settings-card glass">
|
||
<div class="settings-row">
|
||
<input type="text" id="wsUrlInput" value="ws://192.168.200.111:8675" placeholder="ws://ip:port" class="input-url">
|
||
<button id="connectBtnCard" class="btn-primary">Connect</button>
|
||
<label class="auto-connect">
|
||
<input type="checkbox" id="autoConnect" checked> Auto-connect
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Основная сетка -->
|
||
<div class="dashboard">
|
||
<!-- Левая колонка: голосовой аватар -->
|
||
<div class="card voice-card glass">
|
||
<div class="card-header">
|
||
<span class="header-icon">🎤</span>
|
||
<h3>Voice Core</h3>
|
||
</div>
|
||
<div class="avatar-container">
|
||
<div class="orb" id="orbCore">
|
||
<div class="orb-pulse"></div>
|
||
<div class="orb-inner">🎙️</div>
|
||
</div>
|
||
<div class="state-badge" id="stateText">Idle</div>
|
||
</div>
|
||
<!-- Визуализатор аудио (волны) -->
|
||
<div class="viz-wrapper">
|
||
<canvas id="audioCanvas" width="500" height="80"></canvas>
|
||
</div>
|
||
<!-- RMS-метр -->
|
||
<div class="rms-container">
|
||
<div class="rms-label">RMS Level</div>
|
||
<div class="rms-bar">
|
||
<div class="rms-fill" id="rmsFill"></div>
|
||
</div>
|
||
<div class="rms-value" id="rmsValue">0.00</div>
|
||
</div>
|
||
<!-- Регулировка громкости -->
|
||
<div class="volume-control">
|
||
<span>🔊 Volume</span>
|
||
<input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="0.8">
|
||
<span id="volumeValue" class="volume-percent">80%</span>
|
||
</div>
|
||
<div class="button-group">
|
||
<button id="muteBtn" class="btn-secondary">🔇 Mute</button>
|
||
<button id="unmuteBtn" class="btn-secondary">🎤 Unmute</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Центр: команды и транскрипция -->
|
||
<div class="card commands-card glass">
|
||
<div class="card-header">
|
||
<span class="header-icon">🕹️</span>
|
||
<h3>Commands & Transcripts</h3>
|
||
</div>
|
||
<div class="button-group">
|
||
<button id="startListeningBtn" class="btn-primary">🎧 Start Listen</button>
|
||
<button id="stopPipelineBtn" class="btn-danger">⏹️ Stop Pipeline</button>
|
||
<button id="stopTimerBtn" class="btn-secondary">⏲️ Stop Timer</button>
|
||
</div>
|
||
<div class="button-group">
|
||
<button id="volUpBtn" class="btn-secondary">➕ Vol+</button>
|
||
<button id="volDownBtn" class="btn-secondary">➖ Vol-</button>
|
||
<button id="requestRmsBtn" class="btn-secondary">📊 Request RMS</button>
|
||
</div>
|
||
<div class="button-group">
|
||
<button id="singlePressBtn" class="btn-outline">Single</button>
|
||
<button id="doublePressBtn" class="btn-outline">Double</button>
|
||
<button id="triplePressBtn" class="btn-outline">Triple</button>
|
||
<button id="longPressBtn" class="btn-outline">Long</button>
|
||
</div>
|
||
<div class="transcript-area">
|
||
<div class="transcript-item">
|
||
<div class="transcript-label">You said:</div>
|
||
<div id="lastStt" class="transcript-text">—</div>
|
||
</div>
|
||
<div class="transcript-item">
|
||
<div class="transcript-label">Assistant said:</div>
|
||
<div id="lastTts" class="transcript-text">—</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Правая колонка: телеметрия и логи -->
|
||
<div class="card telemetry-card glass">
|
||
<div class="card-header">
|
||
<span class="header-icon">📡</span>
|
||
<h3>Telemetry & Events</h3>
|
||
</div>
|
||
<div class="status-grid">
|
||
<div class="status-chip"><span>🔇 Muted:</span> <strong id="mutedStatus">—</strong></div>
|
||
<div class="status-chip"><span>🏠 HA:</span> <strong id="haStatus">—</strong></div>
|
||
<div class="status-chip"><span>🎚️ Vol:</span> <strong id="liveVol">—</strong></div>
|
||
</div>
|
||
<div class="event-feed" id="eventFeed">
|
||
<div class="event-item">⬤ Ready to connect...</div>
|
||
</div>
|
||
<button id="clearEvents" class="btn-secondary full-width">Clear log</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html> |