xjsc0 commited on
Commit
7389d4c
·
1 Parent(s): ffbb4ab

修复了一些已知问题

Browse files
Files changed (1) hide show
  1. app.py +141 -65
app.py CHANGED
@@ -123,8 +123,6 @@ def mix_vocal_and_accompaniment(
123
 
124
  # ---------------------------------------------------------------------------
125
  # Inference wrapper / 推理入口
126
- # Single @spaces.GPU scope covers ALL heavy work (separation + synthesis)
127
- # so models stay resident in GPU memory across steps within one call.
128
  # ---------------------------------------------------------------------------
129
  @spaces.GPU
130
  def synthesize(
@@ -140,16 +138,8 @@ def synthesize(
140
  cfg_strength,
141
  seed,
142
  ):
143
- """
144
- 主合成流程 / Main synthesis pipeline.
145
-
146
- 1. (可选) 用 MelBandRoformer 分离参考音频和旋律音频的人声与伴奏
147
- 2. 送入 YingMusicSinger 合成
148
- 3. (可选) 将合成人声与旋律音频的伴奏混合
149
- """
150
  import random
151
 
152
- # ---- 输入校验 / Input validation ----------------------------------------
153
  if ref_audio is None:
154
  raise gr.Error("请上传参考音频 / Please upload Reference Audio")
155
  if melody_audio is None:
@@ -168,7 +158,6 @@ def synthesize(
168
  if actual_seed < 0:
169
  actual_seed = random.randint(0, 2**31 - 1)
170
 
171
- # ---- Step 1: 人声分离(合并在同一 GPU 上下文中)/ Vocal separation (same GPU context) ----
172
  melody_accomp_path = None
173
  actual_ref_path = ref_audio_path
174
  actual_melody_path = melody_audio_path
@@ -180,7 +169,6 @@ def synthesize(
180
  melody_vocals_path, melody_accomp_path = _separate_vocals_impl(melody_audio_path)
181
  actual_melody_path = melody_vocals_path
182
 
183
- # ---- Step 2: 模型推理 / Model inference (same GPU context) ---------------
184
  model = _load_model_impl()
185
 
186
  audio_tensor, sr = model(
@@ -199,7 +187,6 @@ def synthesize(
199
  vocal_out_path = os.path.join(tempfile.mkdtemp(), "vocal_output.wav")
200
  torchaudio.save(vocal_out_path, audio_tensor.to("cpu"), sample_rate=sr)
201
 
202
- # ---- Step 3: 混合伴奏 / Mix accompaniment (optional) ---------------------
203
  if (
204
  separate_vocals_flag
205
  and mix_accompaniment_flag
@@ -215,66 +202,138 @@ def synthesize(
215
  # Example presets / 预设示例
216
  # ---------------------------------------------------------------------------
217
  EXAMPLES_MELODY_CONTROL = [
218
- # [ref_audio, melody_audio, ref_text, target_text, sep, mix, sil, t_shift, nfe, cfg, seed]
219
  [
220
- "examples/melody_control/ref_01.wav",
221
- "examples/melody_control/melody_01.wav",
222
- "该体谅不执着|如果那天我",
223
- "好多天|看不完你",
224
- True, False, 0.5, 0.5, 32, 3.0, -1,
225
  ],
226
  [
227
- "examples/melody_control/ref_02.wav",
228
- "examples/melody_control/melody_02.wav",
229
- "月光下的身影|渐渐模糊",
230
- "星光照亮前路|指引方向",
231
- True, False, 0.5, 0.5, 32, 3.0, -1,
232
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  ]
234
 
235
  EXAMPLES_LYRIC_EDIT = [
236
  [
237
- "examples/lyric_edit/ref_01.wav",
238
- "examples/lyric_edit/melody_01.wav",
239
- "该体谅的不执着|如果那天我",
240
- "忘不掉的笑容|心里面",
241
- True, False, 0.5, 0.5, 32, 3.0, -1,
242
  ],
243
  [
244
- "examples/lyric_edit/ref_02.wav",
245
- "examples/lyric_edit/melody_02.wav",
246
- "夜深了还不睡|想着你的脸",
247
- "春风又吹过来|带走我思念",
248
- True, False, 0.5, 0.5, 32, 3.0, -1,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  ],
250
  ]
251
 
252
 
253
  # ---------------------------------------------------------------------------
254
  # Custom CSS / 自定义样式
 
 
 
 
 
255
  # ---------------------------------------------------------------------------
256
  CUSTOM_CSS = """
257
  @import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,500;0,9..40,700;1,9..40,400&family=Playfair+Display:wght@600;800&display=swap');
258
 
259
  :root {
260
- --primary: #e85d04;
261
- --primary-light: #f48c06;
 
 
262
  --bg-dark: #0d1117;
263
  --surface: #161b22;
264
  --surface-light: #21262d;
265
  --text: #f0f6fc;
266
  --text-muted: #8b949e;
267
- --accent-glow: rgba(232, 93, 4, 0.15);
268
  --border: #30363d;
269
  }
270
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  .gradio-container {
272
  font-family: 'DM Sans', sans-serif !important;
273
  max-width: 1100px !important;
274
  margin: auto !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  }
276
 
277
- /* ---------- Badge links: no underline, no gap artifacts ---------- */
278
  #app-header .badges a {
279
  text-decoration: none !important;
280
  display: inline-block;
@@ -291,7 +350,7 @@ CUSTOM_CSS = """
291
  line-height: 1.8;
292
  }
293
 
294
- /* ---------- Header / 头部 ---------- */
295
  #app-header {
296
  text-align: center;
297
  padding: 1.8rem 1rem 0.5rem;
@@ -341,17 +400,23 @@ CUSTOM_CSS = """
341
  font-weight: 600;
342
  }
343
 
344
- /* ---------- Section labels / 分区标题 ---------- */
345
  .section-title {
346
  font-family: 'DM Sans', sans-serif !important;
347
  font-weight: 700 !important;
348
  font-size: 1rem !important;
349
  letter-spacing: 0.06em;
350
  text-transform: uppercase;
351
- color: var(--primary-light) !important;
352
- border-bottom: 2px solid var(--primary);
353
- padding-bottom: 6px;
354
- margin-bottom: 12px !important;
 
 
 
 
 
 
355
  }
356
 
357
  /* ---------- Example tabs ---------- */
@@ -360,29 +425,44 @@ CUSTOM_CSS = """
360
  font-size: 0.95rem !important;
361
  }
362
 
363
- /* ---------- Run button / 合成按钮 ---------- */
364
  #run-btn {
365
- background: linear-gradient(135deg, #e85d04, #dc2f02) !important;
366
  border: none !important;
367
- color: #fff !important;
368
  font-weight: 700 !important;
369
  font-size: 1.1rem !important;
370
  letter-spacing: 0.04em;
371
  padding: 12px 0 !important;
372
  border-radius: 10px !important;
373
  transition: transform 0.15s, box-shadow 0.25s !important;
374
- box-shadow: 0 4px 20px rgba(232, 93, 4, 0.35) !important;
375
  }
376
  #run-btn:hover {
377
  transform: translateY(-1px) !important;
378
- box-shadow: 0 6px 28px rgba(232, 93, 4, 0.5) !important;
379
  }
380
 
381
- /* ---------- Output audio / 输出音频 ---------- */
382
  #output-audio {
383
- border: 2px solid var(--primary) !important;
384
  border-radius: 12px !important;
385
- background: var(--accent-glow) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  }
387
  """
388
 
@@ -490,7 +570,7 @@ def build_ui():
490
  )
491
 
492
  # ================================================================
493
- # ROW 2 – 预设示例 / Example Presets ← before vocal separation
494
  # ================================================================
495
  gr.HTML("<hr style='border-color:#30363d; margin: 16px 0 12px;'>")
496
  gr.Markdown("#### 🎵 预设示例 / Example Presets", elem_classes="section-title")
@@ -498,8 +578,6 @@ def build_ui():
498
  "<small style='color:#8b949e;'>点击任意行自动填入上方输入区域 / Click any row to auto-fill the inputs above</small>"
499
  )
500
 
501
- # Hidden advanced-param components so gr.Examples can reference them
502
- # (real sliders rendered inside the accordion below override these values)
503
  with gr.Row(visible=False):
504
  _sep_flag_ex = gr.Checkbox(value=True)
505
  _mix_flag_ex = gr.Checkbox(value=False)
@@ -532,16 +610,19 @@ def build_ui():
532
  )
533
 
534
  # ================================================================
535
- # ROW 3 – 伴奏分离 / Vocal Separation
536
  # ================================================================
537
  gr.HTML("<hr style='border-color:#30363d; margin: 16px 0 12px;'>")
538
  gr.Markdown("#### 🎚️ 伴奏分离 / Vocal Separation", elem_classes="section-title")
 
 
 
539
  gr.HTML("""
540
  <div style="font-size:0.85rem; color:#8b949e; line-height:1.75; margin: 0 0 12px; padding: 10px 16px;
541
  background: rgba(255,255,255,0.03); border-radius: 8px; border: 1px solid #21262d;">
542
  <ul style="margin:0; padding-left:1.2em; list-style: none;">
543
  <li style="margin-bottom:7px;">
544
- 💡 若输入的<b style="color:#c9d1d9;">参考音频</b>或<b style="color:#c9d1d9;">旋律音频</b>中含有伴奏或背景噪音,请开启「分离人声后过模型」—— 模型基于纯人声训练,混合音频会影响合成质量。<br>
545
  <span style="color:#6e7681; font-size:0.82rem;">If either input contains accompaniment or background noise, enable <i>Separate vocals before synthesis</i> — the model is trained on clean vocals only and mixed audio degrades quality.</span>
546
  </li>
547
  <li style="margin-bottom:7px;">
@@ -549,7 +630,7 @@ def build_ui():
549
  <span style="color:#6e7681; font-size:0.82rem;">If both inputs are already clean vocals, skip separation — enabling it unnecessarily may introduce artifacts from the separation model.</span>
550
  </li>
551
  <li>
552
- 💡 若旋律音频含有伴奏,开启「分离人声后过模型」后,最终输出是否保留伴奏由「输出时混入伴奏」控制。<br>
553
  <span style="color:#6e7681; font-size:0.82rem;">If the melody audio contains accompaniment and separation is enabled, use <i>Mix accompaniment into output</i> to decide whether to include it in the final result.</span>
554
  </li>
555
  </ul>
@@ -597,7 +678,7 @@ def build_ui():
597
  )
598
 
599
  # ================================================================
600
- # ROW 5 – 合成按钮与输出 / Run & Output
601
  # ================================================================
602
  gr.HTML("<hr style='border-color:#30363d; margin: 12px 0;'>")
603
  run_btn = gr.Button("🎤 开始合成 / Start Synthesizing", elem_id="run-btn", size="lg")
@@ -608,16 +689,12 @@ def build_ui():
608
  elem_id="output-audio",
609
  )
610
 
611
- # All inputs for the synthesize() call (uses real sliders, not example placeholders)
612
  _all_inputs = [
613
  ref_audio, melody_audio, ref_text, target_text,
614
  separate_vocals_flag, mix_accompaniment_flag,
615
  sil_len_to_end, t_shift, nfe_step, cfg_strength, seed,
616
  ]
617
 
618
- # ================================================================
619
- # Event wiring / 事件绑定
620
- # ================================================================
621
  separate_vocals_flag.change(
622
  fn=lambda sep: gr.update(interactive=sep, value=False),
623
  inputs=[separate_vocals_flag],
@@ -630,14 +707,13 @@ def build_ui():
630
  outputs=output_audio,
631
  )
632
 
633
- # ---- 页脚:免责声明 / Footer: disclaimer ----
634
  gr.HTML(DISCLAIMER_HTML)
635
 
636
  return demo
637
 
638
 
639
  # ---------------------------------------------------------------------------
640
- # Entry point / 启动入口
641
  # ---------------------------------------------------------------------------
642
  if __name__ == "__main__":
643
  demo = build_ui()
 
123
 
124
  # ---------------------------------------------------------------------------
125
  # Inference wrapper / 推理入口
 
 
126
  # ---------------------------------------------------------------------------
127
  @spaces.GPU
128
  def synthesize(
 
138
  cfg_strength,
139
  seed,
140
  ):
 
 
 
 
 
 
 
141
  import random
142
 
 
143
  if ref_audio is None:
144
  raise gr.Error("请上传参考音频 / Please upload Reference Audio")
145
  if melody_audio is None:
 
158
  if actual_seed < 0:
159
  actual_seed = random.randint(0, 2**31 - 1)
160
 
 
161
  melody_accomp_path = None
162
  actual_ref_path = ref_audio_path
163
  actual_melody_path = melody_audio_path
 
169
  melody_vocals_path, melody_accomp_path = _separate_vocals_impl(melody_audio_path)
170
  actual_melody_path = melody_vocals_path
171
 
 
172
  model = _load_model_impl()
173
 
174
  audio_tensor, sr = model(
 
187
  vocal_out_path = os.path.join(tempfile.mkdtemp(), "vocal_output.wav")
188
  torchaudio.save(vocal_out_path, audio_tensor.to("cpu"), sample_rate=sr)
189
 
 
190
  if (
191
  separate_vocals_flag
192
  and mix_accompaniment_flag
 
202
  # Example presets / 预设示例
203
  # ---------------------------------------------------------------------------
204
  EXAMPLES_MELODY_CONTROL = [
 
205
  [
206
+ "examples/hf_space/melody_control/melody_control_ZH_01_timbre.wav",
207
+ "examples/hf_space/melody_control/melody_control_ZH_01_melody.wav",
208
+ "人和人沟通|有时候没有用",
209
+ "此刻记忆中的点滴啊|能否再次被珍藏",
210
+ True, True, 0.5, 0.5, 32, 3.0, -1,
211
  ],
212
  [
213
+ "examples/hf_space/melody_control/melody_control_EN_01_timbre.wav",
214
+ "examples/hf_space/melody_control/melody_control_EN_01_melody.wav",
215
+ "i don't know feel|but i wanna try",
216
+ "won't open the door|and say tomorrow",
217
+ True, True, 0.5, 0.5, 32, 3.0, -1,
218
  ],
219
+ [
220
+ "examples/hf_space/melody_control/melody_control_EN_02_timbre.wav",
221
+ "examples/hf_space/melody_control/melody_control_EN_02_melody.wav",
222
+ "and she'll never know your story like|i do",
223
+ "你将安然无恙|无人能再伤你",
224
+ False, False, 0.5, 0.5, 32, 3.0, -1,
225
+ ],
226
+ [
227
+ "examples/hf_space/melody_control/melody_control_ZH_02_timbre.wav",
228
+ "examples/hf_space/melody_control/melody_control_ZH_02_melody.wav",
229
+ "就让你|在别人怀里|快乐",
230
+ "Missing you in my mind|missing you in my heart",
231
+ False, False, 0.5, 0.5, 32, 3.0, -1,
232
+ ]
233
  ]
234
 
235
  EXAMPLES_LYRIC_EDIT = [
236
  [
237
+ "examples/hf_space/lyric_edit/SingEdit_ZH_01.wav",
238
+ "examples/hf_space/lyric_edit/SingEdit_ZH_01.wav",
239
+ "天青色等烟雨|而在等你|炊烟袅袅升起",
240
+ "阳光中赏花香|花瓣飘落|山间幽静致远",
241
+ True, True, 0.5, 0.5, 32, 3.0, -1,
242
  ],
243
  [
244
+ "examples/hf_space/lyric_edit/SingEdit_EN_01.wav",
245
+ "examples/hf_space/lyric_edit/SingEdit_EN_01.wav",
246
+ "can you tell my heart is speaking|my eyes will give you clues",
247
+ "can you spot the moon is grinning|my lips will show you hints",
248
+ True, True, 0.5, 0.5, 32, 3.0, -1,
249
+ ],
250
+ [
251
+ "examples/hf_space/lyric_edit/SingEdit_ZH_02.wav",
252
+ "examples/hf_space/lyric_edit/SingEdit_ZH_02.wav",
253
+ "歌声是翅膀|唱出了希望|所有的付出只因爱的力量|和你一样",
254
+ "火锅是梦想|煮出了欢畅|全部的辛劳全因肉的力量|与汤一样",
255
+ False, False, 0.5, 0.5, 32, 3.0, -1,
256
+ ],
257
+ [
258
+ "examples/hf_space/lyric_edit/SingEdit_EN_02.wav",
259
+ "examples/hf_space/lyric_edit/SingEdit_EN_02.wav",
260
+ "i can hear what you say|now i know|why know we can|make it",
261
+ "i can see where you go|but i say|why not we will|break it",
262
+ False, False, 0.5, 0.5, 32, 3.0, -1,
263
  ],
264
  ]
265
 
266
 
267
  # ---------------------------------------------------------------------------
268
  # Custom CSS / 自定义样式
269
+ # CHANGES:
270
+ # 1. Top gradient bar using palette colors
271
+ # 2. Section titles: left-bar accent instead of bottom border
272
+ # 3. Color palette updated to #FE9EC7 / #F9F6C4 / #89D4FF / #44ACFF
273
+ # 4. Vocal-sep info box: reference/melody text use palette colors
274
  # ---------------------------------------------------------------------------
275
  CUSTOM_CSS = """
276
  @import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,500;0,9..40,700;1,9..40,400&family=Playfair+Display:wght@600;800&display=swap');
277
 
278
  :root {
279
+ --primary: #44ACFF;
280
+ --primary-light: #89D4FF;
281
+ --primary-warm: #FE9EC7;
282
+ --palette-yellow: #F9F6C4;
283
  --bg-dark: #0d1117;
284
  --surface: #161b22;
285
  --surface-light: #21262d;
286
  --text: #f0f6fc;
287
  --text-muted: #8b949e;
288
+ --accent-glow: rgba(68, 172, 255, 0.10);
289
  --border: #30363d;
290
  }
291
 
292
+ /* ========== 1. TOP GRADIENT BAR ========== */
293
+ /* Inject a full-width gradient strip at the very top of the page */
294
+ body > gradio-app::before,
295
+ .gradio-container > *:first-child::before {
296
+ content: '';
297
+ display: block;
298
+ height: 0;
299
+ }
300
+
301
+ /* Use a pseudo-element on the outermost wrapper Gradio renders */
302
+ .app.svelte-182fdeq::before,
303
+ footer ~ *::before {
304
+ display: none;
305
+ }
306
+
307
+ /* Reliable approach: prepend a fixed bar via the container's outline */
308
  .gradio-container {
309
  font-family: 'DM Sans', sans-serif !important;
310
  max-width: 1100px !important;
311
  margin: auto !important;
312
+ /* top gradient bar using outline trick */
313
+ outline: none;
314
+ position: relative;
315
+ }
316
+
317
+ .gradio-container::before {
318
+ content: '';
319
+ display: block;
320
+ position: absolute;
321
+ top: 0;
322
+ left: 0;
323
+ right: 0;
324
+ height: 5px;
325
+ background: linear-gradient(90deg,
326
+ #FE9EC7 0%,
327
+ #F9F6C4 33%,
328
+ #89D4FF 66%,
329
+ #44ACFF 100%
330
+ );
331
+ border-radius: 3px 3px 0 0;
332
+ z-index: 100;
333
+ pointer-events: none;
334
  }
335
 
336
+ /* ---------- Badge links ---------- */
337
  #app-header .badges a {
338
  text-decoration: none !important;
339
  display: inline-block;
 
350
  line-height: 1.8;
351
  }
352
 
353
+ /* ---------- Header ---------- */
354
  #app-header {
355
  text-align: center;
356
  padding: 1.8rem 1rem 0.5rem;
 
400
  font-weight: 600;
401
  }
402
 
403
+ /* ========== 2. Section labels: left accent bar instead of bottom border ========== */
404
  .section-title {
405
  font-family: 'DM Sans', sans-serif !important;
406
  font-weight: 700 !important;
407
  font-size: 1rem !important;
408
  letter-spacing: 0.06em;
409
  text-transform: uppercase;
410
+ color: var(--primary) !important;
411
+ /* Remove the old bottom-border horizontal line */
412
+ border-bottom: none !important;
413
+ /* Replace with a left accent bar */
414
+ border-left: 4px solid var(--primary-warm) !important;
415
+ padding: 3px 0 3px 10px !important;
416
+ margin-bottom: 14px !important;
417
+ background: linear-gradient(90deg, rgba(254,158,199,0.08) 0%, transparent 70%) !important;
418
+ border-radius: 0 4px 4px 0 !important;
419
+ display: block;
420
  }
421
 
422
  /* ---------- Example tabs ---------- */
 
425
  font-size: 0.95rem !important;
426
  }
427
 
428
+ /* ========== 3. Run button palette blue ========== */
429
  #run-btn {
430
+ background: linear-gradient(135deg, #44ACFF, #89D4FF) !important;
431
  border: none !important;
432
+ color: #0a1628 !important;
433
  font-weight: 700 !important;
434
  font-size: 1.1rem !important;
435
  letter-spacing: 0.04em;
436
  padding: 12px 0 !important;
437
  border-radius: 10px !important;
438
  transition: transform 0.15s, box-shadow 0.25s !important;
439
+ box-shadow: 0 4px 20px rgba(68, 172, 255, 0.35) !important;
440
  }
441
  #run-btn:hover {
442
  transform: translateY(-1px) !important;
443
+ box-shadow: 0 6px 28px rgba(68, 172, 255, 0.5) !important;
444
  }
445
 
446
+ /* ---------- Output audio ---------- */
447
  #output-audio {
448
+ border: 2px solid #44ACFF !important;
449
  border-radius: 12px !important;
450
+ background: rgba(68, 172, 255, 0.07) !important;
451
+ }
452
+
453
+ /* ========== 4. Vocal-sep info box: fix highlighted text colors ========== */
454
+ /* Target the <b> tags inside the vocal separation info box */
455
+ .vocal-sep-info b {
456
+ /* default fallback */
457
+ color: #c9d1d9;
458
+ font-weight: 700;
459
+ }
460
+ /* Specifically target ref audio and melody audio highlights via data-color */
461
+ b[data-ref] {
462
+ color: #FE9EC7 !important;
463
+ }
464
+ b[data-melody] {
465
+ color: #89D4FF !important;
466
  }
467
  """
468
 
 
570
  )
571
 
572
  # ================================================================
573
+ # ROW 2 – 预设示例
574
  # ================================================================
575
  gr.HTML("<hr style='border-color:#30363d; margin: 16px 0 12px;'>")
576
  gr.Markdown("#### 🎵 预设示例 / Example Presets", elem_classes="section-title")
 
578
  "<small style='color:#8b949e;'>点击任意行自动填入上方输入区域 / Click any row to auto-fill the inputs above</small>"
579
  )
580
 
 
 
581
  with gr.Row(visible=False):
582
  _sep_flag_ex = gr.Checkbox(value=True)
583
  _mix_flag_ex = gr.Checkbox(value=False)
 
610
  )
611
 
612
  # ================================================================
613
+ # ROW 3 – 伴奏分离
614
  # ================================================================
615
  gr.HTML("<hr style='border-color:#30363d; margin: 16px 0 12px;'>")
616
  gr.Markdown("#### 🎚️ 伴奏分离 / Vocal Separation", elem_classes="section-title")
617
+
618
+ # CHANGE 4: Use inline style colors for 参考音频 and 旋律音频
619
+ # so they render correctly regardless of CSS specificity issues
620
  gr.HTML("""
621
  <div style="font-size:0.85rem; color:#8b949e; line-height:1.75; margin: 0 0 12px; padding: 10px 16px;
622
  background: rgba(255,255,255,0.03); border-radius: 8px; border: 1px solid #21262d;">
623
  <ul style="margin:0; padding-left:1.2em; list-style: none;">
624
  <li style="margin-bottom:7px;">
625
+ 💡 若输入的<b style="color:#FE9EC7; font-weight:700;">参考音频</b>或<b style="color:#89D4FF; font-weight:700;">旋律音频</b>中含有伴奏或背景噪音,请开启「分离人声后过模型」—— 模型基于纯人声训练,混合音频会影响合成质量。<br>
626
  <span style="color:#6e7681; font-size:0.82rem;">If either input contains accompaniment or background noise, enable <i>Separate vocals before synthesis</i> — the model is trained on clean vocals only and mixed audio degrades quality.</span>
627
  </li>
628
  <li style="margin-bottom:7px;">
 
630
  <span style="color:#6e7681; font-size:0.82rem;">If both inputs are already clean vocals, skip separation — enabling it unnecessarily may introduce artifacts from the separation model.</span>
631
  </li>
632
  <li>
633
+ 💡 若<b style="color:#89D4FF; font-weight:700;">旋律音频</b>含有伴奏,开启「分离人声后过模型」后,最终输出是否保留伴奏由「输出时混入伴奏」控制。<br>
634
  <span style="color:#6e7681; font-size:0.82rem;">If the melody audio contains accompaniment and separation is enabled, use <i>Mix accompaniment into output</i> to decide whether to include it in the final result.</span>
635
  </li>
636
  </ul>
 
678
  )
679
 
680
  # ================================================================
681
+ # ROW 5 – 合成按钮与输出
682
  # ================================================================
683
  gr.HTML("<hr style='border-color:#30363d; margin: 12px 0;'>")
684
  run_btn = gr.Button("🎤 开始合成 / Start Synthesizing", elem_id="run-btn", size="lg")
 
689
  elem_id="output-audio",
690
  )
691
 
 
692
  _all_inputs = [
693
  ref_audio, melody_audio, ref_text, target_text,
694
  separate_vocals_flag, mix_accompaniment_flag,
695
  sil_len_to_end, t_shift, nfe_step, cfg_strength, seed,
696
  ]
697
 
 
 
 
698
  separate_vocals_flag.change(
699
  fn=lambda sep: gr.update(interactive=sep, value=False),
700
  inputs=[separate_vocals_flag],
 
707
  outputs=output_audio,
708
  )
709
 
 
710
  gr.HTML(DISCLAIMER_HTML)
711
 
712
  return demo
713
 
714
 
715
  # ---------------------------------------------------------------------------
716
+ # Entry point
717
  # ---------------------------------------------------------------------------
718
  if __name__ == "__main__":
719
  demo = build_ui()