Spaces:
Running
Running
Download index.html from Luigi/PrimeTTS-Streaming: direct link, hf CLI and curl.
- Browser
- Download file 6.54 kB
-
https://huggingface.co/spaces/Luigi/PrimeTTS-Streaming/resolve/main/index.html
- Command line
-
hf download hf://spaces/Luigi/PrimeTTS-Streaming/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Luigi/PrimeTTS-Streaming/resolve/main/index.html
6.54 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>PrimeTTS · real-time streaming (WASM)</title> | |
| <style> | |
| :root { --bg:#0e1116; --card:#171c26; --fg:#e6edf3; --mut:#8b98a9; --acc:#5eead4; --acc2:#38bdf8; } | |
| * { box-sizing:border-box; } | |
| body { margin:0; font:15px/1.5 -apple-system,Segoe UI,Roboto,sans-serif; background:var(--bg); color:var(--fg); } | |
| .wrap { max-width:720px; margin:0 auto; padding:32px 20px 64px; } | |
| h1 { font-size:22px; margin:0 0 4px; } | |
| .sub { color:var(--mut); margin:0 0 24px; font-size:13px; } | |
| .badge { display:inline-block; padding:2px 8px; border-radius:999px; background:#0b2b28; color:var(--acc); font-size:11px; font-weight:600; } | |
| .card { background:var(--card); border:1px solid #232a36; border-radius:14px; padding:18px; } | |
| textarea { width:100%; min-height:96px; resize:vertical; background:#0b0f16; color:var(--fg); border:1px solid #2a3342; border-radius:10px; padding:12px; font-size:15px; } | |
| .row { display:flex; gap:12px; align-items:center; margin-top:14px; flex-wrap:wrap; } | |
| button { background:linear-gradient(135deg,var(--acc),var(--acc2)); color:#04121a; border:0; font-weight:700; padding:11px 22px; border-radius:10px; cursor:pointer; font-size:15px; } | |
| button:disabled { opacity:.5; cursor:default; } | |
| .stat { font-variant-numeric:tabular-nums; color:var(--mut); font-size:13px; } | |
| .stat b { color:var(--fg); } | |
| .meter { height:6px; background:#0b0f16; border-radius:6px; overflow:hidden; margin-top:16px; } | |
| .meter > i { display:block; height:100%; width:0; background:linear-gradient(90deg,var(--acc),var(--acc2)); transition:width .1s; } | |
| .chips { margin-top:12px; display:flex; gap:8px; flex-wrap:wrap; } | |
| .chip { font-size:12px; color:var(--mut); border:1px solid #2a3342; padding:4px 10px; border-radius:999px; cursor:pointer; } | |
| .chip:hover { color:var(--fg); border-color:var(--acc); } | |
| label.opt { color:var(--mut); font-size:13px; display:flex; align-items:center; gap:6px; } | |
| .sectitle { font-size:12px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--mut); margin:30px 0 12px; } | |
| .grid2 { display:grid; grid-template-columns:1fr 1fr; gap:16px; } | |
| @media (max-width:560px){ .grid2 { grid-template-columns:1fr; } } | |
| .subcard { background:var(--card); border:1px solid #232a36; border-radius:14px; padding:16px; display:flex; flex-direction:column; } | |
| .subcard h3 { font-size:15px; margin:0 0 4px; display:flex; align-items:center; gap:6px; } | |
| .subcard .tag { font-size:11px; color:var(--mut); font-weight:400; } | |
| .subcard p { color:var(--mut); font-size:12.5px; margin:0 0 14px; flex:1; } | |
| .subcard button { width:100%; } | |
| #transcript:empty { display:none; } | |
| #loading { position:fixed; inset:0; background:#0b0f16; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; z-index:50; transition:opacity .3s; } | |
| #loading.done { opacity:0; pointer-events:none; } | |
| #loadlabel { color:var(--mut); font-size:13px; } | |
| #loadbarwrap { width:280px; height:6px; background:#171c26; border-radius:6px; overflow:hidden; } | |
| #loadbar { height:100%; width:0; background:linear-gradient(90deg,var(--acc),var(--acc2)); transition:width .2s; } | |
| #loadnote { color:var(--mut); font-size:11px; max-width:280px; text-align:center; } | |
| </style> | |
| <script type="module" crossorigin src="./assets/index-fhMCuR15.js"></script> | |
| </head> | |
| <body> | |
| <div id="loading"> | |
| <div style="font-size:18px;font-weight:700;">PrimeTTS · loading models…</div> | |
| <div id="loadbarwrap"><div id="loadbar"></div></div> | |
| <div id="loadlabel">Starting…</div> | |
| <div id="loadnote">First load fetches ~600MB of ONNX/GGUF models (cached after that). Runs 100% in your browser — no server.</div> | |
| </div> | |
| <div class="wrap"> | |
| <h1>PrimeTTS · real-time streaming <span class="badge" id="backend">…</span></h1> | |
| <p class="sub">Token-level MB-iSTFT-VITS · audio streams chunk-by-chunk (24 frames ≈ 384 ms) — first sound in ~100 ms. zh-TW + English. Runs entirely client-side (WASM).</p> | |
| <div class="sectitle">① Type & speak</div> | |
| <div class="card"> | |
| <textarea id="text" placeholder="輸入中文或 English…">您好,幫您轉接給 Jason 王經理,他的分機是 2580。</textarea> | |
| <div class="chips" id="chips"></div> | |
| <div class="row"> | |
| <button id="go" disabled>▶ Speak (stream)</button> | |
| <label class="opt">voice | |
| <select id="voice" style="background:#0b0f16;color:var(--fg);border:1px solid #2a3342;border-radius:8px;padding:5px 8px;font-size:13px;"></select> | |
| </label> | |
| <label class="opt"><input type="checkbox" id="onenter" checked> stream on Enter</label> | |
| <span class="stat">first-audio <b id="first">–</b> · chunks <b id="nc">0</b> · <b id="audio">0.0s</b></span> | |
| <a id="dl" download="primetts.wav" style="display:none;color:var(--acc);font-size:13px;text-decoration:none;border:1px solid #2a3342;border-radius:8px;padding:5px 10px;">⬇ WAV</a> | |
| </div> | |
| <div class="meter"><i id="bar"></i></div> | |
| </div> | |
| <div id="chatcard" style="display:none;"> | |
| <div class="sectitle">② Streaming input · text is generated live, then spoken (zh-TW)</div> | |
| <div class="grid2"> | |
| <div class="subcard" id="storyopt" style="display:none;"> | |
| <h3>📖 Story generator <span class="tag">llama2.c-zh 15M</span></h3> | |
| <p>No input needed — generates a fresh short tale and speaks it as it writes.</p> | |
| <button id="storygo">▶ Generate story</button> | |
| </div> | |
| <div class="subcard" id="chatopt" style="display:none;"> | |
| <h3>💬 Real-time chat <span class="tag">Gemma-3-270m-it</span></h3> | |
| <p>Ask anything — it replies in zh-TW as it generates, spoken clause-by-clause.</p> | |
| <textarea id="prompt" style="min-height:52px; margin-bottom:10px;" placeholder="輸入訊息…">請用一百字介紹台灣</textarea> | |
| <button id="chatgo">▶ Send</button> | |
| </div> | |
| </div> | |
| <div class="row"><span class="stat">first-audio <b id="cfirst">–</b> · <b id="caudio">0.0s</b></span> | |
| <a id="cdl" download="primetts.wav" style="display:none;color:var(--acc);font-size:13px;text-decoration:none;border:1px solid #2a3342;border-radius:8px;padding:5px 10px;">⬇ WAV</a> | |
| </div> | |
| <div id="transcript" style="margin-top:12px; padding:14px; background:var(--card); border:1px solid #232a36; border-radius:12px; color:#cdd9e5; font-size:15px; line-height:1.8;"></div> | |
| </div> | |
| </div> | |
| </body> | |
| </html> | |