Daily Tech Briefing
AI 科技速览
每天 5 分钟内学习 AI。获取最新的人工智能新闻,理解其重要性,并学习如何将其应用于您的工作。
Dev.to AI · 2026/8/4 03:24:26
Why Browser-Based Multilingual TTS Kept Freezing at 86% — and How We Fixed It
AI 中文解读
【Why Browser-Based Multilingual TTS Kept Freezing at 86% — and How We Fixed It】Running text-to-speech entirely in the browser sounds simple: download an ONNX model, create an inference session, and synthesize audio without sending user text or media to a server.
In production, ...
<p>Running text-to-speech entirely in the browser sounds simple: download an ONNX model, create an inference session, and synthesize audio without sending user text or media to a server.</p>
<p>In production, it is much harder.</p>
<p>While building multilingual voice generation for <a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer">Timeline Studio</a>, we repeatedly saw the same failure: the model-loading UI stopped at <strong>86%</strong>, the Generate button stayed busy, and switching from Chinese to English, German, Korean, Thai, or Japanese made the issue more likely.</p>
<p>The most useful console message was:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>Unable to cache file QuotaExceededError: Quota exceeded.
QuotaExceededError:
The operation failed because it would cause the application
to exceed its storage quota.
</code></pre>
</div>
<p>The progress bar was only the symptom. The real problem was the interaction between large model files, multiple TTS runtimes, browser storage quotas, service-worker caching, WebGPU initialization, and region-specific model mirrors.</p>
<p>This post explains the architecture changes that made the multilingual pipeline reliable.</p>
<ul>
<li>
<strong>Project:</strong> <a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer">https://github.com/MartinDelophy/ai-video-editor</a>
</li>
<li>
<strong>Live demo:</strong> <a href="https://video-editor.ai-creator.top/" rel="noopener noreferrer">https://video-editor.ai-creator.top/</a>
</li>
</ul>
<h2>
The browser was doing more than the progress bar showed
</h2>
<p>A browser TTS model normally goes through several stages:</p>
<ol>
<li>Download configuration, phonemizer, tokenizer, and vocabulary files.</li>
<li>Download one or more ONNX model files.</li>
<li>Store artifacts in Cache Storage.</li>
<li>Create an ONNX Runtime session.</li>
<li>Compile the graph for WebGPU or initialize WASM.</li>
<li>Run a warm-up inference.</li>
<li>Finally synthesize the requested speech.</li>
</ol>
<p>Our original progress calculation mainly represented network downloads. If the files finished downloading but cache insertion or session creation failed, the UI retained the last reported value — often 86%.</p>
<p>So the browser was not necessarily still downloading anything. It had already moved into an unrepresented stage and thrown an exception before the state machine could reach either success or a useful error state.</p>
<p>The fix started by treating model setup as a real multi-stage operation:</p>
<ul>
<li>Checking local model cache</li>
<li>Downloading model artifacts</li>
<li>Initializing the local inference engine</li>
<li>Preparing the selected voice</li>
<li>Generating speech</li>
</ul>
<p>During initialization, the UI now says what is actually happening instead of pretending another file is still downloading.</p>
<h2>
One origin, many competing caches
</h2>
<p>Timeline Studio supports several browser-local voice runtimes because one model family is not the best choice for every language:</p>
<div class="table-wrapper-paragraph"><table>
<thead>
<tr>
<th>Language group</th>
<th>Runtime</th>
<th>Execution path</th>
</tr>
</thead>
<tbody>
<tr>
<td>Chinese</td>
<td>Piper</td>
<td>WebGPU first, WASM fallback</td>
</tr>
<tr>
<td>English</td>
<td>Kokoro Q8</td>
<td>WASM</td>
</tr>
<tr>
<td>Selected European languages</td>
<td>Piper</td>
<td>WASM</td>
</tr>
<tr>
<td>Korean, Thai, Vietnamese, Russian</td>
<td>MMS</td>
<td>WASM</td>
</tr>
<tr>
<td>Japanese</td>
<td>Supertonic</td>
<td>WASM</td>
</tr>
</tbody>
</table></div>
<p>All of these runtimes operate under the same browser origin. Cache Storage, IndexedDB, and service-worker caches therefore compete for the same site quota.</p>
<p>After a user tried several voices, the origin could contain:</p>
<ul>
<li>Current model files</li>
<li>Older model revisions</li>
<l
分享
阅读原文 ↗