Files
captionninja/capture-local.html

115 lines
9.3 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"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Caption Capture</title><link rel="icon" type="image/svg+xml" href="./caption-local/favicon.svg"><link rel="stylesheet" href="./caption-local/theme.css"><link rel="stylesheet" href="./caption-local/capture.css"></head><body>
<a class="skip-link" href="#captureControls">Skip to caption controls</a>
<nav class="cc-room-menu" data-current="capture" aria-label="Caption room workflow" hidden></nav>
<header><h1>Caption Capture</h1>
<p>Speech is processed by your Caption Local service. Choose your audio input, start captions, then Stop and download your transcript.</p></header>
<main>
<details class="panel" id="serviceConnection" open>
<summary id="connectionTitle">1. Connect your service</summary>
<form id="connection">
<div class="fields">
<label>Service address<input id="endpoint" type="url" required aria-describedby="connectionHelp" value="http://localhost:8765"></label>
</div>
<p id="connectionHelp" class="hint">This page connects automatically to the instance serving it. Use the advanced options below if Caption Capture runs on another computer.</p>
<div class="actions"><button id="connect" type="submit">Connect and check service</button></div>
<p id="connectionError" role="alert"></p>
</form>
</details>
<p class="cc-status-row" id="capabilitiesRow"><span id="serviceDot" class="cc-dot" data-state="warn" aria-label="Checking service"></span><span id="capabilities" role="status">Checking speech service…</span></p>
<section class="panel" aria-labelledby="audioTitle">
<h2 id="audioTitle">2. Choose your audio and output</h2>
<div class="fields">
<label>Microphone<select id="microphone"><option value="">System default</option></select></label>
<label>Spoken language<select id="language"><option value="en" selected>English</option><option value="auto">Detect automatically</option></select></label>
<label>Microphone sensitivity<select id="sensitivity"><option value="0.0008">Quiet speech</option><option value="0.002" selected>Normal</option><option value="0.006">Noisy room</option></select></label>
<label>Caption interval<select id="captionInterval"><option value="3">3 seconds — earlier</option><option value="6" selected>6 seconds — balanced</option><option value="9">9 seconds — more context</option></select></label>
<label>Local preview<select id="mode"><option value="transcribe">Spoken-language captions</option><option value="translate">English translation</option><option value="both">Original + English</option></select></label>
</div>
<p class="hint" id="outputHint">Start with six-second captions. Select the spoken language explicitly for the most reliable translation.</p>
</section>
<section class="panel" id="captureControls" aria-labelledby="captionsTitle" tabindex="-1">
<h2 id="captionsTitle">3. Capture and save</h2>
<div class="actions">
<button id="start" disabled>Start captions</button> <button id="stop" disabled>Stop</button>
<button id="retry" hidden>Retry pending audio</button> <button id="discard" hidden>Discard pending audio</button>
</div>
<p class="cc-status-row"><span id="captureDot" class="cc-dot" data-state="idle" aria-label="Capture not started"></span><span id="status" role="status">Ready</span></p><p id="error" role="alert"></p>
<label>Microphone level<meter id="meter" min="0" max="0.1" value="0"></meter></label>
<div id="captions" role="log" aria-live="polite" aria-label="Live captions"></div>
<button id="download">Download transcript</button>
<p class="hint">Stop and let pending audio finish before downloading. Audio is not saved; closing the tab can lose pending audio and unsaved text.</p>
</section>
<section class="panel" id="captureSettings" aria-labelledby="captureSettingsTitle">
<h2 id="captureSettingsTitle">4. Capture settings</h2>
<div class="fields">
<div class="setting"><span class="field-label">Save current settings</span><button id="saveSettings" type="button">Save capture settings</button></div>
<div class="setting"><label for="loadSettings">Load saved settings</label><input id="loadSettings" type="file" accept="application/json,.json"></div>
</div>
<p class="hint">Save or import local preferences. Tokens, microphone identifiers, room names and sharing are excluded. Connect first, then load settings for that service.</p>
</section>
<details class="panel" id="advancedOptions">
<summary>Advanced options</summary>
<p class="hint">Relay sharing, self-hosting, remote setup and diagnostics.</p>
<div class="advanced-body">
<details><summary>Send captions to captions.coop</summary>
<p>Optional: caption text travels through the room’s private relay. Audio stays on the inference host. The editor reviews captions before publishing them to the audience room.</p>
<label>Audience output<select id="relayOutput"><option value="transcript">Original transcription</option><option value="translation">English translation</option></select></label>
<label>Destination workflow<select id="relayTarget"><option value="editor">Human editor (private source room)</option><option value="overlay">Direct overlay (publishes without review)</option></select></label>
<p>For a direct overlay, use its room instead. Anyone with that room link can see the shared text; direct captions skip human review.</p>
<details><summary>Use a private relay</summary>
<label>Relay address<input id="relayAddress" type="url" value="" placeholder="wss://relay.example.org" spellcheck="false"></label>
<label>Caption website address<input id="captionSite" type="url" value="" placeholder="https://captions.example.org/" spellcheck="false"></label>
<label>Room publishing token<input id="relayToken" type="password" autocomplete="off" spellcheck="false"></label>
<label>Editor output room<input id="reviewRoom" value="output" autocomplete="off" maxlength="128"></label>
<p>A private relay needs its own room token, separate from the room admin link. The editor needs the source viewing token and output publishing token. Links carry the relay address, never tokens. Turn sharing off before changing these settings.</p>
</details>
<label>Source room<input id="room" value="source" autocomplete="off" maxlength="128"></label>
<label><input id="share" type="checkbox"> Send caption text to captions.coop</label>
<p class="cc-status-row"><span id="relayDot" class="cc-dot" data-state="idle" aria-label="Sharing off"></span><span id="relay" role="status">Sharing off</span></p>
<p id="overlayReady" hidden>Direct monitor: <a id="overlayLink" target="_blank" rel="noopener noreferrer">Open source overlay</a> (bypasses review; carries the viewing token in the link fragment).</p>
</details>
<details id="selfHostHelp">
<summary>Using your own self-hosted instance</summary>
<p>This page connects to the instance that serves it. To use a different self-hosted instance, open its own capture page. Credentials are never sent to another origin.</p>
<label>Self-hosted origin<input id="selfHostOrigin" type="url" placeholder="https://captions.example.org" spellcheck="false"></label>
<div class="actions"><button id="openSelfHost" type="button">Open self-hosted capture page</button></div>
<p id="selfHostError" role="alert"></p>
</details>
<details><summary>Connection and capture diagnostics</summary>
<dl class="diagnostics-grid" id="diagnostics">
<div class="diagnostic"><dt>Model</dt><dd id="diagModel">—</dd></div>
<div class="diagnostic"><dt>Device</dt><dd id="diagDevice">—</dd></div>
<div class="diagnostic"><dt>Precision</dt><dd id="diagPrecision">—</dd></div>
<div class="diagnostic"><dt>Processing now</dt><dd id="diagRunning">—</dd></div>
<div class="diagnostic"><dt>Waiting</dt><dd id="diagPending">—</dd></div>
<div class="diagnostic"><dt>Version</dt><dd id="diagVersion">—</dd></div>
<div class="diagnostic"><dt>Buffered audio</dt><dd id="diagBuffered">—</dd></div>
<div class="diagnostic"><dt>Pending audio</dt><dd id="diagAudioPending">—</dd></div>
<div class="diagnostic"><dt>Failed audio</dt><dd id="diagAudioFailed">—</dd></div>
<div class="diagnostic"><dt>Recent requests</dt><dd id="diagRequests">—</dd></div>
<div class="diagnostic"><dt>Last response</dt><dd id="diagLastResponse">—</dd></div>
<div class="diagnostic"><dt>Server processing</dt><dd id="diagServerTime">—</dd></div>
<div class="diagnostic"><dt>Network + upload</dt><dd id="diagNetwork">—</dd></div>
<div class="diagnostic"><dt>Requested language</dt><dd id="diagRequestedLanguage">—</dd></div>
<div class="diagnostic"><dt>Detected language</dt><dd id="diagDetectedLanguage">—</dd></div>
<div class="diagnostic"><dt>Audience output</dt><dd id="diagAudienceOutput">—</dd></div>
</dl>
<p>Response duration includes network, queue and inference time; it is not speech-to-caption delay. The last 100 requests are retained in memory. Downloads exclude tokens, service addresses, room names, audio and captions.</p>
<button id="downloadDiagnostics">Download diagnostics</button>
</details>
</div>
</details>
</main>
<script src="./caption-local/caption-status.js"></script><script src="./caption-local/caption-room-menu.js"></script><script src="./caption-local/relay-config.js"></script><script src="./caption-local/private-relay-client.js"></script><script src="./caption-local/ws-publisher.js"></script><script src="./caption-local/audio-buffer.js"></script><script src="./caption-local/local-connection.js"></script><script src="./caption-local/app.js"></script><script src="./caption-local/local-page.js"></script>
</body></html>