Update app.py
Browse files
app.py
CHANGED
|
@@ -49,82 +49,70 @@ LANGUAGE_MAP = {
|
|
| 49 |
# CHUNK TEXT - Chia văn bản thành các đoạn nhỏ theo câu/đoạn
|
| 50 |
# ============================================================================
|
| 51 |
|
| 52 |
-
def split_into_chunks(text: str
|
| 53 |
"""
|
| 54 |
-
Chia văn bản thành các chunk theo câu
|
| 55 |
-
|
| 56 |
-
|
|
|
|
|
|
|
|
|
|
| 57 |
"""
|
| 58 |
text = text.strip()
|
| 59 |
if not text:
|
| 60 |
return []
|
| 61 |
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
paragraphs = re.split(r'\n\s*\n', text)
|
| 67 |
|
| 68 |
-
|
|
|
|
| 69 |
para = para.strip()
|
| 70 |
if not para:
|
| 71 |
continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
continue
|
| 76 |
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
else:
|
| 96 |
-
if current:
|
| 97 |
-
chunks.append(current)
|
| 98 |
-
# Nếu part vẫn quá dài, chia theo từ
|
| 99 |
-
if len(part) > max_chars:
|
| 100 |
-
words = part.split()
|
| 101 |
-
current = ""
|
| 102 |
-
for w in words:
|
| 103 |
-
if len(current) + len(w) + 1 <= max_chars:
|
| 104 |
-
current = (current + " " + w).strip()
|
| 105 |
-
else:
|
| 106 |
-
if current:
|
| 107 |
-
chunks.append(current)
|
| 108 |
-
current = w
|
| 109 |
-
else:
|
| 110 |
-
current = part
|
| 111 |
else:
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
current = sent
|
| 118 |
-
|
| 119 |
-
if current:
|
| 120 |
chunks.append(current)
|
|
|
|
| 121 |
|
| 122 |
-
|
|
|
|
| 123 |
|
|
|
|
| 124 |
|
| 125 |
-
# ============================================================================
|
| 126 |
-
# AUDIO UTILS
|
| 127 |
-
# ============================================================================
|
| 128 |
|
| 129 |
def _normalize_audio(wav, eps=1e-12, clip=True):
|
| 130 |
"""Chuẩn hóa âm thanh về float32 trong khoảng [-1, 1]."""
|
|
@@ -269,11 +257,11 @@ def wrap_chunk_area(inner_html: str) -> str:
|
|
| 269 |
# HELPER: Preview chunks trước khi xử lý
|
| 270 |
# ============================================================================
|
| 271 |
|
| 272 |
-
def preview_chunks(text: str
|
| 273 |
"""Hiển thị preview danh sách chunks sẽ được tạo."""
|
| 274 |
if not text or not text.strip():
|
| 275 |
return "<p style='color:#9ca3af; font-style:italic; padding:8px;'>Nhập văn bản để xem trước các đoạn...</p>"
|
| 276 |
-
chunks = split_into_chunks(text.strip()
|
| 277 |
if not chunks:
|
| 278 |
return "<p style='color:#9ca3af;'>Không có đoạn nào.</p>"
|
| 279 |
rows = ""
|
|
@@ -355,7 +343,7 @@ def _run_chunked(chunks, generate_fn, total):
|
|
| 355 |
yield all_audio, html_blocks, f"✅ Hoàn tất {total} đoạn.", total
|
| 356 |
|
| 357 |
|
| 358 |
-
def generate_voice_design_chunked(text, language, voice_description
|
| 359 |
"""Tạo giọng nói theo từng chunk - Voice Design (1.7B)."""
|
| 360 |
if not text or not text.strip():
|
| 361 |
yield None, "Lỗi: Văn bản là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Văn bản là bắt buộc.</p>")
|
|
@@ -364,7 +352,7 @@ def generate_voice_design_chunked(text, language, voice_description, chunk_size)
|
|
| 364 |
yield None, "Lỗi: Mô tả giọng nói là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Mô tả giọng nói là bắt buộc.</p>")
|
| 365 |
return
|
| 366 |
|
| 367 |
-
chunks = split_into_chunks(text.strip()
|
| 368 |
total = len(chunks)
|
| 369 |
lang_en = LANGUAGE_MAP.get(language, "Auto")
|
| 370 |
|
|
@@ -392,7 +380,7 @@ def generate_voice_design_chunked(text, language, voice_description, chunk_size)
|
|
| 392 |
yield out_audio, status, wrap_chunk_area("".join(html_blocks))
|
| 393 |
|
| 394 |
|
| 395 |
-
def generate_voice_clone_chunked(ref_audio, ref_text, target_text, language, use_xvector_only, model_size
|
| 396 |
"""Tạo giọng nói theo từng chunk - Voice Clone (Base)."""
|
| 397 |
if not target_text or not target_text.strip():
|
| 398 |
yield None, "Lỗi: Văn bản cần đọc là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Văn bản cần đọc là bắt buộc.</p>")
|
|
@@ -407,7 +395,7 @@ def generate_voice_clone_chunked(ref_audio, ref_text, target_text, language, use
|
|
| 407 |
yield None, "Lỗi: Văn bản tham chiếu là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Văn bản tham chiếu là bắt buộc.</p>")
|
| 408 |
return
|
| 409 |
|
| 410 |
-
chunks = split_into_chunks(target_text.strip()
|
| 411 |
total = len(chunks)
|
| 412 |
lang_en = LANGUAGE_MAP.get(language, "Auto")
|
| 413 |
|
|
@@ -437,7 +425,7 @@ def generate_voice_clone_chunked(ref_audio, ref_text, target_text, language, use
|
|
| 437 |
yield out_audio, status, wrap_chunk_area("".join(html_blocks))
|
| 438 |
|
| 439 |
|
| 440 |
-
def generate_custom_voice_chunked(text, language, speaker, instruct, model_size
|
| 441 |
"""Tạo giọng nói theo từng chunk - CustomVoice."""
|
| 442 |
if not text or not text.strip():
|
| 443 |
yield None, "Lỗi: Văn bản là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Văn bản là bắt buộc.</p>")
|
|
@@ -446,7 +434,7 @@ def generate_custom_voice_chunked(text, language, speaker, instruct, model_size,
|
|
| 446 |
yield None, "Lỗi: Giọng đọc là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Giọng đọc là bắt buộc.</p>")
|
| 447 |
return
|
| 448 |
|
| 449 |
-
chunks = split_into_chunks(text.strip()
|
| 450 |
total = len(chunks)
|
| 451 |
lang_en = LANGUAGE_MAP.get(language, "Auto")
|
| 452 |
|
|
@@ -479,17 +467,6 @@ def generate_custom_voice_chunked(text, language, speaker, instruct, model_size,
|
|
| 479 |
# UI
|
| 480 |
# ============================================================================
|
| 481 |
|
| 482 |
-
def _chunk_controls():
|
| 483 |
-
"""Controls cài đặt chia đoạn tái sử dụng."""
|
| 484 |
-
with gr.Accordion("⚙️ Cài đặt chia đoạn", open=False):
|
| 485 |
-
chunk_size = gr.Slider(
|
| 486 |
-
label="Số ký tự tối đa mỗi đoạn",
|
| 487 |
-
minimum=50, maximum=500, value=200, step=10,
|
| 488 |
-
info="Văn bản tự động chia ở dấu câu gần nhất trước giới hạn này. Số đoạn không giới hạn."
|
| 489 |
-
)
|
| 490 |
-
return chunk_size
|
| 491 |
-
|
| 492 |
-
|
| 493 |
def _chunk_output_area(tab_id: str):
|
| 494 |
"""Output area: audio tổng hợp + status + HTML preview từng chunk."""
|
| 495 |
audio_out = gr.Audio(
|
|
@@ -548,7 +525,6 @@ Hỗ trợ văn bản **không giới hạn độ dài** — tự động chia c
|
|
| 548 |
placeholder="Ví dụ: Giọng ngạc nhiên, lo lắng, bắt đầu hoảng loạn...",
|
| 549 |
value="Giọng ngạc nhiên, không tin tưởng, bắt đầu có chút hoảng loạn."
|
| 550 |
)
|
| 551 |
-
d_chunk_size = _chunk_controls()
|
| 552 |
with gr.Row():
|
| 553 |
d_preview_btn = gr.Button("🔍 Xem trước các đoạn", variant="secondary")
|
| 554 |
d_gen_btn = gr.Button("▶ Tạo giọng nói", variant="primary", scale=2)
|
|
@@ -558,12 +534,12 @@ Hỗ trợ văn bản **không giới hạn độ dài** — tự động chia c
|
|
| 558 |
|
| 559 |
d_preview_btn.click(
|
| 560 |
fn=lambda t, cs: preview_chunks(t, cs),
|
| 561 |
-
inputs=[d_text
|
| 562 |
outputs=[d_chunk_html],
|
| 563 |
)
|
| 564 |
d_gen_btn.click(
|
| 565 |
fn=generate_voice_design_chunked,
|
| 566 |
-
inputs=[d_text, d_language, d_instruct
|
| 567 |
outputs=[d_audio_out, d_status, d_chunk_html],
|
| 568 |
)
|
| 569 |
|
|
@@ -599,7 +575,6 @@ Hỗ trợ văn bản **không giới hạn độ dài** — tự động chia c
|
|
| 599 |
c_model_size = gr.Dropdown(
|
| 600 |
label="Kích thước mô hình", choices=MODEL_SIZES, value="0.6B", interactive=True
|
| 601 |
)
|
| 602 |
-
c_chunk_size = _chunk_controls()
|
| 603 |
with gr.Row():
|
| 604 |
c_preview_btn = gr.Button("🔍 Xem trước các đoạn", variant="secondary")
|
| 605 |
c_gen_btn = gr.Button("▶ Nhân bản & Tạo", variant="primary", scale=2)
|
|
@@ -609,12 +584,12 @@ Hỗ trợ văn bản **không giới hạn độ dài** — tự động chia c
|
|
| 609 |
|
| 610 |
c_preview_btn.click(
|
| 611 |
fn=lambda t, cs: preview_chunks(t, cs),
|
| 612 |
-
inputs=[c_target_text
|
| 613 |
outputs=[c_chunk_html],
|
| 614 |
)
|
| 615 |
c_gen_btn.click(
|
| 616 |
fn=generate_voice_clone_chunked,
|
| 617 |
-
inputs=[c_ref_audio, c_ref_text, c_target_text, c_language, c_xvector, c_model_size
|
| 618 |
outputs=[c_audio_out, c_status, c_chunk_html],
|
| 619 |
)
|
| 620 |
|
|
@@ -651,7 +626,6 @@ Hỗ trợ văn bản **không giới hạn độ dài** — tự động chia c
|
|
| 651 |
t_model_size = gr.Dropdown(
|
| 652 |
label="Kích thước mô hình", choices=MODEL_SIZES, value="0.6B", interactive=True
|
| 653 |
)
|
| 654 |
-
t_chunk_size = _chunk_controls()
|
| 655 |
with gr.Row():
|
| 656 |
t_preview_btn = gr.Button("🔍 Xem trước các đoạn", variant="secondary")
|
| 657 |
t_gen_btn = gr.Button("▶ Tạo giọng nói", variant="primary", scale=2)
|
|
@@ -661,12 +635,12 @@ Hỗ trợ văn bản **không giới hạn độ dài** — tự động chia c
|
|
| 661 |
|
| 662 |
t_preview_btn.click(
|
| 663 |
fn=lambda t, cs: preview_chunks(t, cs),
|
| 664 |
-
inputs=[t_text
|
| 665 |
outputs=[t_chunk_html],
|
| 666 |
)
|
| 667 |
t_gen_btn.click(
|
| 668 |
fn=generate_custom_voice_chunked,
|
| 669 |
-
inputs=[t_text, t_language, t_speaker, t_instruct, t_model_size
|
| 670 |
outputs=[t_audio_out, t_status, t_chunk_html],
|
| 671 |
)
|
| 672 |
|
|
|
|
| 49 |
# CHUNK TEXT - Chia văn bản thành các đoạn nhỏ theo câu/đoạn
|
| 50 |
# ============================================================================
|
| 51 |
|
| 52 |
+
def split_into_chunks(text: str) -> list:
|
| 53 |
"""
|
| 54 |
+
Chia văn bản thành các chunk thông minh theo dấu câu.
|
| 55 |
+
Quy tắc:
|
| 56 |
+
- Tách thành câu tại dấu kết thúc câu (.!?… và tương đương CJK).
|
| 57 |
+
- Gom câu ngắn (<60 ký tự) vào chunk hiện tại.
|
| 58 |
+
- Flush chunk khi đã đủ dài (>= 80 ký tự) và câu tiếp theo cũng tự đứng được (>= 30 ký tự).
|
| 59 |
+
- Tôn trọng ngắt đoạn (dòng trống) — luôn flush trước đoạn mới.
|
| 60 |
"""
|
| 61 |
text = text.strip()
|
| 62 |
if not text:
|
| 63 |
return []
|
| 64 |
|
| 65 |
+
SENT_SPLIT = re.compile(r'(?<=[.!?\u2026\u3002\uff01\uff1f])\s+')
|
| 66 |
+
FLUSH_LEN = 100 # flush chunk khi đạt độ dài này
|
| 67 |
+
SHORT_SENT = 40 # câu ngắn hơn ngưỡng này luôn được gom vào chunk trước
|
| 68 |
+
MAX_LEN = 200 # không để chunk vượt quá ngưỡng này dù câu tiếp có ngắn
|
|
|
|
| 69 |
|
| 70 |
+
raw_sents = []
|
| 71 |
+
for para in re.split(r'\n\s*\n', text):
|
| 72 |
para = para.strip()
|
| 73 |
if not para:
|
| 74 |
continue
|
| 75 |
+
sents = [s.strip() for s in SENT_SPLIT.split(para) if s.strip()]
|
| 76 |
+
if sents:
|
| 77 |
+
# Đánh dấu câu cuối của mỗi đoạn để flush
|
| 78 |
+
raw_sents.extend(sents[:-1])
|
| 79 |
+
raw_sents.append(("PARA_END", sents[-1]))
|
| 80 |
|
| 81 |
+
if not raw_sents:
|
| 82 |
+
return [text]
|
|
|
|
| 83 |
|
| 84 |
+
chunks = []
|
| 85 |
+
current = ""
|
| 86 |
+
|
| 87 |
+
for item in raw_sents:
|
| 88 |
+
is_para_end = isinstance(item, tuple)
|
| 89 |
+
sent = item[1] if is_para_end else item
|
| 90 |
+
|
| 91 |
+
if not current:
|
| 92 |
+
current = sent
|
| 93 |
+
else:
|
| 94 |
+
combined = current + " " + sent
|
| 95 |
+
# Gom nếu: chunk hiện tại còn ngắn HOẶC câu tiếp theo quá ngắn để đứng riêng
|
| 96 |
+
if len(combined) > MAX_LEN:
|
| 97 |
+
# Câu tiếp quá dài để gom — flush ngay
|
| 98 |
+
chunks.append(current)
|
| 99 |
+
current = sent
|
| 100 |
+
elif len(current) < FLUSH_LEN or len(sent) < SHORT_SENT:
|
| 101 |
+
current = combined
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
else:
|
| 103 |
+
chunks.append(current)
|
| 104 |
+
current = sent
|
| 105 |
+
|
| 106 |
+
# Flush tại cuối đoạn
|
| 107 |
+
if is_para_end and current:
|
|
|
|
|
|
|
|
|
|
| 108 |
chunks.append(current)
|
| 109 |
+
current = ""
|
| 110 |
|
| 111 |
+
if current:
|
| 112 |
+
chunks.append(current)
|
| 113 |
|
| 114 |
+
return [c for c in chunks if c.strip()]
|
| 115 |
|
|
|
|
|
|
|
|
|
|
| 116 |
|
| 117 |
def _normalize_audio(wav, eps=1e-12, clip=True):
|
| 118 |
"""Chuẩn hóa âm thanh về float32 trong khoảng [-1, 1]."""
|
|
|
|
| 257 |
# HELPER: Preview chunks trước khi xử lý
|
| 258 |
# ============================================================================
|
| 259 |
|
| 260 |
+
def preview_chunks(text: str) -> str:
|
| 261 |
"""Hiển thị preview danh sách chunks sẽ được tạo."""
|
| 262 |
if not text or not text.strip():
|
| 263 |
return "<p style='color:#9ca3af; font-style:italic; padding:8px;'>Nhập văn bản để xem trước các đoạn...</p>"
|
| 264 |
+
chunks = split_into_chunks(text.strip())
|
| 265 |
if not chunks:
|
| 266 |
return "<p style='color:#9ca3af;'>Không có đoạn nào.</p>"
|
| 267 |
rows = ""
|
|
|
|
| 343 |
yield all_audio, html_blocks, f"✅ Hoàn tất {total} đoạn.", total
|
| 344 |
|
| 345 |
|
| 346 |
+
def generate_voice_design_chunked(text, language, voice_description):
|
| 347 |
"""Tạo giọng nói theo từng chunk - Voice Design (1.7B)."""
|
| 348 |
if not text or not text.strip():
|
| 349 |
yield None, "Lỗi: Văn bản là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Văn bản là bắt buộc.</p>")
|
|
|
|
| 352 |
yield None, "Lỗi: Mô tả giọng nói là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Mô tả giọng nói là bắt buộc.</p>")
|
| 353 |
return
|
| 354 |
|
| 355 |
+
chunks = split_into_chunks(text.strip())
|
| 356 |
total = len(chunks)
|
| 357 |
lang_en = LANGUAGE_MAP.get(language, "Auto")
|
| 358 |
|
|
|
|
| 380 |
yield out_audio, status, wrap_chunk_area("".join(html_blocks))
|
| 381 |
|
| 382 |
|
| 383 |
+
def generate_voice_clone_chunked(ref_audio, ref_text, target_text, language, use_xvector_only, model_size):
|
| 384 |
"""Tạo giọng nói theo từng chunk - Voice Clone (Base)."""
|
| 385 |
if not target_text or not target_text.strip():
|
| 386 |
yield None, "Lỗi: Văn bản cần đọc là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Văn bản cần đọc là bắt buộc.</p>")
|
|
|
|
| 395 |
yield None, "Lỗi: Văn bản tham chiếu là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Văn bản tham chiếu là bắt buộc.</p>")
|
| 396 |
return
|
| 397 |
|
| 398 |
+
chunks = split_into_chunks(target_text.strip())
|
| 399 |
total = len(chunks)
|
| 400 |
lang_en = LANGUAGE_MAP.get(language, "Auto")
|
| 401 |
|
|
|
|
| 425 |
yield out_audio, status, wrap_chunk_area("".join(html_blocks))
|
| 426 |
|
| 427 |
|
| 428 |
+
def generate_custom_voice_chunked(text, language, speaker, instruct, model_size):
|
| 429 |
"""Tạo giọng nói theo từng chunk - CustomVoice."""
|
| 430 |
if not text or not text.strip():
|
| 431 |
yield None, "Lỗi: Văn bản là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Văn bản là bắt buộc.</p>")
|
|
|
|
| 434 |
yield None, "Lỗi: Giọng đọc là bắt buộc.", wrap_chunk_area("<p style='color:red'>Lỗi: Giọng đọc là bắt buộc.</p>")
|
| 435 |
return
|
| 436 |
|
| 437 |
+
chunks = split_into_chunks(text.strip())
|
| 438 |
total = len(chunks)
|
| 439 |
lang_en = LANGUAGE_MAP.get(language, "Auto")
|
| 440 |
|
|
|
|
| 467 |
# UI
|
| 468 |
# ============================================================================
|
| 469 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 470 |
def _chunk_output_area(tab_id: str):
|
| 471 |
"""Output area: audio tổng hợp + status + HTML preview từng chunk."""
|
| 472 |
audio_out = gr.Audio(
|
|
|
|
| 525 |
placeholder="Ví dụ: Giọng ngạc nhiên, lo lắng, bắt đầu hoảng loạn...",
|
| 526 |
value="Giọng ngạc nhiên, không tin tưởng, bắt đầu có chút hoảng loạn."
|
| 527 |
)
|
|
|
|
| 528 |
with gr.Row():
|
| 529 |
d_preview_btn = gr.Button("🔍 Xem trước các đoạn", variant="secondary")
|
| 530 |
d_gen_btn = gr.Button("▶ Tạo giọng nói", variant="primary", scale=2)
|
|
|
|
| 534 |
|
| 535 |
d_preview_btn.click(
|
| 536 |
fn=lambda t, cs: preview_chunks(t, cs),
|
| 537 |
+
inputs=[d_text],
|
| 538 |
outputs=[d_chunk_html],
|
| 539 |
)
|
| 540 |
d_gen_btn.click(
|
| 541 |
fn=generate_voice_design_chunked,
|
| 542 |
+
inputs=[d_text, d_language, d_instruct],
|
| 543 |
outputs=[d_audio_out, d_status, d_chunk_html],
|
| 544 |
)
|
| 545 |
|
|
|
|
| 575 |
c_model_size = gr.Dropdown(
|
| 576 |
label="Kích thước mô hình", choices=MODEL_SIZES, value="0.6B", interactive=True
|
| 577 |
)
|
|
|
|
| 578 |
with gr.Row():
|
| 579 |
c_preview_btn = gr.Button("🔍 Xem trước các đoạn", variant="secondary")
|
| 580 |
c_gen_btn = gr.Button("▶ Nhân bản & Tạo", variant="primary", scale=2)
|
|
|
|
| 584 |
|
| 585 |
c_preview_btn.click(
|
| 586 |
fn=lambda t, cs: preview_chunks(t, cs),
|
| 587 |
+
inputs=[c_target_text],
|
| 588 |
outputs=[c_chunk_html],
|
| 589 |
)
|
| 590 |
c_gen_btn.click(
|
| 591 |
fn=generate_voice_clone_chunked,
|
| 592 |
+
inputs=[c_ref_audio, c_ref_text, c_target_text, c_language, c_xvector, c_model_size],
|
| 593 |
outputs=[c_audio_out, c_status, c_chunk_html],
|
| 594 |
)
|
| 595 |
|
|
|
|
| 626 |
t_model_size = gr.Dropdown(
|
| 627 |
label="Kích thước mô hình", choices=MODEL_SIZES, value="0.6B", interactive=True
|
| 628 |
)
|
|
|
|
| 629 |
with gr.Row():
|
| 630 |
t_preview_btn = gr.Button("🔍 Xem trước các đoạn", variant="secondary")
|
| 631 |
t_gen_btn = gr.Button("▶ Tạo giọng nói", variant="primary", scale=2)
|
|
|
|
| 635 |
|
| 636 |
t_preview_btn.click(
|
| 637 |
fn=lambda t, cs: preview_chunks(t, cs),
|
| 638 |
+
inputs=[t_text],
|
| 639 |
outputs=[t_chunk_html],
|
| 640 |
)
|
| 641 |
t_gen_btn.click(
|
| 642 |
fn=generate_custom_voice_chunked,
|
| 643 |
+
inputs=[t_text, t_language, t_speaker, t_instruct, t_model_size],
|
| 644 |
outputs=[t_audio_out, t_status, t_chunk_html],
|
| 645 |
)
|
| 646 |
|