bol-tts-marathi / index.template.html
shreyask's picture
metrics: TTFB (time to first audio) replaces total-synth in headline metric
aed4de5 verified
Raw
History Blame Contribute Delete
10.1 kB
<!doctype html>
<html lang="mr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="icon"
type="image/svg+xml"
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Ctext y='48' font-size='48'%3E%F0%9F%AA%94%3C/text%3E%3C/svg%3E"
/>
<title>बोल — Marathi TTS · WebGPU</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Tiro+Devanagari+Marathi&family=Yatra+One&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="/src/styles.css" />
</head>
<body>
<!-- Warli tribal art strip: dancers, hut, deer, microphones, sun motifs.
Custom-illustrated band in the style of traditional Warli wall paintings
from Maharashtra. Microphones are a contemporary addition reflecting
the TTS theme. -->
<div class="warli-strip" aria-hidden="true">
<img src="/warli-strip.svg" alt="" />
</div>
<main>
<header>
<h1>बोल</h1>
<span class="namaste">Marathi Text-to-Speech</span>
<p>
Kokoro-82M fine-tuned for
<a
href="https://en.wikipedia.org/wiki/Marathi_language"
target="_blank"
rel="noopener"
>मराठी</a
>
· runs in your browser via WebGPU
</p>
</header>
<section id="status" class="card status">initializing…</section>
<section class="card model-gate" id="model-gate" hidden>
<div class="model-gate-text">
<strong>Tap to load the TTS model</strong> (~325 MB fp32 ONNX ·
one-time download, browser-cached)<br />
<span class="model-gate-sub">
fp32 is the recommended precision for Kokoro on WebGPU (matches
kokoro.js + HeadTTS defaults; int8 breaks ISTFTNet decoder audio
quality). Plus ~40 MB for onnxruntime-web WASM + espeak-ng worker.
</span>
</div>
<button id="load-model" class="primary">Load model</button>
</section>
<section class="card">
<div class="text-label-row">
<label for="text">मराठी मजकूर — Marathi text (Devanagari)</label>
<button
id="transliterate"
class="text-tool"
title="Transliterate Latin → Devanagari using ITRANS scheme. e.g. 'namaskaar majhe naav amit aahe' → 'नमस्कार माझे नाव अमित आहे'. Edit the result before synthesizing if needed."
type="button"
>
A·a → अ
</button>
</div>
<textarea id="text" rows="3">
पावसाच्या संध्याकाळी शनिवारवाड्याजवळ गरम कटिंग चहा घेत मी मित्रांना म्हणालो, “आज आकाशातला प्रत्येक ढग एखादी नवी गोष्ट सांगतोय.”</textarea
>
<!-- chips populated dynamically from public/voicepacks.json (test_phrases.*) -->
<div class="examples" id="chips-marathi">
<span class="examples-label">मराठी:</span>
</div>
<div class="examples" id="chips-minglish">
<span class="examples-label">Minglish:</span>
</div>
<div class="controls">
<label class="voice-control">
<span class="voice-control-row">
<span>आवाज · Voice</span>
<a
id="voice-ref-dl"
class="voice-ref-link"
download
title="Download a reference clip from the training data — hear the actual speaker for this voice."
>🎧 Reference clip</a
>
</span>
<!-- options populated dynamically from public/voicepacks.json (voices[]) -->
<select id="voice"></select>
</label>
<label class="speed-control">
<span class="speed-control-row">
<span>गती · Speed</span>
<span id="speed-val">1.00×</span>
</span>
<input
id="speed"
type="range"
min="0.5"
max="1.5"
step="0.05"
value="1.0"
/>
</label>
<button id="synth" class="primary">Synthesize</button>
</div>
</section>
<section class="card" id="output-section" hidden>
<audio id="audio" hidden></audio>
<div class="player">
<button
id="playpause"
class="playpause"
title="Play / Pause (space)"
aria-label="Play / Pause"
>
</button>
<div class="player-main">
<canvas
id="waveform"
class="waveform"
tabindex="0"
aria-label="Click to seek"
></canvas>
<div class="player-time">
<span id="time-cur">0:00</span>
<span id="time-total">0:00</span>
</div>
</div>
<a
id="audio-dl"
class="audio-dl-btn"
title="Download synthesized audio as WAV"
aria-label="Download WAV"
download="bol-tts-output.wav"
>
</a>
</div>
<!-- Primary transcript: each word highlighted as audio plays.
Click a word to seek there. Expand the summary below for IPA + timing. -->
<div
class="transcript-compact"
id="transcript-compact"
title="Click any word to seek playback to it"
></div>
<details class="transcript-details" id="transcript-details">
<summary>Per-word IPA + timing</summary>
<div class="sidebyside" id="transcript">
<div
class="col-head"
title="Devanagari script — Marathi text as written. Each row is one word from your input."
>
देवनागरी
</div>
<div
class="col-head"
title="International Phonetic Alphabet — how each word is pronounced. These are the phonemes fed to the model (via the espeak-ng WASM worker running in your browser)."
>
IPA
</div>
<div
class="col-head"
title="Start and end time of each word in the synthesized audio, predicted by Kokoro's prosody model (pred_dur). The bar fills progressively as the word is playing."
>
timing
</div>
<!-- rows injected by main.ts -->
</div>
</details>
<aside class="facts">
🪔 <strong>मराठी phoneme fact:</strong> Marathi's retroflex lateral
<span class="ipa-inline">ɭ</span> (ळ) is unusual among Indic languages
— Hindi doesn't have it. We added <span class="ipa-inline">ɭ</span> to
Kokoro's vocabulary at slot 144 (replacing an unused placeholder) so
the model could learn ळ cleanly during fine-tuning. Listen for it in
"केळी" (banana) or "सकाळ" (morning).
</aside>
<details class="details">
<summary>All phonemes + raw timings (debug)</summary>
<pre id="phonemes" class="phonemes"></pre>
<pre id="word-timings" class="word-timings"></pre>
</details>
</section>
<section class="card metrics-card" id="metrics-card" hidden>
<div class="metrics-header">Performance</div>
<div class="metrics-grid">
<div class="metric">
<div class="metric-label">Time to First Audio</div>
<div class="metric-value">
<span id="m-ttfb">--</span><span class="metric-unit">ms</span>
</div>
<div class="metric-context">total synth: <span id="m-synth">--</span> ms</div>
</div>
<div class="metric metric-highlight">
<div class="metric-label">Real-Time Factor</div>
<div class="metric-value">
<span id="m-rtf">--</span><span class="metric-unit">×</span>
</div>
<div class="metric-context">&gt;1× = faster than real-time</div>
</div>
<div class="metric">
<div class="metric-label">Tokens / sec</div>
<div class="metric-value">
<span id="m-tps">--</span>
</div>
<div class="metric-context"><span id="m-tokens">0</span> tokens · <span id="m-frames">0</span> frames</div>
</div>
</div>
</section>
<footer>
<p>
Model
<a
href="https://huggingface.co/shreyask/bol-tts-marathi-onnx"
target="_blank"
rel="noopener"
>shreyask/bol-tts-marathi-onnx</a
>
· recipe
<a
href="https://github.com/shreyaskarnik/bol-tts-marathi"
target="_blank"
rel="noopener"
>github.com/shreyaskarnik/bol-tts-marathi</a
>
· built on
<a
href="https://github.com/hexgrad/kokoro"
target="_blank"
rel="noopener"
>Kokoro-82M</a
>
via
<a
href="https://github.com/semidark/kokoro-deutsch"
target="_blank"
rel="noopener"
>kokoro-deutsch</a
>
</p>
</footer>
</main>
<div class="warli-strip warli-strip--bottom" aria-hidden="true">
<img src="/warli-strip.svg" alt="" />
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>