lollms-client 0.15.1__py3-none-any.whl → 0.16.0__py3-none-any.whl
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.
Potentially problematic release.
This version of lollms-client might be problematic. Click here for more details.
- examples/generate_and_speak/generate_and_speak.py +251 -0
- examples/generate_game_sfx/generate_game_fx.py +240 -0
- examples/text_2_image.py +0 -1
- lollms_client/__init__.py +1 -1
- lollms_client/llm_bindings/llamacpp/__init__.py +561 -734
- lollms_client/lollms_core.py +49 -29
- lollms_client/lollms_stt_binding.py +3 -15
- lollms_client/lollms_tti_binding.py +5 -29
- lollms_client/lollms_ttm_binding.py +5 -28
- lollms_client/lollms_tts_binding.py +4 -28
- lollms_client/lollms_ttv_binding.py +4 -28
- lollms_client/stt_bindings/lollms/__init__.py +5 -4
- lollms_client/stt_bindings/whisper/__init__.py +304 -0
- lollms_client/stt_bindings/whispercpp/__init__.py +380 -0
- lollms_client/tti_bindings/lollms/__init__.py +4 -6
- lollms_client/ttm_bindings/audiocraft/__init__.py +281 -0
- lollms_client/ttm_bindings/bark/__init__.py +339 -0
- lollms_client/tts_bindings/bark/__init__.py +336 -0
- lollms_client/tts_bindings/piper_tts/__init__.py +343 -0
- lollms_client/tts_bindings/xtts/__init__.py +317 -0
- lollms_client-0.16.0.dist-info/METADATA +183 -0
- {lollms_client-0.15.1.dist-info → lollms_client-0.16.0.dist-info}/RECORD +25 -16
- lollms_client-0.15.1.dist-info/METADATA +0 -192
- {lollms_client-0.15.1.dist-info → lollms_client-0.16.0.dist-info}/WHEEL +0 -0
- {lollms_client-0.15.1.dist-info → lollms_client-0.16.0.dist-info}/licenses/LICENSE +0 -0
- {lollms_client-0.15.1.dist-info → lollms_client-0.16.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
# lollms_client/tts_bindings/bark/__init__.py
|
|
2
|
+
import io
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional, List, Union, Dict, Any
|
|
6
|
+
|
|
7
|
+
from ascii_colors import trace_exception, ASCIIColors
|
|
8
|
+
|
|
9
|
+
# --- Package Management and Conditional Imports ---
|
|
10
|
+
_bark_deps_installed_with_correct_torch = False
|
|
11
|
+
_bark_installation_error = ""
|
|
12
|
+
try:
|
|
13
|
+
import pipmaster as pm
|
|
14
|
+
import platform
|
|
15
|
+
|
|
16
|
+
preferred_torch_device_for_install = "cpu"
|
|
17
|
+
if platform.system() == "Linux" or platform.system() == "Windows":
|
|
18
|
+
preferred_torch_device_for_install = "cuda"
|
|
19
|
+
elif platform.system() == "Darwin":
|
|
20
|
+
preferred_torch_device_for_install = "mps"
|
|
21
|
+
|
|
22
|
+
torch_pkgs = ["torch", "torchaudio","xformers"]
|
|
23
|
+
bark_core_pkgs = ["transformers", "accelerate", "sentencepiece"]
|
|
24
|
+
other_deps = ["scipy", "numpy"]
|
|
25
|
+
|
|
26
|
+
torch_index_url = None
|
|
27
|
+
if preferred_torch_device_for_install == "cuda":
|
|
28
|
+
torch_index_url = "https://download.pytorch.org/whl/cu126"
|
|
29
|
+
ASCIIColors.info(f"Attempting to ensure PyTorch with CUDA support (target index: {torch_index_url}) for Bark TTS binding.")
|
|
30
|
+
pm.ensure_packages(torch_pkgs, index_url=torch_index_url)
|
|
31
|
+
pm.ensure_packages(bark_core_pkgs + other_deps)
|
|
32
|
+
else:
|
|
33
|
+
ASCIIColors.info("Ensuring PyTorch, Bark dependencies, and others using default PyPI index for Bark TTS binding.")
|
|
34
|
+
pm.ensure_packages(torch_pkgs + bark_core_pkgs + other_deps)
|
|
35
|
+
|
|
36
|
+
import torch
|
|
37
|
+
from transformers import AutoProcessor, BarkModel, GenerationConfig
|
|
38
|
+
import scipy.io.wavfile
|
|
39
|
+
import numpy as np
|
|
40
|
+
|
|
41
|
+
_bark_deps_installed_with_correct_torch = True
|
|
42
|
+
except Exception as e:
|
|
43
|
+
_bark_installation_error = str(e)
|
|
44
|
+
AutoProcessor, BarkModel, GenerationConfig, torch, scipy, np = None, None, None, None, None, None
|
|
45
|
+
# --- End Package Management ---
|
|
46
|
+
|
|
47
|
+
from lollms_client.lollms_tts_binding import LollmsTTSBinding # Changed base class
|
|
48
|
+
|
|
49
|
+
BindingName = "BarkTTSBinding" # Changed BindingName
|
|
50
|
+
|
|
51
|
+
# Bark model IDs (can be used as 'model_name' for this binding)
|
|
52
|
+
BARK_MODELS = [
|
|
53
|
+
"suno/bark", # Full model
|
|
54
|
+
"suno/bark-small", # Smaller, faster model
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
# Bark voice presets, used as the 'voice' argument in generate_audio
|
|
58
|
+
BARK_VOICE_PRESETS = [
|
|
59
|
+
"v2/en_speaker_0", "v2/en_speaker_1", "v2/en_speaker_2", "v2/en_speaker_3",
|
|
60
|
+
"v2/en_speaker_4", "v2/en_speaker_5", "v2/en_speaker_6", "v2/en_speaker_7",
|
|
61
|
+
"v2/en_speaker_8", "v2/en_speaker_9",
|
|
62
|
+
"v2/de_speaker_0", "v2/es_speaker_0", "v2/fr_speaker_0", "v2/hi_speaker_0",
|
|
63
|
+
"v2/it_speaker_0", "v2/ja_speaker_0", "v2/ko_speaker_0", "v2/pl_speaker_0",
|
|
64
|
+
"v2/pt_speaker_0", "v2/ru_speaker_0", "v2/tr_speaker_0", "v2/zh_speaker_0",
|
|
65
|
+
# Non-speech sounds (less relevant for pure TTS, but part of Bark's capabilities)
|
|
66
|
+
"[laughter]", "[laughs]", "[sighs]", "[music]", "[gasps]", "[clears throat]",
|
|
67
|
+
"♪", "...", "[MAN]", "[WOMAN]" # Special tokens
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class BarkTTSBinding(LollmsTTSBinding): # Changed class name and base class
|
|
72
|
+
def __init__(self,
|
|
73
|
+
model_name: str = "suno/bark-small", # This is the Bark model ID
|
|
74
|
+
default_voice: Optional[str] = "v2/en_speaker_6", # This is the default voice_preset
|
|
75
|
+
device: Optional[str] = None,
|
|
76
|
+
enable_better_transformer: bool = True,
|
|
77
|
+
host_address: Optional[str] = None, # Unused for local binding
|
|
78
|
+
service_key: Optional[str] = None, # Unused for local binding
|
|
79
|
+
verify_ssl_certificate: bool = True, # Unused for local binding
|
|
80
|
+
**kwargs):
|
|
81
|
+
|
|
82
|
+
super().__init__(binding_name="bark") # Call LollmsTTSBinding's init
|
|
83
|
+
|
|
84
|
+
if not _bark_deps_installed_with_correct_torch:
|
|
85
|
+
raise ImportError(f"Bark TTS binding dependencies not met. Error: {_bark_installation_error}")
|
|
86
|
+
|
|
87
|
+
self.device = device
|
|
88
|
+
if self.device is None:
|
|
89
|
+
if torch.cuda.is_available(): self.device = "cuda"; ASCIIColors.info("CUDA device detected by PyTorch for Bark TTS.")
|
|
90
|
+
elif hasattr(torch.backends, 'mps') and torch.backends.mps.is_available(): self.device = "mps"; ASCIIColors.info("MPS device detected for Bark TTS.")
|
|
91
|
+
else: self.device = "cpu"; ASCIIColors.info("No GPU (CUDA/MPS) by PyTorch, using CPU for Bark TTS.")
|
|
92
|
+
elif self.device == "cuda" and not torch.cuda.is_available(): self.device = "cpu"; ASCIIColors.warning("CUDA req, not avail. CPU for Bark TTS.")
|
|
93
|
+
elif self.device == "mps" and not (hasattr(torch.backends, 'mps') and torch.backends.mps.is_available()): self.device = "cpu"; ASCIIColors.warning("MPS req, not avail. CPU for Bark TTS.")
|
|
94
|
+
|
|
95
|
+
ASCIIColors.info(f"BarkTTSBinding: Using device '{self.device}'.")
|
|
96
|
+
|
|
97
|
+
self.bark_model_id = model_name # Store the actual Bark model ID separately
|
|
98
|
+
self.loaded_bark_model_id = None
|
|
99
|
+
self.model: Optional[BarkModel] = None
|
|
100
|
+
self.processor: Optional[AutoProcessor] = None
|
|
101
|
+
self.default_voice_preset = default_voice # Renamed for clarity in TTS context
|
|
102
|
+
self.enable_better_transformer = enable_better_transformer
|
|
103
|
+
|
|
104
|
+
self.default_generation_params = {}
|
|
105
|
+
temp_gen_config = GenerationConfig()
|
|
106
|
+
for key, value in kwargs.items():
|
|
107
|
+
if hasattr(temp_gen_config, key):
|
|
108
|
+
self.default_generation_params[key] = value
|
|
109
|
+
|
|
110
|
+
self._load_bark_model(self.bark_model_id)
|
|
111
|
+
|
|
112
|
+
def _load_bark_model(self, model_id_to_load: str):
|
|
113
|
+
if self.model is not None and self.loaded_bark_model_id == model_id_to_load:
|
|
114
|
+
ASCIIColors.info(f"Bark model '{model_id_to_load}' already loaded.")
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
ASCIIColors.info(f"Loading Bark model for TTS: '{model_id_to_load}' on device '{self.device}'...")
|
|
118
|
+
try:
|
|
119
|
+
dtype_for_bark = torch.float16 if self.device == "cuda" else None
|
|
120
|
+
|
|
121
|
+
self.processor = AutoProcessor.from_pretrained(model_id_to_load)
|
|
122
|
+
self.model = BarkModel.from_pretrained(
|
|
123
|
+
model_id_to_load,
|
|
124
|
+
torch_dtype=dtype_for_bark,
|
|
125
|
+
low_cpu_mem_usage=True if self.device != "cpu" else False
|
|
126
|
+
).to(self.device)
|
|
127
|
+
|
|
128
|
+
if self.enable_better_transformer and self.device == "cuda":
|
|
129
|
+
try:
|
|
130
|
+
self.model = self.model.to_bettertransformer()
|
|
131
|
+
ASCIIColors.info("Applied BetterTransformer optimization to Bark model.")
|
|
132
|
+
except Exception as e_bt:
|
|
133
|
+
ASCIIColors.warning(f"Failed to apply BetterTransformer: {e_bt}. Proceeding without it.")
|
|
134
|
+
|
|
135
|
+
# (CPU offload logic remains the same)
|
|
136
|
+
if "small" not in model_id_to_load and self.device=="cpu":
|
|
137
|
+
ASCIIColors.warning("Using full Bark model on CPU. Generation might be slow.")
|
|
138
|
+
elif self.device != "cpu" and "small" not in model_id_to_load:
|
|
139
|
+
if hasattr(self.model, "enable_model_cpu_offload"):
|
|
140
|
+
try: self.model.enable_model_cpu_offload(); ASCIIColors.info("Enabled model_cpu_offload for Bark.")
|
|
141
|
+
except Exception as e: ASCIIColors.warning(f"Could not enable model_cpu_offload: {e}")
|
|
142
|
+
elif hasattr(self.model, "enable_cpu_offload"):
|
|
143
|
+
try: self.model.enable_cpu_offload(); ASCIIColors.info("Enabled cpu_offload for Bark (older API).")
|
|
144
|
+
except Exception as e: ASCIIColors.warning(f"Could not enable cpu_offload (older API): {e}")
|
|
145
|
+
else: ASCIIColors.info("CPU offload not explicitly enabled.")
|
|
146
|
+
|
|
147
|
+
self.loaded_bark_model_id = model_id_to_load
|
|
148
|
+
ASCIIColors.green(f"Bark model '{model_id_to_load}' for TTS loaded successfully.")
|
|
149
|
+
except Exception as e:
|
|
150
|
+
self.model, self.processor, self.loaded_bark_model_id = None, None, None
|
|
151
|
+
ASCIIColors.error(f"Failed to load Bark model '{model_id_to_load}': {e}"); trace_exception(e)
|
|
152
|
+
raise RuntimeError(f"Failed to load Bark model '{model_id_to_load}'") from e
|
|
153
|
+
|
|
154
|
+
def generate_audio(self,
|
|
155
|
+
text: str,
|
|
156
|
+
voice: Optional[str] = None, # This will be the Bark voice_preset
|
|
157
|
+
do_sample: Optional[bool] = True, # Default to True for more natural speech
|
|
158
|
+
temperature: Optional[float] = 0.7, # General speech temperature
|
|
159
|
+
**kwargs) -> bytes:
|
|
160
|
+
if self.model is None or self.processor is None:
|
|
161
|
+
raise RuntimeError("Bark model or processor not loaded.")
|
|
162
|
+
|
|
163
|
+
effective_voice_preset = voice if voice is not None else self.default_voice_preset
|
|
164
|
+
if effective_voice_preset not in BARK_VOICE_PRESETS and not Path(effective_voice_preset).exists():
|
|
165
|
+
ASCIIColors.warning(f"Voice preset '{effective_voice_preset}' not in known presets. Bark will attempt to use it as is.")
|
|
166
|
+
|
|
167
|
+
ASCIIColors.info(f"Generating speech with Bark: '{text[:60]}...' (Voice Preset: {effective_voice_preset})")
|
|
168
|
+
try:
|
|
169
|
+
inputs = self.processor(text=[text], voice_preset=effective_voice_preset, return_tensors="pt")
|
|
170
|
+
inputs = {k: v.to(self.device) for k, v in inputs.items()}
|
|
171
|
+
|
|
172
|
+
if 'attention_mask' not in inputs:
|
|
173
|
+
inputs['attention_mask'] = torch.ones_like(inputs['input_ids'])
|
|
174
|
+
|
|
175
|
+
if hasattr(self.model, 'generation_config') and self.model.generation_config is not None:
|
|
176
|
+
gen_config = GenerationConfig.from_dict(self.model.generation_config.to_dict())
|
|
177
|
+
else:
|
|
178
|
+
gen_config = GenerationConfig()
|
|
179
|
+
|
|
180
|
+
for key, value in self.default_generation_params.items():
|
|
181
|
+
if hasattr(gen_config, key): setattr(gen_config, key, value)
|
|
182
|
+
|
|
183
|
+
# For TTS, do_sample is usually True
|
|
184
|
+
gen_config.do_sample = do_sample if do_sample is not None else True
|
|
185
|
+
|
|
186
|
+
# Apply general temperature hint for TTS
|
|
187
|
+
if temperature is not None:
|
|
188
|
+
# Bark's main temperatures for speech quality are often coarse and fine.
|
|
189
|
+
# Semantic temperature can also play a role.
|
|
190
|
+
if 'semantic_temperature' not in kwargs and hasattr(gen_config, 'semantic_temperature'):
|
|
191
|
+
gen_config.semantic_temperature = kwargs.get("semantic_temperature", temperature)
|
|
192
|
+
if 'coarse_temperature' not in kwargs and hasattr(gen_config, 'coarse_temperature'):
|
|
193
|
+
gen_config.coarse_temperature = kwargs.get("coarse_temperature", temperature)
|
|
194
|
+
if 'fine_temperature' not in kwargs and hasattr(gen_config, 'fine_temperature'):
|
|
195
|
+
gen_config.fine_temperature = kwargs.get("fine_temperature", temperature * 0.8) # Fine is often lower
|
|
196
|
+
|
|
197
|
+
for key, value in kwargs.items():
|
|
198
|
+
if hasattr(gen_config, key): setattr(gen_config, key, value)
|
|
199
|
+
|
|
200
|
+
pad_token_id_to_set = None
|
|
201
|
+
# (pad_token_id logic remains the same)
|
|
202
|
+
if hasattr(self.model.config, 'semantic_config') and hasattr(self.model.config.semantic_config, 'pad_token_id'):
|
|
203
|
+
pad_token_id_to_set = self.model.config.semantic_config.pad_token_id
|
|
204
|
+
elif hasattr(self.model.config, 'text_config') and hasattr(self.model.config.text_config, 'pad_token_id'):
|
|
205
|
+
pad_token_id_to_set = self.model.config.text_config.pad_token_id
|
|
206
|
+
elif hasattr(self.processor, 'tokenizer') and self.processor.tokenizer and self.processor.tokenizer.pad_token_id is not None:
|
|
207
|
+
pad_token_id_to_set = self.processor.tokenizer.pad_token_id
|
|
208
|
+
|
|
209
|
+
if pad_token_id_to_set is not None:
|
|
210
|
+
gen_config.pad_token_id = pad_token_id_to_set
|
|
211
|
+
if hasattr(gen_config, 'eos_token_id') and gen_config.eos_token_id is None:
|
|
212
|
+
eos_id = getattr(getattr(self.model.config, 'semantic_config', None), 'eos_token_id', None)
|
|
213
|
+
if eos_id is not None: gen_config.eos_token_id = eos_id
|
|
214
|
+
else:
|
|
215
|
+
ASCIIColors.warning("Could not determine pad_token_id for Bark TTS. Using default in GenerationConfig.")
|
|
216
|
+
if gen_config.eos_token_id is not None and gen_config.pad_token_id is None:
|
|
217
|
+
gen_config.pad_token_id = gen_config.eos_token_id
|
|
218
|
+
elif gen_config.pad_token_id is None:
|
|
219
|
+
gen_config.pad_token_id = 0
|
|
220
|
+
|
|
221
|
+
ASCIIColors.debug(f"Bark TTS final generation_config: {gen_config.to_json_string()}")
|
|
222
|
+
|
|
223
|
+
with torch.no_grad():
|
|
224
|
+
output = self.model.generate(
|
|
225
|
+
input_ids=inputs['input_ids'],
|
|
226
|
+
attention_mask=inputs.get('attention_mask'),
|
|
227
|
+
generation_config=gen_config
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
if isinstance(output, torch.Tensor): speech_output_tensor = output
|
|
231
|
+
elif isinstance(output, dict) and ("audio_features" in output or "waveform" in output) :
|
|
232
|
+
speech_output_tensor = output.get("waveform", output.get("audio_features"))
|
|
233
|
+
else: raise TypeError(f"Unexpected output type from BarkModel.generate: {type(output)}. Content: {output}")
|
|
234
|
+
|
|
235
|
+
audio_array_np = speech_output_tensor.cpu().numpy().squeeze()
|
|
236
|
+
if audio_array_np.ndim == 0 or audio_array_np.size == 0:
|
|
237
|
+
raise RuntimeError("Bark model returned empty audio data.")
|
|
238
|
+
|
|
239
|
+
audio_int16 = (audio_array_np * 32767).astype(np.int16)
|
|
240
|
+
|
|
241
|
+
buffer = io.BytesIO()
|
|
242
|
+
sample_rate_to_use = int(self.model.generation_config.sample_rate if hasattr(self.model.generation_config, 'sample_rate') and self.model.generation_config.sample_rate else 24_000)
|
|
243
|
+
scipy.io.wavfile.write(buffer, rate=sample_rate_to_use, data=audio_int16)
|
|
244
|
+
audio_bytes = buffer.getvalue()
|
|
245
|
+
buffer.close()
|
|
246
|
+
|
|
247
|
+
ASCIIColors.green("Bark TTS audio generation successful.")
|
|
248
|
+
return audio_bytes
|
|
249
|
+
except Exception as e:
|
|
250
|
+
ASCIIColors.error(f"Bark TTS audio generation failed: {e}"); trace_exception(e)
|
|
251
|
+
if "out of memory" in str(e).lower() and self.device == "cuda":
|
|
252
|
+
ASCIIColors.yellow("CUDA out of memory. Consider using suno/bark-small or ensure GPU has sufficient VRAM.")
|
|
253
|
+
raise RuntimeError(f"Bark TTS audio generation error: {e}") from e
|
|
254
|
+
|
|
255
|
+
def list_voices(self, **kwargs) -> List[str]: # Renamed from list_models
|
|
256
|
+
"""Lists available Bark voice presets."""
|
|
257
|
+
return BARK_VOICE_PRESETS.copy()
|
|
258
|
+
|
|
259
|
+
def get_bark_model_ids(self) -> List[str]: # Helper to list actual Bark models
|
|
260
|
+
"""Lists available Bark underlying model IDs."""
|
|
261
|
+
return BARK_MODELS.copy()
|
|
262
|
+
|
|
263
|
+
def __del__(self):
|
|
264
|
+
if hasattr(self, 'model') and self.model is not None:
|
|
265
|
+
del self.model; self.model = None
|
|
266
|
+
if hasattr(self, 'processor') and self.processor is not None:
|
|
267
|
+
del self.processor; self.processor = None
|
|
268
|
+
if torch and hasattr(torch, 'cuda') and torch.cuda.is_available():
|
|
269
|
+
torch.cuda.empty_cache()
|
|
270
|
+
loaded_name = getattr(self, 'loaded_bark_model_id', None) # Use specific attribute
|
|
271
|
+
msg = f"BarkTTSBinding for model '{loaded_name}' destroyed." if loaded_name else "BarkTTSBinding destroyed."
|
|
272
|
+
ASCIIColors.info(msg)
|
|
273
|
+
|
|
274
|
+
# --- Main Test Block ---
|
|
275
|
+
if __name__ == '__main__':
|
|
276
|
+
if not _bark_deps_installed_with_correct_torch:
|
|
277
|
+
print(f"{ASCIIColors.RED}Bark TTS binding dependencies not met. Skipping tests. Error: {_bark_installation_error}{ASCIIColors.RESET}")
|
|
278
|
+
exit()
|
|
279
|
+
|
|
280
|
+
ASCIIColors.yellow("--- BarkTTSBinding Test ---")
|
|
281
|
+
# Use bark_model_id to specify the underlying Bark model
|
|
282
|
+
test_bark_model_id = "suno/bark-small"
|
|
283
|
+
test_output_dir = Path("./test_bark_tts_output")
|
|
284
|
+
test_output_dir.mkdir(exist_ok=True)
|
|
285
|
+
tts_binding = None
|
|
286
|
+
|
|
287
|
+
try:
|
|
288
|
+
ASCIIColors.cyan(f"\n--- Initializing BarkTTSBinding (Bark Model: '{test_bark_model_id}') ---")
|
|
289
|
+
tts_binding = BarkTTSBinding(
|
|
290
|
+
model_name=test_bark_model_id, # This is the Bark model ID from HF
|
|
291
|
+
default_voice="v2/en_speaker_3" # This is the default voice_preset
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
ASCIIColors.cyan("\n--- Listing available Bark voice presets (voices) ---")
|
|
295
|
+
voices = tts_binding.list_voices(); print(f"Available voice presets (first 10): {voices[:10]}...")
|
|
296
|
+
ASCIIColors.cyan("\n--- Listing available Bark underlying model IDs ---")
|
|
297
|
+
bark_models = tts_binding.get_bark_model_ids(); print(f"Underlying Bark models: {bark_models}")
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
texts_to_synthesize = [
|
|
301
|
+
("hello_world_default_voice", "Hello world, this is a test of the Bark text to speech binding."),
|
|
302
|
+
("excited_greeting_spk6", "Wow! This is really cool! I can't believe it's working so well.", "v2/en_speaker_6"),
|
|
303
|
+
("question_spk1", "Can you generate different types of voices?", "v2/en_speaker_1"),
|
|
304
|
+
("german_example", "Hallo Welt, wie geht es dir heute?", "v2/de_speaker_0"),
|
|
305
|
+
("laughter_in_text", "This is so funny [laughter] I can't stop laughing.", "v2/en_speaker_0"), # Testing non-speech token
|
|
306
|
+
]
|
|
307
|
+
|
|
308
|
+
for name, text, *voice_arg in texts_to_synthesize:
|
|
309
|
+
voice_to_use = voice_arg[0] if voice_arg else None # Use specified voice or binding's default
|
|
310
|
+
ASCIIColors.cyan(f"\n--- Synthesizing TTS for: '{name}' (Voice: {voice_to_use or tts_binding.default_voice_preset}) ---")
|
|
311
|
+
print(f"Text: {text}")
|
|
312
|
+
try:
|
|
313
|
+
# Example of passing Bark-specific GenerationConfig params for this call
|
|
314
|
+
tts_kwargs = {"semantic_temperature": 0.6, "coarse_temperature": 0.7, "fine_temperature": 0.5}
|
|
315
|
+
if "[laughter]" in text: # Special handling for prompts with non-speech sounds
|
|
316
|
+
tts_kwargs["semantic_temperature"] = 0.8 # May need higher temp for non-speech
|
|
317
|
+
tts_kwargs["coarse_temperature"] = 0.8
|
|
318
|
+
|
|
319
|
+
audio_bytes = tts_binding.generate_audio(text, voice=voice_to_use, **tts_kwargs)
|
|
320
|
+
if audio_bytes:
|
|
321
|
+
output_filename = f"tts_{name}_{tts_binding.bark_model_id.split('/')[-1]}.wav"
|
|
322
|
+
output_path = test_output_dir / output_filename
|
|
323
|
+
with open(output_path, "wb") as f: f.write(audio_bytes)
|
|
324
|
+
ASCIIColors.green(f"TTS for '{name}' saved to: {output_path} ({len(audio_bytes) / 1024:.2f} KB)")
|
|
325
|
+
else: ASCIIColors.error(f"TTS generation for '{name}' returned empty bytes.")
|
|
326
|
+
except Exception as e_gen: ASCIIColors.error(f"Failed to generate TTS for '{name}': {e_gen}")
|
|
327
|
+
|
|
328
|
+
except ImportError as e_imp: ASCIIColors.error(f"Import error: {e_imp}")
|
|
329
|
+
except RuntimeError as e_rt: ASCIIColors.error(f"Runtime error: {e_rt}")
|
|
330
|
+
except Exception as e: ASCIIColors.error(f"Unexpected error: {e}"); trace_exception(e)
|
|
331
|
+
finally:
|
|
332
|
+
if tts_binding: del tts_binding
|
|
333
|
+
ASCIIColors.info(f"Test TTS audio (if any) are in: {test_output_dir.resolve()}")
|
|
334
|
+
print(f"{ASCIIColors.YELLOW}Check the audio files in '{test_output_dir.resolve()}'!{ASCIIColors.RESET}")
|
|
335
|
+
|
|
336
|
+
ASCIIColors.yellow("\n--- BarkTTSBinding Test Finished ---")
|