xost6377 commited on
Commit
a74e8fb
·
verified ·
1 Parent(s): f6f653d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -277
app.py CHANGED
@@ -10,39 +10,24 @@ import soundfile as sf
10
  import time
11
  from datetime import datetime
12
 
13
-
14
  def log(msg: str):
15
- """打印带时间戳的日志"""
16
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
17
  print(f"[{timestamp}] {msg}")
18
 
19
-
20
  def setup_cache_env():
21
- """
22
- Setup cache environment variables.
23
- Must be called in GPU worker context as well.
24
- """
25
  _cache_home = os.path.join(os.path.expanduser("~"), ".cache")
26
-
27
- # HuggingFace cache
28
  os.environ["HF_HOME"] = os.path.join(_cache_home, "huggingface")
29
  os.environ["HUGGINGFACE_HUB_CACHE"] = os.path.join(_cache_home, "huggingface", "hub")
30
-
31
- # ModelScope cache (for FunASR SenseVoice)
32
  os.environ["MODELSCOPE_CACHE"] = os.path.join(_cache_home, "modelscope")
33
-
34
- # Torch Hub cache (for some audio models like ZipEnhancer)
35
  os.environ["TORCH_HOME"] = os.path.join(_cache_home, "torch")
36
-
37
- # Create cache directories
38
  for d in [os.environ["HF_HOME"], os.environ["MODELSCOPE_CACHE"], os.environ["TORCH_HOME"]]:
39
  os.makedirs(d, exist_ok=True)
40
 
41
-
42
- # Setup cache in main process BEFORE any imports
43
  setup_cache_env()
44
 
45
- # Limit thread count to avoid OpenBLAS resource errors in ZeroGPU
46
  os.environ["OPENBLAS_NUM_THREADS"] = "4"
47
  os.environ["OMP_NUM_THREADS"] = "4"
48
  os.environ["MKL_NUM_THREADS"] = "4"
@@ -50,124 +35,55 @@ os.environ["TOKENIZERS_PARALLELISM"] = "false"
50
  if os.environ.get("HF_REPO_ID", "").strip() == "":
51
  os.environ["HF_REPO_ID"] = "openbmb/VoxCPM1.5"
52
 
53
- # Global model cache for ZeroGPU
54
  _asr_model = None
55
  _voxcpm_model = None
56
-
57
- # Fixed local paths for models (to avoid repeated downloads in GPU workers)
58
  ASR_LOCAL_DIR = "./models/SenseVoiceSmall"
59
  VOXCPM_LOCAL_DIR = "./models/VoxCPM1.5"
60
 
61
-
62
  def predownload_models():
63
- """
64
- Pre-download models at startup (runs in main process, not GPU worker).
65
- Download to fixed local directories so GPU workers can reuse them.
66
- """
67
- print("=" * 50)
68
- print("Pre-downloading models to local directories...")
69
- print("=" * 50)
70
-
71
- # Pre-download ASR model (SenseVoice) to fixed local directory
72
- if not os.path.isdir(ASR_LOCAL_DIR) or not os.path.exists(os.path.join(ASR_LOCAL_DIR, "model.pt")):
73
- try:
74
- from huggingface_hub import snapshot_download
75
- asr_model_id = "FunAudioLLM/SenseVoiceSmall"
76
- print(f"Pre-downloading ASR model: {asr_model_id} -> {ASR_LOCAL_DIR}")
77
- os.makedirs(ASR_LOCAL_DIR, exist_ok=True)
78
- snapshot_download(
79
- repo_id=asr_model_id,
80
- local_dir=ASR_LOCAL_DIR,
81
- )
82
- print(f"ASR model downloaded to: {ASR_LOCAL_DIR}")
83
- except Exception as e:
84
- print(f"Warning: Failed to pre-download ASR model: {e}")
85
- else:
86
- print(f"ASR model already exists at: {ASR_LOCAL_DIR}")
87
-
88
- # Pre-download VoxCPM model to fixed local directory
89
- if not os.path.isdir(VOXCPM_LOCAL_DIR) or not os.path.exists(os.path.join(VOXCPM_LOCAL_DIR, "model.safetensors")):
90
- try:
91
- from huggingface_hub import snapshot_download
92
- voxcpm_model_id = os.environ.get("HF_REPO_ID", "openbmb/VoxCPM1.5")
93
- print(f"Pre-downloading VoxCPM model: {voxcpm_model_id} -> {VOXCPM_LOCAL_DIR}")
94
- os.makedirs(VOXCPM_LOCAL_DIR, exist_ok=True)
95
- snapshot_download(
96
- repo_id=voxcpm_model_id,
97
- local_dir=VOXCPM_LOCAL_DIR,
98
- )
99
- print(f"VoxCPM model downloaded to: {VOXCPM_LOCAL_DIR}")
100
- except Exception as e:
101
- print(f"Warning: Failed to pre-download VoxCPM model: {e}")
102
- else:
103
- print(f"VoxCPM model already exists at: {VOXCPM_LOCAL_DIR}")
104
-
105
- print("=" * 50)
106
- print("Model pre-download complete!")
107
- print("=" * 50)
108
-
109
 
110
- # Run pre-download at startup
111
  predownload_models()
112
 
113
-
114
  def get_asr_model():
115
- """Lazy load ASR model from local directory."""
116
  global _asr_model
117
  if _asr_model is None:
118
  from funasr import AutoModel
119
- log("=" * 50)
120
- log(f"Loading ASR model from: {ASR_LOCAL_DIR}")
121
- start_time = time.time()
122
- _asr_model = AutoModel(
123
- model=ASR_LOCAL_DIR, # Use local directory path
124
- disable_update=True,
125
- log_level='INFO',
126
- device="cuda:0",
127
- )
128
- load_time = time.time() - start_time
129
- log(f"ASR model loaded. (耗时: {load_time:.2f}s)")
130
- log("=" * 50)
131
  return _asr_model
132
 
 
 
 
 
 
 
133
 
 
134
  def get_voxcpm_model():
135
- """Lazy load VoxCPM model (without denoiser)."""
136
  global _voxcpm_model
137
  if _voxcpm_model is None:
138
  import voxcpm
139
- log("=" * 50)
140
- log(f"Loading VoxCPM model from: {VOXCPM_LOCAL_DIR}")
141
- start_time = time.time()
142
  _voxcpm_model = voxcpm.VoxCPM(
143
- voxcpm_model_path=VOXCPM_LOCAL_DIR,
144
  optimize=False,
145
- enable_denoiser=False, # Disable denoiser to avoid ZipEnhancer download
146
  )
147
- load_time = time.time() - start_time
148
- log(f"VoxCPM model loaded. (耗时: {load_time:.2f}s)")
149
- log("=" * 50)
 
150
  return _voxcpm_model
151
 
152
-
153
- @spaces.GPU(duration=120)
154
- def prompt_wav_recognition(prompt_wav: Optional[str]) -> str:
155
- """Use ASR to recognize prompt audio text."""
156
- if prompt_wav is None or not prompt_wav.strip():
157
- return ""
158
- log("=" * 50)
159
- log("[ASR] 开始语音识别...")
160
- asr_model = get_asr_model()
161
- start_time = time.time()
162
- res = asr_model.generate(input=prompt_wav, language="auto", use_itn=True)
163
- inference_time = time.time() - start_time
164
- text = res[0]["text"].split('|>')[-1]
165
- log(f"[ASR] 识别结果: {text}")
166
- log(f"[ASR] 推理耗时: {inference_time:.2f}s")
167
- log("=" * 50)
168
- return text
169
-
170
-
171
  @spaces.GPU(duration=120)
172
  def generate_tts_audio_gpu(
173
  text_input: str,
@@ -177,20 +93,11 @@ def generate_tts_audio_gpu(
177
  inference_timesteps_input: int = 10,
178
  do_normalize: bool = True,
179
  ) -> Tuple[int, np.ndarray]:
180
- """
181
- GPU function: Generate speech from text using VoxCPM.
182
- prompt_wav_data is (audio_array, sample_rate) tuple.
183
- """
184
  voxcpm_model = get_voxcpm_model()
185
-
186
  text = (text_input or "").strip()
187
- if len(text) == 0:
188
- raise ValueError("Please input text to synthesize.")
189
 
190
- prompt_text = prompt_text_input if prompt_text_input else None
191
  prompt_wav_path = None
192
-
193
- # If prompt audio data provided, write to temp file for voxcpm
194
  if prompt_wav_data is not None:
195
  audio_array, sr = prompt_wav_data
196
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
@@ -198,33 +105,20 @@ def generate_tts_audio_gpu(
198
  prompt_wav_path = f.name
199
 
200
  try:
201
- log("=" * 50)
202
- log("[TTS] 开始语音合成...")
203
- log(f"[TTS] 目标文本: {text}")
204
- start_time = time.time()
205
  wav = voxcpm_model.generate(
206
  text=text,
207
- prompt_text=prompt_text,
208
  prompt_wav_path=prompt_wav_path,
209
  cfg_value=float(cfg_value_input),
210
  inference_timesteps=int(inference_timesteps_input),
211
  normalize=do_normalize,
212
- denoise=False, # Denoiser disabled
213
  )
214
- inference_time = time.time() - start_time
215
- audio_duration = len(wav) / voxcpm_model.tts_model.sample_rate
216
- rtf = inference_time / audio_duration if audio_duration > 0 else 0
217
- log(f"[TTS] 推理耗时: {inference_time:.2f}s | 音频时长: {audio_duration:.2f}s | RTF: {rtf:.3f}")
218
- log("=" * 50)
219
  return (voxcpm_model.tts_model.sample_rate, wav)
220
  finally:
221
- # Cleanup temp file
222
  if prompt_wav_path and os.path.exists(prompt_wav_path):
223
- try:
224
- os.unlink(prompt_wav_path)
225
- except Exception:
226
- pass
227
-
228
 
229
  def generate_tts_audio(
230
  text_input: str,
@@ -234,179 +128,56 @@ def generate_tts_audio(
234
  inference_timesteps_input: int = 10,
235
  do_normalize: bool = True,
236
  ) -> Tuple[int, np.ndarray]:
237
- """
238
- Wrapper: Read audio file in CPU, then call GPU function.
239
- """
240
  prompt_wav_data = None
241
-
242
- # Read audio file before entering GPU context
243
  if prompt_wav_path_input and os.path.exists(prompt_wav_path_input):
244
  try:
245
  audio_array, sr = sf.read(prompt_wav_path_input, dtype='float32')
246
  prompt_wav_data = (audio_array, sr)
247
- print(f"Loaded prompt audio: {audio_array.shape}, sr={sr}")
248
- except Exception as e:
249
- print(f"Warning: Failed to load prompt audio: {e}")
250
- prompt_wav_data = None
251
-
252
  return generate_tts_audio_gpu(
253
  text_input=text_input,
254
  prompt_wav_data=prompt_wav_data,
255
  prompt_text_input=prompt_text_input,
256
  cfg_value_input=cfg_value_input,
257
  inference_timesteps_input=inference_timesteps_input,
258
- do_normalize=do_normalize,
259
  )
260
 
261
-
262
- # ---------- UI Builders ----------
263
-
264
  def create_demo_interface():
265
- """Build the Gradio UI for VoxCPM demo."""
266
- # static assets (logo path)
267
  try:
268
- gr.set_static_paths(paths=[Path.cwd().absolute()/"assets"])
269
- except Exception:
270
- pass
271
-
272
- with gr.Blocks(
273
- theme=gr.themes.Soft(
274
- primary_hue="blue",
275
- secondary_hue="gray",
276
- neutral_hue="slate",
277
- font=[gr.themes.GoogleFont("Inter"), "Arial", "sans-serif"]
278
- ),
279
- css="""
280
- .logo-container {
281
- text-align: center;
282
- margin: 0.5rem 0 1rem 0;
283
- }
284
- .logo-container img {
285
- height: 80px;
286
- width: auto;
287
- max-width: 200px;
288
- display: inline-block;
289
- }
290
- /* Bold accordion labels */
291
- #acc_quick details > summary,
292
- #acc_tips details > summary {
293
- font-weight: 600 !important;
294
- font-size: 1.1em !important;
295
- }
296
- /* Bold labels for specific checkboxes */
297
- #chk_denoise label,
298
- #chk_denoise span,
299
- #chk_normalize label,
300
- #chk_normalize span {
301
- font-weight: 600;
302
- }
303
- """
304
- ) as interface:
305
- # Header logo
306
- gr.HTML('<div class="logo-container"><img src="/gradio_api/file=assets/voxcpm-logo.png" alt="VoxCPM Logo"></div>')
307
-
308
- # Quick Start
309
- with gr.Accordion("📋 Quick Start Guide |快速入门", open=False, elem_id="acc_quick"):
310
- gr.Markdown("""
311
- ### How to Use |使用说明
312
- 1. **(Optional) Provide a Voice Prompt** - Upload or record an audio clip to provide the desired voice characteristics for synthesis.
313
- **(可选)提供参考声音** - 上传或录制一段音频,为声音合成提供音色、语调和情感等个性化特征
314
- 2. **(Optional) Enter prompt text** - If you provided a voice prompt, enter the corresponding transcript here (auto-recognition available).
315
- **(可选项)输入参考文本** - 如果提供了参考语音,请输入其对应的文本内容(支持自动识别)。
316
- 3. **Enter target text** - Type the text you want the model to speak.
317
- **输入目标文本** - 输入您希望模型朗读的文字内容。
318
- 4. **Generate Speech** - Click the "Generate" button to create your audio.
319
- **生成语音** - 点击"生成"按钮,即可为您创造出音频。
320
- """)
321
 
322
- # Pro Tips
323
- with gr.Accordion("💡 Pro Tips |使用建议", open=False, elem_id="acc_tips"):
324
- gr.Markdown("""
325
- ### Text Normalization|文本正则化
326
- - **Enable** to process general text with an external WeTextProcessing component.
327
- **启用**:使用 WeTextProcessing 组件,可支持常见文本的正则化处理。
328
- - **Disable** to use VoxCPM's native text understanding ability. For example, it supports phonemes input (For Chinese, phonemes are converted using pinyin, {ni3}{hao3}; For English, phonemes are converted using CMUDict, {HH AH0 L OW1}), try it!
329
- **禁用**:将使用 VoxCPM 内置的文本理解能力。如,支持音素输入(如中文转拼音:{ni3}{hao3};英文转CMUDict:{HH AH0 L OW1})和公式符号合成,尝试一下!
330
 
331
- ### CFG Value|CFG 值
332
- - **Lower CFG** if the voice prompt sounds strained or expressive, or instability occurs with long text input.
333
- **调低**:如果提示语音听起来不自然或过于夸张,或者长文本输入出现稳定性问题。
334
- - **Higher CFG** for better adherence to the prompt speech style or input text, or instability occurs with too short text input.
335
- **调高**:为更好地贴合提示音频的风格或输入文本, 或者极短文本输入出现稳定性问题。
336
-
337
- ### Inference Timesteps|推理时间步
338
- - **Lower** for faster synthesis speed.
339
- **调低**:合成速度更快。
340
- - **Higher** for better synthesis quality.
341
- **调高**:合成质量更佳。
342
- """)
343
-
344
- # Main controls
345
  with gr.Row():
346
  with gr.Column():
347
- prompt_wav = gr.Audio(
348
- sources=["upload", 'microphone'],
349
- type="filepath",
350
- label="Prompt Speech (Optional, or let VoxCPM improvise)",
351
- value="./examples/example.wav",
352
- )
353
- with gr.Row():
354
- prompt_text = gr.Textbox(
355
- value="Just by listening a few minutes a day, you'll be able to eliminate negative thoughts by conditioning your mind to be more positive.",
356
- label="Prompt Text",
357
- placeholder="Please enter the prompt text. Automatic recognition is supported, and you can correct the results yourself..."
358
- )
359
  run_btn = gr.Button("Generate Speech", variant="primary")
360
 
361
  with gr.Column():
362
- cfg_value = gr.Slider(
363
- minimum=1.0,
364
- maximum=3.0,
365
- value=2.0,
366
- step=0.1,
367
- label="CFG Value (Guidance Scale)",
368
- info="Higher values increase adherence to prompt, lower values allow more creativity"
369
- )
370
- inference_timesteps = gr.Slider(
371
- minimum=4,
372
- maximum=30,
373
- value=10,
374
- step=1,
375
- label="Inference Timesteps",
376
- info="Number of inference timesteps for generation (higher values may improve quality but slower)"
377
- )
378
- with gr.Row():
379
- text = gr.Textbox(
380
- value="VoxCPM is an innovative end-to-end TTS model from ModelBest, designed to generate highly realistic speech.",
381
- label="Target Text",
382
- )
383
- with gr.Row():
384
- DoNormalizeText = gr.Checkbox(
385
- value=False,
386
- label="Text Normalization",
387
- elem_id="chk_normalize",
388
- info="We use wetext library to normalize the input text."
389
- )
390
  audio_output = gr.Audio(label="Output Audio")
391
 
392
- # Wiring
393
  run_btn.click(
394
  fn=generate_tts_audio,
395
  inputs=[text, prompt_wav, prompt_text, cfg_value, inference_timesteps, DoNormalizeText],
396
  outputs=[audio_output],
397
- show_progress=True,
398
- api_name="generate",
399
  )
400
  prompt_wav.change(fn=prompt_wav_recognition, inputs=[prompt_wav], outputs=[prompt_text])
401
 
402
  return interface
403
 
404
-
405
- def run_demo(server_name: str = "0.0.0.0", server_port: int = 7860, show_error: bool = True):
406
  interface = create_demo_interface()
407
- # Recommended to enable queue on Spaces for better throughput
408
- interface.queue(max_size=10).launch(server_name=server_name, server_port=server_port, show_error=show_error)
409
-
410
 
411
  if __name__ == "__main__":
412
  run_demo()
 
10
  import time
11
  from datetime import datetime
12
 
13
+ # --------------------- 日志 ---------------------
14
  def log(msg: str):
 
15
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
16
  print(f"[{timestamp}] {msg}")
17
 
18
+ # --------------------- 缓存环境 ---------------------
19
  def setup_cache_env():
 
 
 
 
20
  _cache_home = os.path.join(os.path.expanduser("~"), ".cache")
 
 
21
  os.environ["HF_HOME"] = os.path.join(_cache_home, "huggingface")
22
  os.environ["HUGGINGFACE_HUB_CACHE"] = os.path.join(_cache_home, "huggingface", "hub")
 
 
23
  os.environ["MODELSCOPE_CACHE"] = os.path.join(_cache_home, "modelscope")
 
 
24
  os.environ["TORCH_HOME"] = os.path.join(_cache_home, "torch")
 
 
25
  for d in [os.environ["HF_HOME"], os.environ["MODELSCOPE_CACHE"], os.environ["TORCH_HOME"]]:
26
  os.makedirs(d, exist_ok=True)
27
 
 
 
28
  setup_cache_env()
29
 
30
+ # --------------------- 限制线程 ---------------------
31
  os.environ["OPENBLAS_NUM_THREADS"] = "4"
32
  os.environ["OMP_NUM_THREADS"] = "4"
33
  os.environ["MKL_NUM_THREADS"] = "4"
 
35
  if os.environ.get("HF_REPO_ID", "").strip() == "":
36
  os.environ["HF_REPO_ID"] = "openbmb/VoxCPM1.5"
37
 
38
+ # --------------------- 模型全局缓存 ---------------------
39
  _asr_model = None
40
  _voxcpm_model = None
 
 
41
  ASR_LOCAL_DIR = "./models/SenseVoiceSmall"
42
  VOXCPM_LOCAL_DIR = "./models/VoxCPM1.5"
43
 
44
+ # --------------------- 预下载模型 ---------------------
45
  def predownload_models():
46
+ from huggingface_hub import snapshot_download
47
+ if not os.path.isdir(ASR_LOCAL_DIR):
48
+ os.makedirs(ASR_LOCAL_DIR, exist_ok=True)
49
+ snapshot_download(repo_id="FunAudioLLM/SenseVoiceSmall", local_dir=ASR_LOCAL_DIR)
50
+ if not os.path.isdir(VOXCPM_LOCAL_DIR):
51
+ os.makedirs(VOXCPM_LOCAL_DIR, exist_ok=True)
52
+ snapshot_download(repo_id=os.environ.get("HF_REPO_ID", "openbmb/VoxCPM1.5"), local_dir=VOXCPM_LOCAL_DIR)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
 
54
  predownload_models()
55
 
56
+ # --------------------- ASR ---------------------
57
  def get_asr_model():
 
58
  global _asr_model
59
  if _asr_model is None:
60
  from funasr import AutoModel
61
+ _asr_model = AutoModel(model=ASR_LOCAL_DIR, disable_update=True, log_level='INFO', device="cpu")
 
 
 
 
 
 
 
 
 
 
 
62
  return _asr_model
63
 
64
+ @spaces.GPU(duration=120)
65
+ def prompt_wav_recognition(prompt_wav: Optional[str]) -> str:
66
+ if not prompt_wav: return ""
67
+ asr_model = get_asr_model()
68
+ res = asr_model.generate(input=prompt_wav, language="auto", use_itn=True)
69
+ return res[0]["text"].split('|>')[-1]
70
 
71
+ # --------------------- VoxCPM TTS ---------------------
72
  def get_voxcpm_model():
 
73
  global _voxcpm_model
74
  if _voxcpm_model is None:
75
  import voxcpm
 
 
 
76
  _voxcpm_model = voxcpm.VoxCPM(
77
+ voxcpm_model_path=VOXCPM_LOCAL_DIR,
78
  optimize=False,
79
+ enable_denoiser=False
80
  )
81
+ # CPU 强制 float32
82
+ _voxcpm_model.to(dtype=torch.float32, device="cpu")
83
+ # 禁用内部 GQA 避免 CPU 报错
84
+ _voxcpm_model.tts_model.enable_gqa = False
85
  return _voxcpm_model
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  @spaces.GPU(duration=120)
88
  def generate_tts_audio_gpu(
89
  text_input: str,
 
93
  inference_timesteps_input: int = 10,
94
  do_normalize: bool = True,
95
  ) -> Tuple[int, np.ndarray]:
 
 
 
 
96
  voxcpm_model = get_voxcpm_model()
 
97
  text = (text_input or "").strip()
98
+ if not text: raise ValueError("Please input text to synthesize.")
 
99
 
 
100
  prompt_wav_path = None
 
 
101
  if prompt_wav_data is not None:
102
  audio_array, sr = prompt_wav_data
103
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
 
105
  prompt_wav_path = f.name
106
 
107
  try:
 
 
 
 
108
  wav = voxcpm_model.generate(
109
  text=text,
110
+ prompt_text=prompt_text_input,
111
  prompt_wav_path=prompt_wav_path,
112
  cfg_value=float(cfg_value_input),
113
  inference_timesteps=int(inference_timesteps_input),
114
  normalize=do_normalize,
115
+ denoise=False
116
  )
 
 
 
 
 
117
  return (voxcpm_model.tts_model.sample_rate, wav)
118
  finally:
 
119
  if prompt_wav_path and os.path.exists(prompt_wav_path):
120
+ try: os.unlink(prompt_wav_path)
121
+ except: pass
 
 
 
122
 
123
  def generate_tts_audio(
124
  text_input: str,
 
128
  inference_timesteps_input: int = 10,
129
  do_normalize: bool = True,
130
  ) -> Tuple[int, np.ndarray]:
 
 
 
131
  prompt_wav_data = None
 
 
132
  if prompt_wav_path_input and os.path.exists(prompt_wav_path_input):
133
  try:
134
  audio_array, sr = sf.read(prompt_wav_path_input, dtype='float32')
135
  prompt_wav_data = (audio_array, sr)
136
+ except: pass
 
 
 
 
137
  return generate_tts_audio_gpu(
138
  text_input=text_input,
139
  prompt_wav_data=prompt_wav_data,
140
  prompt_text_input=prompt_text_input,
141
  cfg_value_input=cfg_value_input,
142
  inference_timesteps_input=inference_timesteps_input,
143
+ do_normalize=do_normalize
144
  )
145
 
146
+ # --------------------- Gradio UI ---------------------
 
 
147
  def create_demo_interface():
 
 
148
  try:
149
+ gr.set_static_paths(paths=[Path.cwd()/"assets"])
150
+ except: pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue")) as interface:
153
+ gr.HTML('<div style="text-align:center;"><h2>VoxCPM CPU TTS Demo</h2></div>')
 
 
 
 
 
 
154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  with gr.Row():
156
  with gr.Column():
157
+ prompt_wav = gr.Audio(sources=["upload","microphone"], type="filepath", label="Prompt Speech (Optional)")
158
+ prompt_text = gr.Textbox(label="Prompt Text", placeholder="Optional")
159
+ text = gr.Textbox(label="Target Text", placeholder="Enter text to synthesize")
 
 
 
 
 
 
 
 
 
160
  run_btn = gr.Button("Generate Speech", variant="primary")
161
 
162
  with gr.Column():
163
+ cfg_value = gr.Slider(1.0,3.0,value=2.0,step=0.1,label="CFG Value")
164
+ inference_timesteps = gr.Slider(4,30,value=10,step=1,label="Inference Timesteps")
165
+ DoNormalizeText = gr.Checkbox(value=False,label="Text Normalization")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  audio_output = gr.Audio(label="Output Audio")
167
 
 
168
  run_btn.click(
169
  fn=generate_tts_audio,
170
  inputs=[text, prompt_wav, prompt_text, cfg_value, inference_timesteps, DoNormalizeText],
171
  outputs=[audio_output],
172
+ show_progress=True
 
173
  )
174
  prompt_wav.change(fn=prompt_wav_recognition, inputs=[prompt_wav], outputs=[prompt_text])
175
 
176
  return interface
177
 
178
+ def run_demo(server_name="0.0.0.0", server_port=7860):
 
179
  interface = create_demo_interface()
180
+ interface.queue(max_size=10).launch(server_name=server_name, server_port=server_port)
 
 
181
 
182
  if __name__ == "__main__":
183
  run_demo()