Spaces:
Running on Zero
Running on Zero
first
Browse files- .DS_Store +0 -0
- CLAUDE.md +96 -0
- README.md +6 -7
- app.py +124 -0
- create_env.py +21 -0
- examples.yaml +45 -0
- model_config.yaml +38 -0
- requirements.txt +2 -0
- util.py +97 -0
.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
CLAUDE.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# CLAUDE.md
|
| 2 |
+
|
| 3 |
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
| 4 |
+
|
| 5 |
+
## Project Overview
|
| 6 |
+
|
| 7 |
+
KaniTTS-2 is a Gradio-based web application for text-to-speech generation using the KaniTTS model family from PyPI. It's designed to run on HuggingFace Spaces with GPU acceleration via the `@spaces.GPU` decorator.
|
| 8 |
+
|
| 9 |
+
## Running the Application
|
| 10 |
+
|
| 11 |
+
```bash
|
| 12 |
+
python app.py
|
| 13 |
+
```
|
| 14 |
+
|
| 15 |
+
The app launches on `0.0.0.0:7860` with a Gradio interface.
|
| 16 |
+
|
| 17 |
+
## Architecture
|
| 18 |
+
|
| 19 |
+
### Initialization Flow
|
| 20 |
+
|
| 21 |
+
The application follows a strict initialization sequence that must be maintained:
|
| 22 |
+
|
| 23 |
+
1. **Dependency Setup** ([app.py:1-3](app.py#L1-L3)): `create_env.setup_dependencies()` runs first to install the dev version of transformers from GitHub. This uses a `/tmp/deps_installed` marker to prevent repeated installations.
|
| 24 |
+
|
| 25 |
+
2. **Configuration Loading** ([app.py:12-13](app.py#L12-L13)): Loads `model_config.yaml` which defines multiple model checkpoints (e.g., "test-135000", "test-130000") with their HuggingFace paths and parameters.
|
| 26 |
+
|
| 27 |
+
3. **Examples Loading** ([app.py:15-17](app.py#L15-L17)): Loads `examples.yaml` via the `Examples` adapter class, which transforms YAML examples into Gradio-compatible list-of-lists format.
|
| 28 |
+
|
| 29 |
+
4. **Model Initialization** ([app.py:19-20](app.py#L19-L20)): `InitModels` loads all models upfront so the UI can switch between them without latency. Each model is a `KaniTTS` instance initialized directly with its config using unpacking (`**config`).
|
| 30 |
+
|
| 31 |
+
### Key Components
|
| 32 |
+
|
| 33 |
+
**InitModels** ([util.py:24-57](util.py#L24-L57))
|
| 34 |
+
- Lazy initializer that constructs a map of `model_name -> KaniTTS`
|
| 35 |
+
- Loads all models immediately in `__call__` for zero-switching latency
|
| 36 |
+
- Each `KaniTTS` instance is initialized by unpacking its config directly: `KaniTTS(**config)`
|
| 37 |
+
- No longer requires `NemoAudioPlayer` or HuggingFace token as these are handled internally by the PyPI package
|
| 38 |
+
|
| 39 |
+
**Examples** ([util.py:59-97](util.py#L59-L97))
|
| 40 |
+
- Adapter converting YAML examples to Gradio `gr.Examples` rows
|
| 41 |
+
- Order must match UI inputs: `[text, model_dropdown, temp, top_p, rp]`
|
| 42 |
+
- Centralizes format and defaults so UI input order changes only require updates here and in [app.py](app.py)
|
| 43 |
+
|
| 44 |
+
**generate_speech_gpu** ([app.py:22-55](app.py#L22-L55))
|
| 45 |
+
- Decorated with `@spaces.GPU` for HuggingFace Spaces GPU allocation
|
| 46 |
+
- Calls the model directly: `audio, _ = model(text, temperature=t, top_p=top_p, repetition_penalty=rp)`
|
| 47 |
+
- Returns only the audio tuple: `(sample_rate, audio)` - the text output is ignored
|
| 48 |
+
|
| 49 |
+
### Configuration Files
|
| 50 |
+
|
| 51 |
+
**model_config.yaml**
|
| 52 |
+
- Defines multiple model checkpoints under the `models` key
|
| 53 |
+
- Each model specifies: `model_name` (HF repo path), `device_map`, `use_bematts`, `audio_step`, `use_learnable_rope`
|
| 54 |
+
- All config parameters are passed directly to `KaniTTS` constructor via unpacking
|
| 55 |
+
|
| 56 |
+
**examples.yaml**
|
| 57 |
+
- List of example prompts with their generation parameters
|
| 58 |
+
- Each example requires: `text`, `model`, and optionally `temperature`, `top_p`, `repetition_penalty`
|
| 59 |
+
- Missing parameters fall back to defaults in [util.py:90-92](util.py#L90-L92): temperature=1.0, top_p=0.95, repetition_penalty=1.1
|
| 60 |
+
|
| 61 |
+
### Dependencies
|
| 62 |
+
|
| 63 |
+
- **kani-tts==1.0.1**: Core TTS library from PyPI providing `KaniTTS` class with all inference logic
|
| 64 |
+
- **gradio>=4.0.0**: UI framework
|
| 65 |
+
- **transformers**: Installed from GitHub main branch via [create_env.py](create_env.py) for latest features
|
| 66 |
+
|
| 67 |
+
### Environment Variables
|
| 68 |
+
|
| 69 |
+
- `OMP_NUM_THREADS=4`: Set in [create_env.py:6](create_env.py#L6) to limit OpenMP threading
|
| 70 |
+
|
| 71 |
+
## Important Implementation Notes
|
| 72 |
+
|
| 73 |
+
### Model Inference
|
| 74 |
+
- The KaniTTS model is called directly as a callable: `audio, text = model(text, temperature=..., top_p=..., repetition_penalty=...)`
|
| 75 |
+
- Returns tuple of `(audio, text)` but only audio is used in the UI
|
| 76 |
+
- No `max_tokens` parameter - the model handles sequence length internally
|
| 77 |
+
- Sample rate is hardcoded to 22050 Hz ([app.py:48](app.py#L48))
|
| 78 |
+
|
| 79 |
+
### Example Caching
|
| 80 |
+
- Examples use `cache_examples=True` ([app.py:131](app.py#L131)) to pre-generate audio, speeding up demo interactions
|
| 81 |
+
- If you modify generation logic, cached examples may need regeneration
|
| 82 |
+
|
| 83 |
+
### GPU Allocation
|
| 84 |
+
- The `@spaces.GPU` decorator is critical for HuggingFace Spaces deployment
|
| 85 |
+
- Without it, the app runs on CPU which is significantly slower
|
| 86 |
+
- Device selection falls back gracefully: `"cuda" if torch.cuda.is_available() else "cpu"` ([app.py:35](app.py#L35))
|
| 87 |
+
|
| 88 |
+
### Input Order Dependency
|
| 89 |
+
- The order of inputs in `gr.Examples` ([app.py:128](app.py#L128)) must exactly match the order in `Examples.__call__` ([util.py:94](util.py#L94))
|
| 90 |
+
- Current order: `[text, model_dropdown, temp, top_p, rp]`
|
| 91 |
+
- Changing this requires updates in both locations
|
| 92 |
+
|
| 93 |
+
### Removed Features
|
| 94 |
+
- **Speaker selection**: No longer supported in the new API
|
| 95 |
+
- **Time reporting**: Generation timing is not tracked
|
| 96 |
+
- **Max tokens slider**: Sequence length is handled automatically by the model
|
README.md
CHANGED
|
@@ -1,15 +1,14 @@
|
|
| 1 |
---
|
| 2 |
-
title: KaniTTS
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
-
python_version: '3.12'
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
| 11 |
license: apache-2.0
|
| 12 |
-
|
| 13 |
---
|
| 14 |
|
| 15 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
+
title: KaniTTS-2
|
| 3 |
+
emoji: 😻
|
| 4 |
+
colorFrom: green
|
| 5 |
+
colorTo: gray
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 5.46.0
|
|
|
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
license: apache-2.0
|
| 11 |
+
|
| 12 |
---
|
| 13 |
|
| 14 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from create_env import setup_dependencies
|
| 2 |
+
|
| 3 |
+
setup_dependencies()
|
| 4 |
+
|
| 5 |
+
import spaces
|
| 6 |
+
import gradio as gr
|
| 7 |
+
from util import InitModels, load_config, Examples
|
| 8 |
+
import numpy as np
|
| 9 |
+
import torch
|
| 10 |
+
|
| 11 |
+
config = load_config("./model_config.yaml")
|
| 12 |
+
models_configs = config.models
|
| 13 |
+
|
| 14 |
+
examples_cfg = load_config("./examples.yaml")
|
| 15 |
+
examples_maker = Examples(examples_cfg)
|
| 16 |
+
examples = examples_maker()
|
| 17 |
+
|
| 18 |
+
init_models = InitModels(models_configs)
|
| 19 |
+
models = init_models()
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@spaces.GPU
|
| 23 |
+
def generate_speech_gpu(text, model_choice, t, top_p, rp):
|
| 24 |
+
"""
|
| 25 |
+
Generate speech from text using the selected model on GPU
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
if not text.strip():
|
| 29 |
+
return None
|
| 30 |
+
|
| 31 |
+
if not model_choice:
|
| 32 |
+
return None
|
| 33 |
+
|
| 34 |
+
try:
|
| 35 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 36 |
+
print(f"Using device: {device}")
|
| 37 |
+
|
| 38 |
+
selected_model = models[model_choice]
|
| 39 |
+
|
| 40 |
+
print(f"Generating speech with {model_choice}...")
|
| 41 |
+
audio, _ = selected_model(
|
| 42 |
+
text,
|
| 43 |
+
temperature=t,
|
| 44 |
+
top_p=top_p,
|
| 45 |
+
repetition_penalty=rp
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
sample_rate = 22050
|
| 49 |
+
print("Speech generation completed!")
|
| 50 |
+
|
| 51 |
+
return (sample_rate, audio)
|
| 52 |
+
|
| 53 |
+
except Exception as e:
|
| 54 |
+
print(f"Error during generation: {str(e)}")
|
| 55 |
+
return None
|
| 56 |
+
|
| 57 |
+
# Create Gradio interface
|
| 58 |
+
with gr.Blocks(title="😻 KaniTTS - Text to Speech", theme=gr.themes.Ocean()) as demo:
|
| 59 |
+
gr.Markdown("# 😻 KaniTTS: Fast and Expressive Speech Generation Model")
|
| 60 |
+
gr.Markdown("Select a model and enter text to generate emotional speech")
|
| 61 |
+
|
| 62 |
+
with gr.Row():
|
| 63 |
+
with gr.Column(scale=1):
|
| 64 |
+
model_dropdown = gr.Dropdown(
|
| 65 |
+
choices=list(models_configs.keys()),
|
| 66 |
+
value=list(models_configs.keys())[0],
|
| 67 |
+
label="Selected Model"
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
text_input = gr.Textbox(
|
| 71 |
+
label="Text",
|
| 72 |
+
placeholder="Enter your text ...",
|
| 73 |
+
lines=3,
|
| 74 |
+
max_lines=10
|
| 75 |
+
)
|
| 76 |
+
|
| 77 |
+
with gr.Accordion("Settings", open=False):
|
| 78 |
+
temp = gr.Slider(
|
| 79 |
+
minimum=0.1, maximum=1.5, value=0.6, step=0.05,
|
| 80 |
+
label="Temp",
|
| 81 |
+
)
|
| 82 |
+
top_p = gr.Slider(
|
| 83 |
+
minimum=0.1, maximum=1.0, value=0.95, step=0.05,
|
| 84 |
+
label="Top P",
|
| 85 |
+
)
|
| 86 |
+
rp = gr.Slider(
|
| 87 |
+
minimum=1.0, maximum=2.0, value=1.1, step=0.05,
|
| 88 |
+
label="Repetition Penalty",
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
generate_btn = gr.Button("Run", variant="primary", size="lg")
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
with gr.Column(scale=1):
|
| 95 |
+
audio_output = gr.Audio(
|
| 96 |
+
label="Generated Audio",
|
| 97 |
+
type="numpy"
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
# GPU generation event
|
| 101 |
+
generate_btn.click(
|
| 102 |
+
fn=generate_speech_gpu,
|
| 103 |
+
inputs=[text_input, model_dropdown, temp, top_p, rp],
|
| 104 |
+
outputs=[audio_output]
|
| 105 |
+
)
|
| 106 |
+
|
| 107 |
+
with gr.Row():
|
| 108 |
+
|
| 109 |
+
examples = examples
|
| 110 |
+
|
| 111 |
+
gr.Examples(
|
| 112 |
+
examples=examples,
|
| 113 |
+
inputs=[text_input, model_dropdown, temp, top_p, rp],
|
| 114 |
+
fn=generate_speech_gpu,
|
| 115 |
+
outputs=[audio_output],
|
| 116 |
+
cache_examples=True,
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
if __name__ == "__main__":
|
| 120 |
+
demo.launch(
|
| 121 |
+
server_name="0.0.0.0",
|
| 122 |
+
server_port=7860,
|
| 123 |
+
show_error=True
|
| 124 |
+
)
|
create_env.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import subprocess
|
| 3 |
+
import sys
|
| 4 |
+
|
| 5 |
+
def setup_dependencies():
|
| 6 |
+
os.environ["OMP_NUM_THREADS"] = "4"
|
| 7 |
+
try:
|
| 8 |
+
if os.path.exists('/tmp/deps_installed'):
|
| 9 |
+
return
|
| 10 |
+
|
| 11 |
+
print("Installing transformers dev version...")
|
| 12 |
+
subprocess.check_call([
|
| 13 |
+
sys.executable, "-m", "pip", "install", "--force-reinstall", "--no-cache-dir",
|
| 14 |
+
"git+https://github.com/huggingface/transformers.git"
|
| 15 |
+
])
|
| 16 |
+
|
| 17 |
+
with open('/tmp/deps_installed', 'w') as f:
|
| 18 |
+
f.write('done')
|
| 19 |
+
|
| 20 |
+
except Exception as e:
|
| 21 |
+
print(f"Dependencies setup error: {e}")
|
examples.yaml
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
examples:
|
| 2 |
+
- text: >-
|
| 3 |
+
No, that does not make you a failure. No, sweetie, no. It just, uh, it just means that you're having a tough time...
|
| 4 |
+
model: "test-135000"
|
| 5 |
+
temperature: 1
|
| 6 |
+
top_p: 0.95
|
| 7 |
+
repetition_penalty: 1.1
|
| 8 |
+
|
| 9 |
+
- text: >-
|
| 10 |
+
Anyway, um, so, um, tell me, tell me all about her. I mean, what's she like? Is she really, you know, pretty?
|
| 11 |
+
model: "test-135000"
|
| 12 |
+
temperature: 1
|
| 13 |
+
top_p: 0.95
|
| 14 |
+
repetition_penalty: 1.1
|
| 15 |
+
|
| 16 |
+
- text: >-
|
| 17 |
+
Have some wine, the March Hare said in an encouraging tone. Alice looked all round the table, but there was nothing on it but tea. I don't see any wine, she remarked. There isn't any, said the March Hare. Then it wasn't very civil of you to offer it, said Alice angrily. It wasn't very civil of you to sit down without being invited, said the March Hare. I didn't know it was YOUR table, said Alice; it's laid for a great many more than three. Your hair wants cutting, said the Hatter. He had been looking at Alice for some time with great curiosity, and this was his first speech. You should learn not to make personal remarks, Alice said with some severity; it's very rude.
|
| 18 |
+
model: "test-135000"
|
| 19 |
+
temperature: 1
|
| 20 |
+
top_p: 0.95
|
| 21 |
+
repetition_penalty: 1.1
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
- text: >-
|
| 25 |
+
Attention networks have proven to be an effective approach for embedding categorical inference within a deep neural network. However, for many tasks we may want to model richer structural dependencies without abandoning end-to-end training. In this work, we experiment with incorporating richer structural distributions, encoded using graphical models, within deep networks. We show that these structured attention networks are simple extensions of the basic attention procedure, and that they allow for extending attention beyond the standard softselection approach, such as attending to partial segmentations or to subtrees.
|
| 26 |
+
model: "test-135000"
|
| 27 |
+
temperature: 1
|
| 28 |
+
top_p: 0.95
|
| 29 |
+
repetition_penalty: 1.1
|
| 30 |
+
|
| 31 |
+
- text: >-
|
| 32 |
+
Кыргыз жери! Сенин ар бир ташыңда, ар бир тооңдо, ар бир сууңда менин жүрөгүмдүн бир бөлүгү бар. Сен менин ата-журтум, менин ыйык мекенимсиң.
|
| 33 |
+
model: "test-135000"
|
| 34 |
+
temperature: 1
|
| 35 |
+
top_p: 0.95
|
| 36 |
+
repetition_penalty: 1.1
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
- text: >-
|
| 40 |
+
¿Será que todavía me recuerdas como antes?
|
| 41 |
+
model: "test-135000"
|
| 42 |
+
temperature: 1
|
| 43 |
+
top_p: 0.95
|
| 44 |
+
repetition_penalty: 1.1
|
| 45 |
+
|
model_config.yaml
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
models:
|
| 2 |
+
|
| 3 |
+
"test-135000":
|
| 4 |
+
model_name: nineninesix/full-checkpoint-135000
|
| 5 |
+
device_map: null
|
| 6 |
+
use_bematts: true
|
| 7 |
+
audio_step: 1.0
|
| 8 |
+
use_learnable_rope: true
|
| 9 |
+
|
| 10 |
+
"test-130000":
|
| 11 |
+
model_name: nineninesix/full-checkpoint-130000
|
| 12 |
+
device_map: null
|
| 13 |
+
use_bematts: true
|
| 14 |
+
audio_step: 1.0
|
| 15 |
+
use_learnable_rope: true
|
| 16 |
+
|
| 17 |
+
"test-110000":
|
| 18 |
+
model_name: nineninesix/full-checkpoint-110000
|
| 19 |
+
device_map: null
|
| 20 |
+
use_bematts: true
|
| 21 |
+
audio_step: 1.0
|
| 22 |
+
use_learnable_rope: true
|
| 23 |
+
|
| 24 |
+
"test-95000":
|
| 25 |
+
model_name: nineninesix/full-checkpoint-95000
|
| 26 |
+
device_map: null
|
| 27 |
+
use_bematts: true
|
| 28 |
+
audio_step: 1.0
|
| 29 |
+
use_learnable_rope: true
|
| 30 |
+
|
| 31 |
+
"test-25000":
|
| 32 |
+
model_name: nineninesix/full-checkpoint-25000
|
| 33 |
+
device_map: null
|
| 34 |
+
use_bematts: true
|
| 35 |
+
audio_step: 1.0
|
| 36 |
+
use_learnable_rope: true
|
| 37 |
+
|
| 38 |
+
|
requirements.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
kani-tts==1.0.1
|
| 2 |
+
gradio>=4.0.0
|
util.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from kani_tts import KaniTTS
|
| 2 |
+
|
| 3 |
+
import os
|
| 4 |
+
from omegaconf import OmegaConf
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def load_config(config_path: str):
|
| 8 |
+
"""Load configuration from a YAML file using OmegaConf.
|
| 9 |
+
|
| 10 |
+
Args:
|
| 11 |
+
config_path (str): Path to the YAML configuration file.
|
| 12 |
+
|
| 13 |
+
Returns:
|
| 14 |
+
Any: The loaded OmegaConf DictConfig.
|
| 15 |
+
"""
|
| 16 |
+
resolved_path = os.path.abspath(config_path)
|
| 17 |
+
if not os.path.exists(resolved_path):
|
| 18 |
+
raise FileNotFoundError(f"Config file not found: {resolved_path}")
|
| 19 |
+
config = OmegaConf.load(resolved_path)
|
| 20 |
+
return config
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class InitModels:
|
| 25 |
+
|
| 26 |
+
"""
|
| 27 |
+
Lazy initializer that constructs a map of model name -> KaniTTS.
|
| 28 |
+
|
| 29 |
+
Parameters
|
| 30 |
+
----------
|
| 31 |
+
models_configs : OmegaConf | DictConfig
|
| 32 |
+
The `models` section from `model_config.yaml` describing one or
|
| 33 |
+
more HF model checkpoints and their options (device_map, use_bematts, etc.).
|
| 34 |
+
|
| 35 |
+
Returns
|
| 36 |
+
-------
|
| 37 |
+
dict
|
| 38 |
+
When called, returns a dictionary `{model_name: KaniTTS}`.
|
| 39 |
+
|
| 40 |
+
Notes
|
| 41 |
+
-----
|
| 42 |
+
- All models are loaded immediately in `__call__` so the UI can list
|
| 43 |
+
them and switch between them without extra latency.
|
| 44 |
+
- Each KaniTTS instance is initialized with its config directly.
|
| 45 |
+
"""
|
| 46 |
+
|
| 47 |
+
def __init__(self, models_configs: OmegaConf):
|
| 48 |
+
self.models_configs = models_configs
|
| 49 |
+
|
| 50 |
+
def __call__(self):
|
| 51 |
+
models = {}
|
| 52 |
+
for model_name, config in self.models_configs.items():
|
| 53 |
+
print(f"Loading {model_name}...")
|
| 54 |
+
models[model_name] = KaniTTS(**config)
|
| 55 |
+
print(f"{model_name} loaded!")
|
| 56 |
+
print("All models loaded!")
|
| 57 |
+
return models
|
| 58 |
+
|
| 59 |
+
class Examples:
|
| 60 |
+
|
| 61 |
+
"""
|
| 62 |
+
Adapter that converts YAML examples into Gradio `gr.Examples` rows.
|
| 63 |
+
|
| 64 |
+
Parameters
|
| 65 |
+
----------
|
| 66 |
+
exam_cfg : OmegaConf | DictConfig
|
| 67 |
+
Parsed contents of `examples.yaml`. Expected structure:
|
| 68 |
+
`examples: [ {text, model, temperature?, top_p?, repetition_penalty?}, ... ]`.
|
| 69 |
+
|
| 70 |
+
Behavior
|
| 71 |
+
--------
|
| 72 |
+
- Produces a list-of-lists whose order must match the `inputs` order
|
| 73 |
+
used when constructing `gr.Examples` in `app.py`.
|
| 74 |
+
- Current order: `[text, model_dropdown, temp, top_p, rp]`.
|
| 75 |
+
|
| 76 |
+
Why this exists
|
| 77 |
+
---------------
|
| 78 |
+
- Keeps format and defaults centralized, so changing the UI inputs
|
| 79 |
+
order only requires a single change here and in `app.py`.
|
| 80 |
+
"""
|
| 81 |
+
|
| 82 |
+
def __init__(self, exam_cfg: OmegaConf):
|
| 83 |
+
self.exam_cfg = exam_cfg
|
| 84 |
+
|
| 85 |
+
def __call__(self) -> list[list]:
|
| 86 |
+
rows = []
|
| 87 |
+
for e in self.exam_cfg.examples:
|
| 88 |
+
text = e.get("text")
|
| 89 |
+
model = e.get("model")
|
| 90 |
+
temperature = e.get("temperature", 1.0)
|
| 91 |
+
top_p = e.get("top_p", 0.95)
|
| 92 |
+
repetition_penalty = e.get("repetition_penalty", 1.1)
|
| 93 |
+
# Order must match gr.Examples inputs: [text, model_dropdown, temp, top_p, rp]
|
| 94 |
+
rows.append([text, model, temperature, top_p, repetition_penalty])
|
| 95 |
+
|
| 96 |
+
return rows
|
| 97 |
+
|