astra-local-voice/web/index.html
Jeuner 991f0d1eb5 feat: add voice picker UI and optional Tailnet exposure
Stimmen werden jetzt lazy pro Name geladen und gecacht statt einer
fest verdrahteten Default-Stimme; das UI bekommt ein Dropdown mit
allen 26 deutschen Pocket-TTS-Stimmen (/api/voices), Auswahl wird im
Browser gemerkt und ist während eines laufenden Gesprächs gesperrt.

Zusätzlich ein optionaler ASTRA_TAILNET_HOST, damit die App über
`tailscale serve` auch von einem anderen Gerät im selben Tailnet
erreichbar ist, ohne die Loopback-only-Härtung für alle anderen
Hosts aufzuweichen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVgSHNHdRx3UNTBodFmhRA
2026-09-07 15:15:13 +02:00

35 lines
2.5 KiB
HTML

<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#111820">
<title>Astra · Dein lokaler Sprachraum</title>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
<link rel="stylesheet" href="/static/style.css">
<script src="/static/app.js" defer></script>
</head>
<body>
<main>
<header><a class="brand" href="/" aria-label="Astra Startseite"><span class="star"></span> astra</a><span class="local"><i></i> Nur auf deinem Mac</span></header>
<section class="conversation" aria-labelledby="title">
<div class="intro"><p class="eyebrow">DEIN LOKALER SPRACHRAUM</p><h1 id="title">Einfach aussprechen.</h1><p class="description">Gedanken sortieren. Fragen stellen. Gemeinsam weiterdenken.</p></div>
<div class="orb-wrap" aria-hidden="true"><div class="orbit"></div><div class="orb"><div class="wave"><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div></div></div>
<div class="live-status"><span id="state-dot"></span><p id="status" role="status" aria-live="polite">Modelle werden vorbereitet …</p></div>
<p id="partial" class="partial" aria-live="off"></p>
<p id="error" class="error" role="alert" hidden></p>
<div class="voice-picker">
<label for="voice">Stimme</label>
<select id="voice" disabled></select>
</div>
<div class="controls"><button id="connect" class="primary" disabled><span aria-hidden="true"></span> Gespräch starten</button><button id="mute" class="secondary" hidden aria-pressed="false">Mikrofon pausieren</button></div>
<p class="hint" id="hint">Mikrofon wird erst nach dem Start freigegeben.</p>
</section>
<section class="transcript" aria-labelledby="transcript-title">
<div class="section-top"><h2 id="transcript-title">Unser Gespräch</h2><button id="clear" class="text-button">Verlauf leeren</button></div>
<div id="messages" role="log" aria-live="polite" aria-relevant="additions"><p class="empty">Hier erscheinen deine Worte und Astras Antworten.<br>Der Verlauf bleibt nur für dieses Gespräch im Speicher.</p></div>
</section>
<footer><span>Deutsch <b>·</b> Lokale Spracherkennung & Stimme</span><span id="latency">Bereit für deine Gedanken</span><span class="credits"><a href="https://github.com/Jeuners/astra-local-voice" target="_blank" rel="noopener">GitHub</a><b>·</b><a href="https://www.dillenberg.net" target="_blank" rel="noopener">H.G.O.D. Dillenberg.net</a></span></footer>
</main>
</body>
</html>