zerotts 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
zerotts-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ZeroWeight AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
zerotts-0.1.0/NOTICE ADDED
@@ -0,0 +1,36 @@
1
+ ZeroTTS
2
+ Copyright (c) 2026 ZeroWeight AI
3
+ Licensed under the MIT License (see LICENSE).
4
+
5
+ ------------------------------------------------------------------------------
6
+ This product redistributes third-party components.
7
+ ------------------------------------------------------------------------------
8
+
9
+ MOSS-Audio-Tokenizer-Nano
10
+ Copyright the OpenMOSS Team.
11
+ Licensed under the Apache License, Version 2.0.
12
+ Full text: LICENSES/MOSS-Audio-Tokenizer-Apache-2.0.txt
13
+
14
+ The ZeroTTS weights repository (huggingface.co/zeroweight-ai/ZeroTTS) bundles
15
+ the ONNX **decoder** graphs of MOSS-Audio-Tokenizer-Nano under onnx/codec/, so
16
+ that ZeroTTS has no runtime dependency on an external model repository. The
17
+ encoder graphs are not redistributed. The graphs are unmodified except for the
18
+ removal of the encoder entries from the accompanying metadata file.
19
+
20
+ Upstream: https://github.com/OpenMOSS/MOSS-Audio-Tokenizer
21
+ https://huggingface.co/OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX
22
+
23
+ ------------------------------------------------------------------------------
24
+
25
+ soe-vinorm
26
+ Copyright (c) vinhdq842.
27
+ Licensed under the MIT License.
28
+ Full text: src/zerotts/text_norm/data/LICENSE.soe-vinorm
29
+
30
+ src/zerotts/text_norm/vi_normalizer.py adapts soe-vinorm's Vietnamese number,
31
+ date, time, version and fraction expansion rules, and vendors its abbreviation
32
+ table as data/abbreviations.txt. None of soe-vinorm's machinery is carried over
33
+ — that project tags tokens with a CRF and disambiguates acronyms with an ONNX
34
+ scorer, both downloaded at runtime; this module is pure stdlib regex.
35
+
36
+ Upstream: https://github.com/vinhdq842/soe-vinorm
zerotts-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,350 @@
1
+ Metadata-Version: 2.4
2
+ Name: zerotts
3
+ Version: 0.1.0
4
+ Summary: Lightweight Vietnamese Zero-Shot Text-to-Speech (TTS) with real-time streaming and voice cloning.
5
+ Author: ZeroWeight AI
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/zeroweight-ai/ZeroTTS
8
+ Project-URL: Weights, https://huggingface.co/zeroweight-ai/ZeroTTS
9
+ Project-URL: Benchmark, https://huggingface.co/datasets/zeroweight-ai/ZeroBench-TTS
10
+ Keywords: tts,text-to-speech,vietnamese,onnx,speech-synthesis,lightweight,voice clone
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ License-File: NOTICE
20
+ Requires-Dist: numpy>=1.23
21
+ Requires-Dist: onnxruntime>=1.17.0
22
+ Requires-Dist: tokenizers>=0.20.0
23
+ Requires-Dist: huggingface_hub>=0.23.0
24
+ Requires-Dist: soundfile>=0.12.1
25
+ Requires-Dist: scipy>=1.10.0
26
+ Provides-Extra: webui
27
+ Requires-Dist: gradio>=4.44.0; extra == "webui"
28
+ Requires-Dist: fastapi>=0.110; extra == "webui"
29
+ Requires-Dist: uvicorn>=0.27; extra == "webui"
30
+ Requires-Dist: requests>=2.31; extra == "webui"
31
+ Provides-Extra: eval
32
+ Requires-Dist: torch>=2.4.0; extra == "eval"
33
+ Requires-Dist: torchaudio>=2.4.0; extra == "eval"
34
+ Requires-Dist: transformers>=4.44.0; extra == "eval"
35
+ Requires-Dist: huggingface_hub>=0.23; extra == "eval"
36
+ Requires-Dist: datasets>=2.19; extra == "eval"
37
+ Requires-Dist: librosa>=0.10; extra == "eval"
38
+ Requires-Dist: pandas>=2.0; extra == "eval"
39
+ Requires-Dist: jiwer>=3.0; extra == "eval"
40
+ Provides-Extra: dev
41
+ Requires-Dist: pytest>=7.4; extra == "dev"
42
+ Requires-Dist: ruff>=0.5; extra == "dev"
43
+ Dynamic: license-file
44
+
45
+ <div align="center">
46
+
47
+ <img src="docs/assets/banner.png" alt="ZeroTTS — Vietnamese zero-shot text-to-speech" width="100%">
48
+
49
+ # ZeroTTS
50
+
51
+ ### Vietnamese Zero-Shot Text-to-Speech (TTS) with real-time streaming and voice cloning from seconds of audio. Fast, natural, and optimised for CPU inference.
52
+
53
+ [![PyPI](https://img.shields.io/pypi/v/zerotts?color=3775AB)](https://pypi.org/project/zerotts/)
54
+ [![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
55
+ [![ONNX](https://img.shields.io/badge/ONNX-Runtime-005CED?logo=onnx&logoColor=white)](https://onnxruntime.ai/)
56
+ [![HuggingFace](https://img.shields.io/badge/🤗-Weights-yellow)](https://huggingface.co/zeroweight-ai/ZeroTTS)
57
+ [![Benchmark](https://img.shields.io/badge/🤗-ZeroBench--TTS-orange)](https://huggingface.co/datasets/zeroweight-ai/ZeroBench-TTS)
58
+
59
+ </div>
60
+
61
+ **The most accurate open Vietnamese TTS we know of — 4× fewer word errors than
62
+ the next open model**, and it runs faster than real time on a laptop CPU.
63
+
64
+ * 🗣️ **Zero-shot voice cloning** — cloned from as little as 3 seconds of reference
65
+ audio (up to 30 seconds). No fine-tuning, no per-speaker training.
66
+ * ⚡ **Real-time on CPU, streaming** — ~2× faster than real time (RTF 0.5×),
67
+ first audio chunk in ~70 ms. No GPU required.
68
+ * 🇻🇳 **Built for Vietnamese** — tones, code-switched English, and a built-in
69
+ normalizer that reads `31/12/2026` and `ZeroTTS` the way a person would.
70
+
71
+ ## Samples
72
+
73
+ <table>
74
+ <tr>
75
+ <td width="33%" align="center"><b>Two-speaker conversation</b></td>
76
+ <td width="33%" align="center"><b>Long-form narration</b></td>
77
+ <td width="33%" align="center"><b>News read, code-switched English</b></td>
78
+ </tr>
79
+ <tr>
80
+ <td width="33%"><video src="https://github.com/user-attachments/assets/7f97b370-4544-4df7-9165-ffad8a08eb90" controls width="100%"></video></td>
81
+ <td width="33%"><video src="https://github.com/user-attachments/assets/3c80a328-11cc-4815-b3fb-97ca8d994401" controls width="100%"></video></td>
82
+ <td width="33%"><video src="https://github.com/user-attachments/assets/9a5f6125-3ac3-4f09-81f1-986f38e18f69" controls width="100%"></video></td>
83
+ </tr>
84
+ </table>
85
+
86
+ ## Contents
87
+
88
+ 1. [Samples](#samples)
89
+ 2. [Install](#install)
90
+ 3. [Usage](#usage)
91
+ 4. [Voices — and voice cloning](#voices--and-voice-cloning)
92
+ 5. [Benchmarks](#benchmarks)
93
+ 6. [Web UI](#web-ui)
94
+ 7. [Browser demo](#browser-demo)
95
+ 8. [How it works](#how-it-works)
96
+ 9. [Credits](#credits)
97
+
98
+ ---
99
+
100
+ ## Install
101
+
102
+ ```bash
103
+ pip install zerotts
104
+ ```
105
+
106
+ That pulls `numpy`, `onnxruntime`, `tokenizers`, `huggingface_hub`, `soundfile`,
107
+ `scipy` — and nothing else. Weights download from the Hub on first use
108
+ (~900 MB, cached under `HF_HOME`).
109
+
110
+ Optional extras:
111
+
112
+ ```bash
113
+ pip install "zerotts[webui]" # Gradio demo
114
+ pip install "zerotts[eval]" # benchmark scorers — these DO need torch
115
+ ```
116
+
117
+ The `eval` extra is the only thing in this repo that installs PyTorch, and it is
118
+ for *measuring* quality, not for generating audio.
119
+
120
+ ## Usage
121
+
122
+ ## Web UI
123
+
124
+ ```bash
125
+ pip install "zerotts[webui]"
126
+ python webui/app.py # http://localhost:7860
127
+ python webui/app.py --model ./local_dir # a local model directory
128
+ ```
129
+
130
+ Voice picker, streaming playback, long-form segmentation, and the generation
131
+ settings above.
132
+
133
+ ## Browser demo
134
+
135
+ [`js/`](js/) runs the same model client-side with `onnxruntime-web` — no server,
136
+ no upload. See [docs/BROWSER.md](docs/BROWSER.md).
137
+
138
+ Note the download: the weights are **fp32 and not quantized**, so the demo fetches
139
+ ~900 MB once and persists it (OPFS/Cache API). That is a deliberate
140
+ quality-over-size choice; it targets desktop broadband, not mobile data.
141
+
142
+ ### Python
143
+
144
+ ```python
145
+ from zerotts import ZeroTTS
146
+
147
+ tts = ZeroTTS.from_pretrained("zeroweight-ai/ZeroTTS")
148
+
149
+ print(tts.list_voices())
150
+
151
+ # One shot
152
+ audio = tts.synthesize("Hôm nay trời đẹp quá.", voice="maichi")
153
+ tts.save_audio(audio, "out.wav")
154
+
155
+ # Streaming — first chunk arrives in ~70 ms
156
+ import queue
157
+
158
+ import numpy as np
159
+ import sounddevice as sd # pip install sounddevice
160
+
161
+ TEXT = ("Đây là chế độ phát trực tuyến. Âm thanh được tạo ra và phát ngay lập tức, "
162
+ "không cần chờ toàn bộ đoạn văn hoàn thành. Nhờ vậy, người nghe chỉ mất "
163
+ "khoảng 70 mili giây là đã nghe thấy câu đầu tiên, ngay cả khi mô "
164
+ "hình đang chạy trên CPU của một chiếc laptop bình thường.")
165
+
166
+ pending, tail = queue.Queue(), np.zeros(0, dtype="float32")
167
+
168
+ def feed(outdata, frames, _time, _status):
169
+ global tail
170
+ while len(tail) < frames and not pending.empty():
171
+ tail = np.concatenate([tail, pending.get_nowait()])
172
+ n = min(frames, len(tail))
173
+ outdata[:n, 0] = tail[:n]
174
+ outdata[n:] = 0
175
+ tail = tail[n:]
176
+
177
+ with sd.OutputStream(samplerate=tts.sample_rate, channels=1,
178
+ dtype="float32", callback=feed):
179
+ for chunk in tts.synthesize_stream(TEXT, voice="maichi"):
180
+ pending.put(chunk.reshape(-1)) # chunk is (1, n) float32 at 48 kHz
181
+ while not pending.empty() or len(tail):
182
+ sd.sleep(50) # let the buffer drain before closing
183
+ ```
184
+
185
+ Dates, clock times, fractions and acronyms are expanded to spoken Vietnamese
186
+ before synthesis:
187
+
188
+ ```python
189
+ from zerotts import normalize_vi_text
190
+
191
+ normalize_vi_text("Ngày 23/8/2024 lúc 15h30, giá 1.250.000")
192
+ # 'Ngày hai mươi ba tháng tám năm hai nghìn không trăm hai mươi tư lúc
193
+ # mười lăm giờ ba mươi phút, giá một triệu hai trăm năm mươi nghìn'
194
+ ```
195
+
196
+ `synthesize()` does **not** apply it — it is a separate step so you stay in
197
+ control (the expansions are Vietnamese words, so they are wrong for English
198
+ text). The CLI and web UI apply it by default; `zerotts say --no_text_norm`
199
+ turns it off.
200
+
201
+ Long input should be segmented — the model is trained on utterances, not
202
+ paragraphs:
203
+
204
+ ```python
205
+ from zerotts.chunking import chunk_text, clean_segment_punctuation, normalize_punctuation
206
+
207
+ segments = [clean_segment_punctuation(s)
208
+ for s in chunk_text(normalize_punctuation(long_text), max_chunk_sec=15)]
209
+ ```
210
+
211
+ ### Command line
212
+
213
+ ```bash
214
+ zerotts voices
215
+ zerotts say "Xin chào các bạn." --voice maichi -o hello.wav
216
+ zerotts say "$(cat article.txt)" --voice maichi --chunk -o article.wav
217
+ zerotts bench --voice maichi
218
+ ```
219
+
220
+ ### Generation settings
221
+
222
+ | Argument | Default | Effect |
223
+ |---|---|---|
224
+ | `voice` | `None` | Voice pack name. `None` = the model's unconditional voice, which is *not* stable across runs. |
225
+ | `cfg_scale` | `1.0` | `>1` guides toward the voice's identity, at 2× the per-frame cost. |
226
+ | `audio_temperature` | `0.8` | |
227
+ | `audio_topk` / `audio_topp` | `25` / `0.95` | |
228
+ | `audio_repetition_penalty` | `1.2` | Benchmarked default. `1.0` measurably raises WER and leaves more dead air. |
229
+ | `eoa_extra_frames` | `1` | Frames of trailing audio kept after the model signals stop. `0` clips the last phone's release. |
230
+
231
+ Defaults are the exact settings the [benchmark numbers](#benchmarks) were
232
+ produced with, so out-of-the-box output matches the published scores.
233
+
234
+ ## Voices — and voice cloning
235
+
236
+ A voice in ZeroTTS is a small array of speaker latents, shape
237
+ `(1, n_voice_queries, d_model)`. That array is the *entire* speaker
238
+ conditioning — there is no reference transcript, no in-context audio prompt, no
239
+ teacher-forced frames. It ships as a `.npz` inside the weights repo.
240
+
241
+ > ### Voice cloning is not available in this release
242
+ >
243
+ > Those latents are produced by a voice encoder that reads a reference clip, and
244
+ > **the voice encoder is not published**. This package can load voices; it cannot
245
+ > create them from audio. There is no flag that turns this on.
246
+ >
247
+ > To get latents for your own speaker, visit
248
+ > **[zeroweight.ai](https://zeroweight.ai)** or get in touch.
249
+
250
+ The boundary is narrower than it sounds: latents obtained that way are just a
251
+ `.npz`, so they drop into `voices/<name>/voice.npz` and work with no code change.
252
+
253
+ Eight presets ship with the weights, each tagged by gender, age and register so
254
+ you can pick one by ear or by filter — `maichi` (Mai Chi) is the default used
255
+ throughout this README. Full list, tags, and preview clips:
256
+ [docs/VOICES.md](docs/VOICES.md).
257
+
258
+ ```python
259
+ tts.list_voices() # ['maichi', 'baotrang', ...]
260
+ v = tts.load_voice("maichi")
261
+ v.emb.shape # (1, 10, 768)
262
+ v.display_name, v.gender, v.tags # 'Mai Chi', 'nữ', ['nữ', 'trẻ', 'kể chuyện', ...]
263
+
264
+ # A latent array from anywhere works directly
265
+ audio = tts.synthesize("…", voice=my_latents)
266
+ ```
267
+
268
+ ## Benchmarks
269
+
270
+ Measured on **[ZeroBench-TTS](https://huggingface.co/datasets/zeroweight-ai/ZeroBench-TTS)**
271
+
272
+ Every system reads **normalized text** — dates, numbers and acronyms already
273
+ spoken out, from the benchmark's own curated reading.
274
+
275
+ | | **ZeroTTS** | OmniVoice | XTTS-v2-vietnamse | viXTTS |
276
+ |---|:-:|:-:|:-:|:-:|
277
+ | **WER** ↓ | **0.56 %** | 2.12 % | 7.27 % | 8.61 % |
278
+ | **Naturalness** (UTMOS) ↑ | **2.91** | 2.75 | 2.49 | 2.34 |
279
+ | **Voice similarity** (SSIM) ↑ | 0.938 | **0.951** | 0.941 | 0.935 |
280
+ | **Dead air** (excess silence) ↓ | **0.029 s** | 0.386 s | 0.568 s | 0.215 s |
281
+ | **RTF, CPU** ↓ | **0.50×** | 6.12× | 0.71× | 0.73× |
282
+ | **Time to first audio, CPU** ↓ | **~70 ms** | ~34 s | ~6.1 s | ~5.1 s |
283
+ | Size | **202 M** params, 0.86 GB fp32, CPU | 3.1 GB, GPU | 1.9 GB, GPU | 1.9 GB, GPU |
284
+
285
+ **4× fewer word errors than the next-best system**, and the fastest of the four
286
+ on CPU. The gap is much wider in latency than in throughput: the two XTTS
287
+ fine-tunes also beat real time (0.71×) but need seconds to emit their first
288
+ sample, while OmniVoice is 6× *slower* than real time. All three are sized and
289
+ tuned for a GPU, and it shows.
290
+
291
+ Full comparison tables, per-subset breakdowns, and CPU speed methodology:
292
+ **[docs/BENCHMARKS.md](https://github.com/zeroweight-ai/ZeroTTS/blob/main/docs/BENCHMARKS.md)**
293
+
294
+ ### Speed — CPU
295
+
296
+ RTF (realtime factor, wall-clock synthesis time ÷ output audio duration — lower
297
+ is faster; below 1× is faster than real time) and time-to-first-audio, all
298
+ measured **on CPU**, single request, 8 inference threads pinned to a dedicated
299
+ core pool (no other synthesis running concurrently). Three Vietnamese samples —
300
+ short (26 chars), medium (77 chars), long (227 chars) — each run 6 times with
301
+ the first 2 (cold-cache) discarded; figures below are the mean of the
302
+ remaining 4.
303
+
304
+ | | **ZeroTTS** | OmniVoice | XTTS-v2-vietnamse | viXTTS |
305
+ |---|:-:|:-:|:-:|:-:|
306
+ | RTF — short | **0.51×** | 10.87× | 0.70× | 0.71× |
307
+ | RTF — medium | **0.47×** | 4.82× | 0.70× | 0.70× |
308
+ | RTF — long | **0.53×** | 2.67× | 0.71× | 0.78× |
309
+ | TTFA — short | **53 ms** | 21.7 s | 4.02 s | 2.45 s |
310
+ | TTFA — medium | **66 ms** | 28.9 s | 4.02 s | 3.72 s |
311
+ | TTFA — long | **89 ms** | 52.3 s | 10.3 s | 9.22 s |
312
+
313
+ ZeroTTS's time-to-first-audio comes from its real streaming path — first audio frame,
314
+ not first full utterance. The three baselines have no working CPU streaming
315
+ path, so their TTFA is the time to the complete utterance.
316
+
317
+ ## Credits
318
+
319
+ Speech codec: **[MOSS-Audio-Tokenizer-Nano](https://github.com/OpenMOSS/MOSS-Audio-Tokenizer)**
320
+ by the OpenMOSS team, Apache-2.0. ZeroTTS bundles its ONNX **decoder** graphs in
321
+ the weights repo so there is no external runtime dependency; see
322
+ [NOTICE](NOTICE) and [LICENSES/](LICENSES/).
323
+
324
+ ```bibtex
325
+ @misc{gong2026mossaudiotokenizerscalingaudiotokenizers,
326
+ title={MOSS-Audio-Tokenizer: Scaling Audio Tokenizers for Future Audio Foundation Models},
327
+ author={Yitian Gong and Kuangwei Chen and Zhaoye Fei and Xiaogui Yang and Ke Chen
328
+ and Yang Wang and Kexin Huang and Mingshu Chen and Ruixiao Li
329
+ and Qingyuan Cheng and Shimin Li and Xipeng Qiu},
330
+ year={2026}, eprint={2602.10934}, archivePrefix={arXiv}, primaryClass={cs.SD}
331
+ }
332
+ ```
333
+
334
+ Vietnamese text normalization adapts the expansion rules and abbreviation table
335
+ of **[soe-vinorm](https://github.com/vinhdq842/soe-vinorm)** (MIT), reimplemented
336
+ as pure stdlib regex so the inference path keeps its no-torch, no-download
337
+ guarantee. See [NOTICE](NOTICE).
338
+
339
+ Benchmark reference audio comes from
340
+ [VIVOS](https://huggingface.co/datasets/AILAB-VNUHCM/vivos),
341
+ [viVoice](https://huggingface.co/datasets/capleaf/viVoice),
342
+ [phoaudiobook](https://huggingface.co/datasets/thivux/phoaudiobook) and
343
+ [Emilia](https://huggingface.co/datasets/amphion/Emilia-Dataset).
344
+ ASR scoring uses [PhoWhisper](https://huggingface.co/vinai/PhoWhisper-large) (VinAI).
345
+
346
+ ## License
347
+
348
+ Code and weights: **MIT**. The bundled MOSS codec decoder is Apache-2.0.
349
+ The ZeroBench-TTS *dataset* is CC-BY-NC-4.0 (it redistributes audio from the
350
+ corpora above) — that applies to the benchmark, not to ZeroTTS.