2026-09-03 00:10:18 +04:00

169 lines
7.7 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en" data-loading="true">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="color-scheme" content="dark" />
<title>AGIBOT A3 · Voice Control</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🤖</text></svg>" />
<link rel="stylesheet" href="/styles/main.css" />
</head>
<body>
<!-- ================= HEADER ================= -->
<header class="topbar">
<div class="topbar__brand">
<span class="brand__mark" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
<rect x="4" y="8" width="16" height="12" rx="3" />
<path d="M12 4v4" /><circle cx="12" cy="3" r="1.4" />
<circle cx="9" cy="14" r="1.2" fill="currentColor" stroke="none" />
<circle cx="15" cy="14" r="1.2" fill="currentColor" stroke="none" />
<path d="M9.5 17.5h5" />
</svg>
</span>
<div class="brand__text">
<h1>AGIBOT A3</h1>
<p>Voice Control</p>
</div>
<span class="mode-badge" id="modeBadge" title="Robot mode">--</span>
</div>
<div class="topbar__status">
<!-- starts amber, not red: before the socket opens we genuinely do not
know the robot's state, and a red flash on every load reads as a fault -->
<div class="conn" id="connPill" data-state="connecting" title="Robot connection">
<span class="conn__dot" aria-hidden="true"></span>
<span class="conn__label" id="connLabel">Starting…</span>
</div>
<div class="chip" id="latencyChip" hidden title="Round-trip time to the robot">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M13 2 4 14h7l-1 8 9-12h-7l1-8Z"/></svg>
<span id="latencyValue"></span>
</div>
<button class="icon-btn" id="reconnectBtn" title="Reconnect to robot" aria-label="Reconnect to robot">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M21 12a9 9 0 1 1-2.64-6.36" /><path d="M21 3v6h-6" />
</svg>
</button>
</div>
</header>
<!-- ================= CONFIG BANNER ================= -->
<div class="banner" id="configBanner" hidden role="alert">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M12 9v4"/><path d="M12 17h.01"/><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z"/></svg>
<div class="banner__body"><strong id="bannerTitle">Configuration</strong><span id="bannerText"></span></div>
</div>
<!-- ================= MAIN ================= -->
<main class="layout">
<!-- ---------- speech panel ---------- -->
<section class="panel panel--speech" aria-label="Speech">
<div class="panel__head">
<h2>Say something</h2>
<span class="panel__hint">The robot speaks through its built-in speaker</span>
</div>
<div class="composer">
<textarea
id="textInput"
class="composer__input"
placeholder="Type what you want the robot to say…"
spellcheck="true"
autocomplete="off"
rows="7"
maxlength="1000"></textarea>
<div class="composer__meta">
<span class="kbd-hint"><kbd>Ctrl</kbd><span>+</span><kbd>Enter</kbd> to speak · <kbd>Esc</kbd> to stop</span>
<span class="counter" id="counter"><b id="counterNow">0</b> / <span id="counterMax">1000</span></span>
</div>
</div>
<div class="actions">
<button class="btn btn--speak" id="speakBtn" disabled>
<span class="btn__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 5 6 9H2v6h4l5 4V5Z" /><path d="M15.5 8.5a5 5 0 0 1 0 7" /><path d="M18.5 5.5a9 9 0 0 1 0 13" />
</svg>
</span>
<span class="btn__label" id="speakLabel">Speak</span>
<span class="btn__spinner" aria-hidden="true"></span>
</button>
<button class="btn btn--ghost" id="stopBtn" disabled>
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2" /></svg>
Stop
</button>
<button class="btn btn--ghost" id="clearBtn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M3 6h18"/><path d="M8 6V4h8v2"/><path d="m19 6-1 14H6L5 6"/></svg>
Clear
</button>
</div>
<!-- pipeline -->
<div class="pipeline" id="pipeline" data-stage="idle">
<div class="pipeline__track" aria-hidden="true"><i id="pipelineFill"></i></div>
<ol class="pipeline__steps">
<li data-step="sending"><span class="dot"></span>Sending</li>
<li data-step="processing"><span class="dot"></span>Processing</li>
<li data-step="speaking"><span class="dot"></span>Playing</li>
<li data-step="completed"><span class="dot"></span>Completed</li>
</ol>
</div>
<!-- live status -->
<div class="live" id="live" data-tone="idle" role="status" aria-live="polite">
<span class="live__wave" id="liveWave" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i></span>
<span class="live__text" id="liveText">Ready</span>
<span class="live__detail" id="liveDetail"></span>
</div>
</section>
<!-- ---------- sidebar ---------- -->
<aside class="sidebar">
<section class="panel panel--status" aria-label="Robot status">
<div class="panel__head"><h2>Robot</h2></div>
<dl class="facts">
<div class="fact"><dt>State</dt><dd id="factState"></dd></div>
<div class="fact"><dt>Mode</dt><dd id="factMode"></dd></div>
<div class="fact"><dt>Link</dt><dd id="factTransport"></dd></div>
<div class="fact"><dt>Address</dt><dd id="factAddress" class="mono"></dd></div>
<div class="fact"><dt>Latency</dt><dd id="factLatency"></dd></div>
<div class="fact"><dt>Uptime</dt><dd id="factUptime"></dd></div>
</dl>
<p class="panel__note" id="statusNote" hidden></p>
</section>
<section class="panel panel--audio" aria-label="Saved audio">
<div class="panel__head">
<h2>Saved audio <span class="count" id="audioCount">0</span></h2>
<button class="link-btn" id="clearAudioBtn">Clear</button>
</div>
<p class="panel__note" id="audioNote">
Every line spoken with the neural voice is saved as a .wav file, so it
replays instantly with no synthesis and no internet.
</p>
<ul class="audio-list" id="audioList"></ul>
</section>
<section class="panel panel--history" aria-label="Speech history">
<div class="panel__head">
<h2>History <span class="count" id="historyCount">0</span></h2>
<button class="link-btn" id="clearHistoryBtn">Clear</button>
</div>
<ul class="history" id="historyList"></ul>
<p class="empty" id="historyEmpty">Nothing spoken yet. Your recent utterances appear here — click one to reuse it.</p>
</section>
</aside>
</main>
<div class="toasts" id="toasts" aria-live="assertive"></div>
<script type="module" src="/js/app.js"></script>
</body>
</html>