Skip to content

Commit ba626d1

Browse files
authored
decorator upgrades, fixes, UI improvements (#517)
* add sample voices * rank up chatterbox extension in the order * change resemble enhance gitignore pattern * import text splitter to webui * improve Gradio random seed UI * improve model management API * improve generator compatibility with extensions * add interactivity to model unloading button * attempt Dockerfile pip fix * add chunked generations to chatterbox React UI * voice dropdown stub * readme * add save_wav accumulated
1 parent a9dad24 commit ba626d1

17 files changed

+170
-46
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ extensions.external.json
3636
/data/models/parler_tts/
3737
/data/models/musicgen_audiogen/*/
3838
/data/models/gpt_sovits/
39-
/data/models/resemble_enhance/ds/
39+
/data/models/resemble_enhance/
4040
/data/models/ap_bwe/weights/
4141
/data/models/openvoice/
4242
/data/models/openvoice_v2/

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ RUN npm --version
2424
ENV TORCH_VERSION=2.6.0
2525

2626
ENV PATH="/root/.cargo/bin:$PATH"
27+
RUN pip install --no-cache-dir --upgrade pip setuptools wheel
2728
RUN pip install --no-cache-dir setuptools torch==$TORCH_VERSION torchvision torchaudio
2829

2930
# Set working directory

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,17 @@
8686

8787
## Changelog
8888

89+
June 4:
90+
* Attempt dockerfile fix.
91+
* Add interactivity to model unloading button, improve Gradio random seed UI.
92+
* Add sample voices.
93+
8994
June 1:
9095
* Add presets API.
9196
* Add API Preset config to React UI.
9297

98+
## May 2025
99+
93100
May 31:
94101
* Improve React UI Audio player.
95102
* Fix ROCm installation version.

extensions.json

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,20 @@
9090
"extension_website": "https://github.com/rsxdalv/extension_f5_tts",
9191
"extension_platform_version": "0.0.1"
9292
},
93+
{
94+
"package_name": "extension_chatterbox",
95+
"name": "Chatterbox",
96+
"requirements": "git+https://github.com/rsxdalv/extension_chatterbox@main",
97+
"description": "Chatterbox, Resemble AI's first production-grade open source TTS model",
98+
"extension_type": "interface",
99+
"extension_class": "text-to-speech",
100+
"author": "Resemble AI",
101+
"extension_author": "rsxdalv",
102+
"license": "MIT",
103+
"website": "https://github.com/resemble-ai/chatterbox",
104+
"extension_website": "https://github.com/rsxdalv/extension_chatterbox",
105+
"extension_platform_version": "0.0.1"
106+
},
93107
{
94108
"package_name": "extension_bark",
95109
"recommended": true,
@@ -656,20 +670,6 @@
656670
"website": "https://github.com/rsxdalv/extension_audiobook_generator",
657671
"extension_website": "https://github.com/rsxdalv/extension_audiobook_generator",
658672
"extension_platform_version": "0.0.1"
659-
},
660-
{
661-
"package_name": "extension_chatterbox",
662-
"name": "Chatterbox",
663-
"requirements": "git+https://github.com/rsxdalv/extension_chatterbox@main",
664-
"description": "Chatterbox, Resemble AI's first production-grade open source TTS model",
665-
"extension_type": "interface",
666-
"extension_class": "text-to-speech",
667-
"author": "Resemble AI",
668-
"extension_author": "rsxdalv",
669-
"license": "MIT",
670-
"website": "https://github.com/resemble-ai/chatterbox",
671-
"extension_website": "https://github.com/rsxdalv/extension_chatterbox",
672-
"extension_platform_version": "0.0.1"
673673
}
674674
],
675675
"decorators": [

react-ui/src/components/ChatterboxInputs.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {
1515
import { UnloadModelButton } from "./component/ModelDropdown";
1616
import { AudioInput } from "./AudioComponents";
1717
import { SeedInput } from "./SeedInput";
18+
import { Switch } from "./ui/switch";
19+
import { Label } from "./ui/label";
1820

1921
// Type alias for components that need basic params
2022
type ChatterboxBasicParams = Omit<ChatterboxParams, "audio_prompt_path"> & {
@@ -75,7 +77,7 @@ export const ChatterboxInputs = ({
7577
onChange={handleChange}
7678
label="CFG Weight/Pace"
7779
name="cfg_weight"
78-
min="0.2"
80+
min="0"
7981
max="1"
8082
step="0.05"
8183
decimals={2}
@@ -96,6 +98,13 @@ export const ChatterboxInputs = ({
9698
/>
9799
</div>
98100

101+
{/* add voice dropdown */}
102+
{/* <div className="pt-2">
103+
<VoiceDropdown
104+
params={chatterboxParams}
105+
handleChange={handleChange}
106+
/>
107+
</div> */}
99108
<div className="pt-2">
100109
<AudioInput
101110
url={chatterboxParams.audio_prompt_path?.path}
@@ -110,6 +119,22 @@ export const ChatterboxInputs = ({
110119
/>
111120
</div>
112121

122+
<div className="flex items-center space-x-2">
123+
<Switch
124+
id="chunked"
125+
checked={chatterboxParams.chunked}
126+
name="chunked"
127+
onCheckedChange={(x) =>
128+
handleChange({ target: { name: "chunked", value: x } })
129+
}
130+
/>
131+
<div>
132+
<Label htmlFor="chunked">Chunked</Label>
133+
<CardDescription>
134+
Enable chunked generation for longer prompts.
135+
</CardDescription>
136+
</div>
137+
</div>
113138
<div className="flex items-center gap-4 pt-2">
114139
<RadioWithLabel
115140
label="Device"

react-ui/src/tabs/ChatterboxParams.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface ChatterboxParams extends Seeded {
2727
device: string;
2828
dtype: string;
2929
model_name: string;
30+
chunked: boolean;
3031
}
3132

3233
export const defaultChatterboxParams: ChatterboxParams = {
@@ -40,6 +41,7 @@ export const defaultChatterboxParams: ChatterboxParams = {
4041
model_name: "just_a_placeholder",
4142
seed: -1,
4243
use_random_seed: true,
44+
chunked: false,
4345
};
4446

4547
export type ChatterboxResult = {

tts_webui/decorators/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from .decorator_add_model_type import decorator_add_model_type, decorator_add_model_type_generator
44
from .decorator_apply_torch_seed import decorator_apply_torch_seed, decorator_apply_torch_seed_generator
55
from .decorator_log_generation import decorator_log_generation, decorator_log_generation_generator
6-
from .decorator_save_metadata import decorator_save_metadata
6+
from .decorator_save_metadata import decorator_save_metadata, decorator_save_metadata_generator
77
from .decorator_save_musicgen_npz import decorator_save_musicgen_npz
88
from .decorator_save_wav import decorator_save_wav, decorator_save_wav_generator
99
from .gradio_dict_decorator import dictionarize, dictionarize_wraps

tts_webui/decorators/decorator_save_metadata.py

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,47 @@
33
from tts_webui.utils.outputs.path import get_relative_output_path_ext
44

55

6+
def _save_metadata_to_result(result_dict, kwargs):
7+
"""Helper function to save metadata to a result dictionary."""
8+
path = get_relative_output_path_ext(result_dict, ".json")
9+
print("Saving metadata to", path)
10+
11+
metadata = {
12+
"_version": "0.0.1",
13+
"_hash_version": "0.0.2",
14+
**kwargs,
15+
"outputs": None,
16+
"date": str(result_dict["date"]),
17+
"hash": audio_array_to_sha256(result_dict["audio_out"][1]),
18+
# **result_dict,
19+
}
20+
21+
with open(path, "w") as outfile:
22+
json.dump(
23+
metadata,
24+
outfile,
25+
indent=2,
26+
skipkeys=True,
27+
default=lambda o: f"<<non-serializable: {type(o).__qualname__}>>",
28+
)
29+
30+
result_dict["metadata"] = metadata
31+
return result_dict
32+
33+
634
def decorator_save_metadata(fn):
735
def wrapper(*args, **kwargs):
836
result_dict = fn(*args, **kwargs)
9-
path = get_relative_output_path_ext(result_dict, ".json")
10-
print("Saving metadata to", path)
11-
12-
metadata = {
13-
"_version": "0.0.1",
14-
"_hash_version": "0.0.2",
15-
**kwargs,
16-
"outputs": None,
17-
"date": str(result_dict["date"]),
18-
"hash": audio_array_to_sha256(result_dict["audio_out"][1]),
19-
# **result_dict,
20-
}
21-
with open(path, "w") as outfile:
22-
json.dump(
23-
metadata,
24-
outfile,
25-
indent=2,
26-
skipkeys=True,
27-
default=lambda o: f"<<non-serializable: {type(o).__qualname__}>>",
28-
)
29-
30-
result_dict["metadata"] = metadata
31-
return result_dict
37+
return _save_metadata_to_result(result_dict, kwargs)
38+
39+
return wrapper
40+
41+
42+
def decorator_save_metadata_generator(fn):
43+
def wrapper(*args, **kwargs):
44+
for result_dict in fn(*args, **kwargs):
45+
if result_dict is None:
46+
continue
47+
yield _save_metadata_to_result(result_dict, kwargs)
3248

3349
return wrapper

tts_webui/decorators/decorator_save_wav.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,24 @@ def wrapper(*args, **kwargs):
2828
yield result_dict
2929

3030
return wrapper
31+
32+
33+
def decorator_save_wav_generator_accumulated(fn):
34+
def wrapper(*args, **kwargs):
35+
accumulated_result_dict = None
36+
for result_dict in fn(*args, **kwargs):
37+
if result_dict is None:
38+
continue
39+
if accumulated_result_dict is None:
40+
accumulated_result_dict = result_dict
41+
else:
42+
accumulated_result_dict["audio_out"][1] = np.concatenate(
43+
[
44+
accumulated_result_dict["audio_out"][1],
45+
result_dict["audio_out"][1],
46+
]
47+
)
48+
yield result_dict
49+
_save_wav(accumulated_result_dict)
50+
51+
return wrapper

tts_webui/extensions_loader/decorator_extensions.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,25 @@ def wrapped(*args, **kwargs):
176176
return decorator
177177

178178

179+
def _create_decorator_generator(wrappers_list):
180+
def decorator(fn0):
181+
for wrapper in wrappers_list:
182+
fn0 = wrapper(fn0)
183+
184+
@functools.wraps(fn0)
185+
def wrapped(*args, **kwargs):
186+
yield from fn0(*args, **kwargs)
187+
188+
return wrapped
189+
190+
return decorator
191+
192+
179193
# Define the four decorators using the helper function
180194
decorator_extension_outer = _create_decorator(OUTER_WRAPPERS)
181195
decorator_extension_inner = _create_decorator(INNER_WRAPPERS)
182-
decorator_extension_outer_generator = _create_decorator(OUTER_WRAPPERS_GEN)
183-
decorator_extension_inner_generator = _create_decorator(INNER_WRAPPERS_GEN)
196+
decorator_extension_outer_generator = _create_decorator_generator(OUTER_WRAPPERS_GEN)
197+
decorator_extension_inner_generator = _create_decorator_generator(INNER_WRAPPERS_GEN)
184198

185199
if __name__ == "__main__":
186200
pass

0 commit comments

Comments
 (0)