Spaces:
Running
on
Zero
Running
on
Zero
Upload app.py
Browse files
app.py
CHANGED
@@ -142,7 +142,7 @@ VOCAB = get_vocab()
|
|
142 |
def tokenize(ps):
|
143 |
return [i for i in map(VOCAB.get, ps) if i is not None]
|
144 |
|
145 |
-
# ⭐
|
146 |
CHOICES = {
|
147 |
'🇺🇸 🚺 American Female ⭐': 'af',
|
148 |
'🇺🇸 🚺 Bella': 'af_bella',
|
@@ -212,10 +212,10 @@ def _generate(text, voice, ps, speed, opening_cut, closing_cut, ease_in, ease_ou
|
|
212 |
tokens = tokens[:510]
|
213 |
ps = ''.join(next(k for k, v in VOCAB.items() if i == v) for i in tokens)
|
214 |
try:
|
215 |
-
if use_gpu or (use_gpu
|
216 |
-
out = forward_gpu(tokens, voice, speed)
|
217 |
-
else:
|
218 |
out = forward(tokens, voice, speed)
|
|
|
|
|
219 |
except gr.exceptions.Error as e:
|
220 |
raise gr.Error(e)
|
221 |
return (None, '')
|
@@ -236,11 +236,29 @@ def _generate(text, voice, ps, speed, opening_cut, closing_cut, ease_in, ease_ou
|
|
236 |
def toggle_autoplay(autoplay):
|
237 |
return gr.Audio(interactive=False, label='Output Audio', autoplay=autoplay)
|
238 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
239 |
with gr.Blocks() as basic_tts:
|
240 |
with gr.Row():
|
241 |
with gr.Column():
|
242 |
-
text = gr.Textbox(label='Input Text', info='Generate speech for one segment of text using Kokoro, a TTS model with 80 million parameters
|
243 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
with gr.Row():
|
245 |
random_btn = gr.Button('Random Text', variant='secondary')
|
246 |
generate_btn = gr.Button('Generate', variant='primary')
|
@@ -257,13 +275,6 @@ with gr.Blocks() as basic_tts:
|
|
257 |
autoplay.change(toggle_autoplay, inputs=[autoplay], outputs=[audio])
|
258 |
with gr.Accordion('Output Tokens', open=True):
|
259 |
out_ps = gr.Textbox(interactive=False, show_label=False, info='Tokens used to generate the audio, up to 510 allowed. Same as input tokens if supplied, excluding unknowns.')
|
260 |
-
with gr.Row():
|
261 |
-
use_gpu = gr.Radio(
|
262 |
-
[('CPU', False), ('Force GPU', True), ('Dynamic', None)],
|
263 |
-
value=None if CUDA_AVAILABLE else False, label='⚙️ Hardware',
|
264 |
-
info='CPU: unlimited, ~faster <100 tokens. GPU: limited usage quota, ~faster 100+ tokens. Dynamic: switches based on # of tokens.',
|
265 |
-
interactive=CUDA_AVAILABLE
|
266 |
-
)
|
267 |
with gr.Accordion('Audio Settings', open=False):
|
268 |
with gr.Row():
|
269 |
speed = gr.Slider(minimum=0.5, maximum=2, value=1, step=0.1, label='⚡️ Speed', info='Adjust the speed of the audio; the settings below are auto-scaled by speed')
|
@@ -421,9 +432,17 @@ with gr.Blocks() as lf_tts:
|
|
421 |
with gr.Row():
|
422 |
with gr.Column():
|
423 |
file_input = gr.File(file_types=['.pdf', '.txt'], label='Input File: pdf or txt')
|
424 |
-
text = gr.Textbox(label='Input Text', info='Generate speech in batches of 100 text segments and automatically join them together
|
425 |
file_input.upload(fn=extract_text, inputs=[file_input], outputs=[text])
|
426 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
427 |
with gr.Accordion('Text Settings', open=False):
|
428 |
skip_square_brackets = gr.Checkbox(True, label='Skip [Square Brackets]', info='Recommended for academic papers, Wikipedia articles, or texts with citations')
|
429 |
newline_split = gr.Number(2, label='Newline Split', info='Split the input text on this many newlines. Affects how the text is segmented.', precision=0, minimum=0)
|
@@ -432,24 +451,19 @@ with gr.Blocks() as lf_tts:
|
|
432 |
generate_btn = gr.Button('Generate x0', variant='secondary', interactive=False)
|
433 |
with gr.Column():
|
434 |
audio = gr.Audio(interactive=False, label='Output Audio')
|
435 |
-
use_gpu = gr.Checkbox(value=CUDA_AVAILABLE, label='Use ZeroGPU', info='🚀 ZeroGPU is fast but has a limited usage quota', interactive=CUDA_AVAILABLE)
|
436 |
-
use_gpu.change(
|
437 |
-
fn=lambda v: gr.Checkbox(value=v, label='Use ZeroGPU', info='🚀 ZeroGPU is fast but has a limited usage quota' if v else '🐌 CPU is slow but unlimited'),
|
438 |
-
inputs=[use_gpu], outputs=[use_gpu]
|
439 |
-
)
|
440 |
with gr.Accordion('Audio Settings', open=False):
|
441 |
with gr.Row():
|
442 |
speed = gr.Slider(minimum=0.5, maximum=2, value=1, step=0.1, label='⚡️ Speed', info='Adjust the speed of the audio; the settings below are auto-scaled by speed')
|
443 |
with gr.Row():
|
444 |
with gr.Column():
|
445 |
-
opening_cut = gr.Slider(minimum=0, maximum=24000, value=4000, step=1000, label='✂️ Opening Cut', info='Cut
|
446 |
with gr.Column():
|
447 |
-
closing_cut = gr.Slider(minimum=0, maximum=24000, value=2000, step=1000, label='🎬 Closing Cut', info='Cut
|
448 |
with gr.Row():
|
449 |
with gr.Column():
|
450 |
-
ease_in = gr.Slider(minimum=0, maximum=24000, value=3000, step=1000, label='🎢 Ease In', info='Ease in
|
451 |
with gr.Column():
|
452 |
-
ease_out = gr.Slider(minimum=0, maximum=24000, value=1000, step=1000, label='🛝 Ease Out', info='Ease out
|
453 |
with gr.Row():
|
454 |
pad_between = gr.Slider(minimum=0, maximum=24000, value=10000, step=1000, label='🔇 Pad Between', info='How many samples of silence to insert between segments')
|
455 |
with gr.Row():
|
@@ -460,51 +474,26 @@ with gr.Blocks() as lf_tts:
|
|
460 |
|
461 |
with gr.Blocks() as about:
|
462 |
gr.Markdown("""
|
463 |
-
Kokoro is a frontier TTS model for its size. It has 80 million parameters,<sup>[1]</sup> uses a lean StyleTTS 2 architecture,<sup>[2]</sup> and was trained on high-quality data.
|
464 |
|
465 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
466 |
|
467 |
### Compute
|
468 |
The model was trained on 1x A100-class 80GB instances rented from [Vast.ai](https://cloud.vast.ai/?ref_id=79907).<sup>[3]</sup><br/>
|
469 |
Vast was chosen over other compute providers due to its competitive on-demand hourly rates.<br/>
|
470 |
The average hourly cost for the 1x A100-class 80GB VRAM instances used for training was below $1/hr — around half the quoted rates from other providers.
|
471 |
|
472 |
-
###
|
473 |
-
Inference code: MIT<br/>
|
474 |
-
espeak-ng dependency: GPL-3.0<sup>[4]</sup><br/>
|
475 |
-
Random English texts: Unknown<sup>[5]</sup><br/>
|
476 |
-
Random Japanese texts: CC0 public domain<sup>[6]</sup>
|
477 |
-
|
478 |
-
### References
|
479 |
-
1. Kokoro parameter count | https://hf.co/spaces/hexgrad/Kokoro-TTS/blob/main/app.py#L31
|
480 |
-
2. StyleTTS 2 | https://github.com/yl4579/StyleTTS2
|
481 |
-
3. Vast.ai referral link | https://cloud.vast.ai/?ref_id=79907
|
482 |
-
4. eSpeak NG | https://github.com/espeak-ng/espeak-ng
|
483 |
-
5. Quotable Data | https://github.com/quotable-io/data/blob/master/data/quotes.json
|
484 |
-
6. Common Voice Japanese sentences | https://github.com/common-voice/common-voice/tree/main/server/data/ja
|
485 |
-
|
486 |
-
### Contact
|
487 |
-
@rzvzn on Discord
|
488 |
-
""")
|
489 |
-
|
490 |
-
with gr.Blocks() as faq:
|
491 |
-
gr.Markdown("""
|
492 |
-
### Will this be open sourced?
|
493 |
-
There currently isn't a release date scheduled for the weights. The inference code in this space is MIT licensed. The StyleTTS 2 architecture was already published by Li et al, with MIT licensed code and pretrained weights.
|
494 |
-
|
495 |
-
### What does it mean for a voice to be unstable?
|
496 |
-
An unstable voice is more likely to stumble or produce unnatural artifacts, especially on short or strange texts.
|
497 |
-
|
498 |
-
### CPU faster than ZeroGPU? How?
|
499 |
-
The CPU seems to be a dedicated resource for this Space, whereas the ZeroGPU pool is shared dynamically allocated across all of HF. Obviously the latter demands some kind of queue & allocator system, which inevitably must add latency.
|
500 |
-
|
501 |
-
For Basic TTS under 100 tokens (~characters), only a few seconds of audio needs to be generated, so the actual compute is not that heavy. For these short bursts, the dedicated CPU can often compute the result faster than the total time it takes for you to: enter the ZeroGPU queue, wait to get allocated, and have a GPU compute and deliver the result.
|
502 |
-
|
503 |
-
As you move beyond 100 tokens and especially closer to the ~500 token context window, the GPU catches up. And for Long-Form, since batches of 100 segments are processed at a time, the GPU should outspeed the CPU by 1-2 orders of magnitude.
|
504 |
-
""")
|
505 |
-
|
506 |
-
with gr.Blocks() as api_info:
|
507 |
-
gr.Markdown("""
|
508 |
This Space can be used via API. The following code block can be copied and run in one Google Colab cell.
|
509 |
```
|
510 |
# 1. Install the Gradio Python client
|
@@ -527,21 +516,33 @@ display(Audio(audio_path, autoplay=True))
|
|
527 |
print(out_ps)
|
528 |
```
|
529 |
Note that this Space and the underlying Kokoro model are both under development and subject to change. Reliability is not guaranteed. Hugging Face and/or Gradio might enforce their own rate limits.
|
530 |
-
""")
|
531 |
|
532 |
-
|
533 |
-
|
534 |
-
|
|
535 |
-
| ------- | ---- | ------------------------------ |
|
536 |
| v0.19 | 2024 Nov 22 | 0.261 / 0.627 / 1.897 |
|
537 |
| v0.16 | 2024 Nov 15 | 0.263 / 0.646 / 1.934 |
|
538 |
| v0.14 | 2024 Nov 12 | 0.262 / 0.642 / 1.889 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
539 |
""")
|
540 |
|
541 |
with gr.Blocks() as app:
|
542 |
gr.TabbedInterface(
|
543 |
-
[basic_tts, lf_tts, about
|
544 |
-
['
|
545 |
)
|
546 |
|
547 |
if __name__ == '__main__':
|
|
|
142 |
def tokenize(ps):
|
143 |
return [i for i in map(VOCAB.get, ps) if i is not None]
|
144 |
|
145 |
+
# ⭐ voices are stable, 🧪 voices are unstable
|
146 |
CHOICES = {
|
147 |
'🇺🇸 🚺 American Female ⭐': 'af',
|
148 |
'🇺🇸 🚺 Bella': 'af_bella',
|
|
|
212 |
tokens = tokens[:510]
|
213 |
ps = ''.join(next(k for k, v in VOCAB.items() if i == v) for i in tokens)
|
214 |
try:
|
215 |
+
if not use_gpu or (use_gpu == 'auto' and len(ps) < 100):
|
|
|
|
|
216 |
out = forward(tokens, voice, speed)
|
217 |
+
else:
|
218 |
+
out = forward_gpu(tokens, voice, speed)
|
219 |
except gr.exceptions.Error as e:
|
220 |
raise gr.Error(e)
|
221 |
return (None, '')
|
|
|
236 |
def toggle_autoplay(autoplay):
|
237 |
return gr.Audio(interactive=False, label='Output Audio', autoplay=autoplay)
|
238 |
|
239 |
+
USE_GPU_CHOICES = [('Auto', 'auto'), ('CPU', False), ('ZeroGPU', True)]
|
240 |
+
USE_GPU_INFOS = {
|
241 |
+
'auto': 'Use CPU or GPU, whichever is faster',
|
242 |
+
False: 'CPU is ~faster <100 tokens',
|
243 |
+
True: 'ZeroGPU is ~faster >100 tokens',
|
244 |
+
}
|
245 |
+
def change_use_gpu(value):
|
246 |
+
return gr.Dropdown(USE_GPU_CHOICES, value=value, label='Hardware', info=USE_GPU_INFOS[value], interactive=CUDA_AVAILABLE)
|
247 |
+
|
248 |
with gr.Blocks() as basic_tts:
|
249 |
with gr.Row():
|
250 |
with gr.Column():
|
251 |
+
text = gr.Textbox(label='Input Text', info='Generate speech for one segment of text using Kokoro, a TTS model with 80 million parameters')
|
252 |
+
with gr.Row():
|
253 |
+
voice = gr.Dropdown(list(CHOICES.items()), value='af', label='Voice', info='⭐ voices are stable, 🧪 voices are unstable')
|
254 |
+
use_gpu = gr.Dropdown(
|
255 |
+
USE_GPU_CHOICES,
|
256 |
+
value='auto' if CUDA_AVAILABLE else False,
|
257 |
+
label='Hardware',
|
258 |
+
info=USE_GPU_INFOS['auto' if CUDA_AVAILABLE else False],
|
259 |
+
interactive=CUDA_AVAILABLE
|
260 |
+
)
|
261 |
+
use_gpu.change(fn=change_use_gpu, inputs=[use_gpu], outputs=[use_gpu])
|
262 |
with gr.Row():
|
263 |
random_btn = gr.Button('Random Text', variant='secondary')
|
264 |
generate_btn = gr.Button('Generate', variant='primary')
|
|
|
275 |
autoplay.change(toggle_autoplay, inputs=[autoplay], outputs=[audio])
|
276 |
with gr.Accordion('Output Tokens', open=True):
|
277 |
out_ps = gr.Textbox(interactive=False, show_label=False, info='Tokens used to generate the audio, up to 510 allowed. Same as input tokens if supplied, excluding unknowns.')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
278 |
with gr.Accordion('Audio Settings', open=False):
|
279 |
with gr.Row():
|
280 |
speed = gr.Slider(minimum=0.5, maximum=2, value=1, step=0.1, label='⚡️ Speed', info='Adjust the speed of the audio; the settings below are auto-scaled by speed')
|
|
|
432 |
with gr.Row():
|
433 |
with gr.Column():
|
434 |
file_input = gr.File(file_types=['.pdf', '.txt'], label='Input File: pdf or txt')
|
435 |
+
text = gr.Textbox(label='Input Text', info='Generate speech in batches of 100 text segments and automatically join them together')
|
436 |
file_input.upload(fn=extract_text, inputs=[file_input], outputs=[text])
|
437 |
+
with gr.Row():
|
438 |
+
voice = gr.Dropdown(list(CHOICES.items()), value='af', label='Voice', info='⭐ voices are stable, 🧪 voices are unstable')
|
439 |
+
use_gpu = gr.Dropdown(
|
440 |
+
[('ZeroGPU', True), ('CPU', False)],
|
441 |
+
value=CUDA_AVAILABLE,
|
442 |
+
label='Hardware',
|
443 |
+
info='GPU is >10x faster but has a usage quota',
|
444 |
+
interactive=CUDA_AVAILABLE
|
445 |
+
)
|
446 |
with gr.Accordion('Text Settings', open=False):
|
447 |
skip_square_brackets = gr.Checkbox(True, label='Skip [Square Brackets]', info='Recommended for academic papers, Wikipedia articles, or texts with citations')
|
448 |
newline_split = gr.Number(2, label='Newline Split', info='Split the input text on this many newlines. Affects how the text is segmented.', precision=0, minimum=0)
|
|
|
451 |
generate_btn = gr.Button('Generate x0', variant='secondary', interactive=False)
|
452 |
with gr.Column():
|
453 |
audio = gr.Audio(interactive=False, label='Output Audio')
|
|
|
|
|
|
|
|
|
|
|
454 |
with gr.Accordion('Audio Settings', open=False):
|
455 |
with gr.Row():
|
456 |
speed = gr.Slider(minimum=0.5, maximum=2, value=1, step=0.1, label='⚡️ Speed', info='Adjust the speed of the audio; the settings below are auto-scaled by speed')
|
457 |
with gr.Row():
|
458 |
with gr.Column():
|
459 |
+
opening_cut = gr.Slider(minimum=0, maximum=24000, value=4000, step=1000, label='✂️ Opening Cut', info='Cut samples from the start')
|
460 |
with gr.Column():
|
461 |
+
closing_cut = gr.Slider(minimum=0, maximum=24000, value=2000, step=1000, label='🎬 Closing Cut', info='Cut samples from the end')
|
462 |
with gr.Row():
|
463 |
with gr.Column():
|
464 |
+
ease_in = gr.Slider(minimum=0, maximum=24000, value=3000, step=1000, label='🎢 Ease In', info='Ease in samples, after opening cut')
|
465 |
with gr.Column():
|
466 |
+
ease_out = gr.Slider(minimum=0, maximum=24000, value=1000, step=1000, label='🛝 Ease Out', info='Ease out samples, before closing cut')
|
467 |
with gr.Row():
|
468 |
pad_between = gr.Slider(minimum=0, maximum=24000, value=10000, step=1000, label='🔇 Pad Between', info='How many samples of silence to insert between segments')
|
469 |
with gr.Row():
|
|
|
474 |
|
475 |
with gr.Blocks() as about:
|
476 |
gr.Markdown("""
|
477 |
+
Kokoro is a frontier TTS model for its size. It has 80 million parameters,<sup>[1]</sup> uses a lean StyleTTS 2 architecture,<sup>[2]</sup> and was trained on high-quality data. The weights are currently private, but a free public demo is hosted here, at `https://hf.co/spaces/hexgrad/Kokoro-TTS`. The Community tab is open for feature requests, bug reports, etc. For other inquiries, contact @rzvzn on Discord.
|
478 |
|
479 |
+
### FAQ
|
480 |
+
#### Will this be open sourced?
|
481 |
+
There currently isn't a release date scheduled for the weights. The inference code in this space is MIT licensed. The architecture was already published by Li et al, with MIT licensed code and pretrained weights.<sup>[2]</sup>
|
482 |
+
|
483 |
+
#### What is an unstable voice?
|
484 |
+
An unstable voice is more likely to stumble or produce unnatural artifacts, especially on short or strange texts.
|
485 |
+
|
486 |
+
#### How can CPU be faster than ZeroGPU?
|
487 |
+
The CPU is a dedicated resource for this Space, while the ZeroGPU pool is shared and dynamically allocated across all of HF. The ZeroGPU queue/allocator system inevitably adds latency to each request.<br/>
|
488 |
+
For Basic TTS under ~100 tokens or characters, only a few seconds of audio need to be generated, so the actual compute is not that heavy. In these short bursts, the dedicated CPU can often compute the result faster than the total time it takes to: enter the ZeroGPU queue, wait to get allocated, and have a GPU compute and deliver the result.<br/>
|
489 |
+
ZeroGPU catches up beyond 100 tokens and especially closer to the ~500 token context window. Long-Form mode processes batches of 100 segments at a time, so the GPU should outspeed the CPU by 1-2 orders of magnitude.
|
490 |
|
491 |
### Compute
|
492 |
The model was trained on 1x A100-class 80GB instances rented from [Vast.ai](https://cloud.vast.ai/?ref_id=79907).<sup>[3]</sup><br/>
|
493 |
Vast was chosen over other compute providers due to its competitive on-demand hourly rates.<br/>
|
494 |
The average hourly cost for the 1x A100-class 80GB VRAM instances used for training was below $1/hr — around half the quoted rates from other providers.
|
495 |
|
496 |
+
### Gradio API
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
497 |
This Space can be used via API. The following code block can be copied and run in one Google Colab cell.
|
498 |
```
|
499 |
# 1. Install the Gradio Python client
|
|
|
516 |
print(out_ps)
|
517 |
```
|
518 |
Note that this Space and the underlying Kokoro model are both under development and subject to change. Reliability is not guaranteed. Hugging Face and/or Gradio might enforce their own rate limits.
|
|
|
519 |
|
520 |
+
### Model Version History
|
521 |
+
| Version | Date | Val mel / dur / f0 Losses |
|
522 |
+
| ------- | ---- | ------------------------- |
|
|
|
523 |
| v0.19 | 2024 Nov 22 | 0.261 / 0.627 / 1.897 |
|
524 |
| v0.16 | 2024 Nov 15 | 0.263 / 0.646 / 1.934 |
|
525 |
| v0.14 | 2024 Nov 12 | 0.262 / 0.642 / 1.889 |
|
526 |
+
|
527 |
+
### Licenses
|
528 |
+
Inference code: MIT<br/>
|
529 |
+
espeak-ng dependency: GPL-3.0<sup>[4]</sup><br/>
|
530 |
+
Random English texts: Unknown<sup>[5]</sup><br/>
|
531 |
+
Random Japanese texts: CC0 public domain<sup>[6]</sup>
|
532 |
+
|
533 |
+
### References
|
534 |
+
1. Kokoro parameter count | https://hf.co/spaces/hexgrad/Kokoro-TTS/blob/main/app.py#L31
|
535 |
+
2. StyleTTS 2 | https://github.com/yl4579/StyleTTS2
|
536 |
+
3. Vast.ai referral link | https://cloud.vast.ai/?ref_id=79907
|
537 |
+
4. eSpeak NG | https://github.com/espeak-ng/espeak-ng
|
538 |
+
5. Quotable Data | https://github.com/quotable-io/data/blob/master/data/quotes.json
|
539 |
+
6. Common Voice Japanese sentences | https://github.com/common-voice/common-voice/tree/main/server/data/ja
|
540 |
""")
|
541 |
|
542 |
with gr.Blocks() as app:
|
543 |
gr.TabbedInterface(
|
544 |
+
[basic_tts, lf_tts, about],
|
545 |
+
['🔥 Basic TTS', '📖 Long-Form', 'ℹ️ About'],
|
546 |
)
|
547 |
|
548 |
if __name__ == '__main__':
|