← Files CastReaderARCHIVED FILE

assets/voice-app/ui/index.html

4.32 KB · Oct 4, 2026 · 12:34 UTC

↓ Download file

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="color-scheme" content="light">
  <title>Flashcards · CastReader Voice API</title>
  <link rel="stylesheet" href="/style.css">
  <script type="module" src="/app.js"></script>
</head>
<body>
  <header><a class="brand" href="/">CastReader <span>/ Flashcards</span></a><div class="header-tools"><span class="local">LOCAL APP · 127.0.0.1</span><select id="ui-language" aria-label="Interface language"><option value="en">English</option><option value="zh-CN">中文</option></select></div></header>
  <main>
    <div class="intro"><p class="eyebrow">MULTILINGUAL AUDIO WORKSHOP</p><h1>Write it. Hear it. Keep it.</h1><p>Turn your short phrases into a reusable set of MP3s. Each card keeps its own text and language.</p></div>
    <p id="notice" role="status" aria-live="polite">Opening your local workspace…</p>
    <section class="panel connection" aria-labelledby="connection-title">
      <div><h2 id="connection-title">1. Connect your voice</h2><p id="connection-status">The API key stays in the Node.js server environment.</p></div>
      <button id="connect" type="button">Load ready voices</button>
      <label class="voice-field">Authorized voice<select id="voice" disabled><option value="">Load voices to choose</option></select></label>
      <p id="voice-note" class="hint">Voice discovery and planning do not generate audio.</p>
    </section>
    <div class="workspace">
      <section class="panel editor" aria-labelledby="editor-title">
        <div class="section-head"><div><h2 id="editor-title">2. Make a batch</h2><p>Up to 200 cards · 500 normalized characters per card</p></div><button id="add" class="secondary" type="button">+ Add card</button></div>
        <label>Batch title<input id="title" maxlength="80" value="Everyday phrases" autocomplete="off"></label>
        <p class="hint">Supply the translation yourself and choose its matching language. Editing a saved batch requires a new plan.</p>
        <div id="cards" class="card-list"></div>
        <div class="editor-footer"><span id="count" class="hint"></span><button id="plan" type="button" disabled>Save plan &amp; estimate</button></div>
      </section>
      <aside>
        <section class="panel" aria-labelledby="run-title">
          <h2 id="run-title">3. Review &amp; generate</h2>
          <div id="plan-summary"><p>Save a plan to see its cost and freeze the inputs before generating.</p></div>
          <label class="confirm"><input id="confirm" type="checkbox" disabled><span>I approve normal usage charges for this saved batch. Resume may submit its not-yet-started cards.</span></label>
          <button id="start" type="button" disabled>Generate saved batch</button>
          <p class="hint">Cards run one at a time. Keep the server running; closing this tab does not cancel the batch.</p>
        </section>
        <section class="panel" aria-labelledby="history-title">
          <div class="section-head"><h2 id="history-title">Saved batches</h2><button id="refresh" class="secondary small" type="button">Refresh</button></div>
          <label>Open an original batch<select id="history"><option value="">Choose a saved batch</option></select></label>
          <p id="history-warning" class="hint" role="status" hidden></p>
          <p class="hint">After a restart, open the same batch to recover its original jobs. A failed or expired job is never replaced automatically.</p>
        </section>
      </aside>
    </div>
    <section class="panel results" aria-labelledby="results-title">
      <div class="section-head"><div><h2 id="results-title">Your audio</h2><p id="progress-label">No batch selected.</p></div><div class="actions"><button id="manifest" class="secondary" type="button" disabled>Manifest</button><button id="archive" type="button" disabled>Download all · ZIP</button></div></div>
      <progress id="progress" max="1" value="0" aria-label="Saved clips"></progress>
      <p id="run-error" role="status" class="hint"></p>
      <div id="results"><p class="empty">Saved clips will appear here. Replay and download use your local files without generating again.</p></div>
    </section>
    <footer>CastReader Voice API example · Keys and recovery checkpoints stay on this computer. No account recharge controls.</footer>
  </main>
</body>
</html>

SHA-256: 09051121369b10021a8ca1818faf2b96b24c287196f77d63c387881b228547f9