LTTEAM_TTS / app.py
LTTEAM's picture
Update app.py
bb36424 verified
import os
import random
import numpy as np
import torch
from pathlib import Path
# Đảm bảo torch.load luôn map về CPU khi cần
_orig_torch_load = torch.load
def _torch_load_cpu(f, *args, **kwargs):
if "map_location" not in kwargs:
kwargs["map_location"] = torch.device("cpu")
return _orig_torch_load(f, *args, **kwargs)
torch.load = _torch_load_cpu
from huggingface_hub import snapshot_download
from chatterbox.src.chatterbox.tts import ChatterboxTTS
import gradio as gr
# --- CẤU HÌNH MODEL TỪ HUGGINGFACE ---
MODEL_REPO = "LTTEAM/TTS_Pro"
LOCAL_MODEL_DIR = Path(os.getcwd()) / "models" / "tts_pro"
MODELS = {}
# Download model một lần (cache)
if not LOCAL_MODEL_DIR.exists():
print(f"📥 Đang tải model từ HuggingFace repo {MODEL_REPO} …")
snapshot_download(
repo_id=MODEL_REPO,
repo_type="model",
local_dir=str(LOCAL_MODEL_DIR),
local_dir_use_symlinks=False
)
print(f"✅ Đã tải xong vào {LOCAL_MODEL_DIR}")
def get_or_load_model(device_str: str):
"""
Lấy hoặc load model ChatterboxTTS trên device 'cpu' hoặc 'cuda'.
device_str = "cpu" hoặc "gpu".
"""
device = "cuda" if (device_str == "gpu" and torch.cuda.is_available()) else "cpu"
if device not in MODELS:
print(f"📂 Loading model lên {device} …")
model = ChatterboxTTS.from_local(str(LOCAL_MODEL_DIR), device)
MODELS[device] = model
print(f"✅ Model đã được load lên {device}")
return MODELS[device]
def set_seed(seed: int):
torch.manual_seed(seed)
if torch.cuda.is_available():
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
random.seed(seed)
np.random.seed(seed)
def chunk_text(text: str, chunk_size: int = 300):
"""Chia text dài thành các đoạn tối đa chunk_size ký tự, giữ nguyên từ."""
words = text.split()
chunks, current = [], ""
for w in words:
if len(current) + len(w) + 1 > chunk_size:
chunks.append(current.strip())
current = w
else:
current = f"{current} {w}".strip()
if current:
chunks.append(current.strip())
return chunks
def generate_tts_audio(
device_choice: str,
text_input: str,
audio_prompt_path: str,
exaggeration: float,
temperature: float,
seed_num: int,
cfg_weight: float
):
"""
Sinh audio từ văn bản không giới hạn: chia thành chunk, generate từng chunk, ghép nối.
Trả về (sample_rate, numpy.ndarray).
"""
model = get_or_load_model(device_choice)
if seed_num != 0:
set_seed(int(seed_num))
chunks = chunk_text(text_input, chunk_size=300)
waves, sr = [], model.sr
for idx, chunk in enumerate(chunks, start=1):
print(f"🔊 Sinh đoạn {idx}/{len(chunks)} trên {model.device}")
wav = model.generate(
chunk,
audio_prompt_path=audio_prompt_path,
exaggeration=exaggeration,
temperature=temperature,
cfg_weight=cfg_weight,
)
waves.append(wav.squeeze(0).cpu().numpy())
full_wave = np.concatenate(waves, axis=0)
print("✅ Hoàn thành sinh toàn bộ audio.")
return sr, full_wave
# --- GIAO DIỆN GRADIO TIẾNG VIỆT ---
with gr.Blocks(title="LTTEAM TTS") as demo:
gr.Markdown(
"""
# LTTEAM TTS
**Phát triển bởi: Lý Trần**
Ứng dụng chuyển văn bản thành giọng nói chất lượng cao, hỗ trợ đầu vào không giới hạn.
"""
)
with gr.Row():
with gr.Column():
device_choice = gr.Radio(
choices=["cpu", "gpu"],
value="gpu" if torch.cuda.is_available() else "cpu",
label="Chọn thiết bị"
)
text = gr.Textbox(
label="Văn bản (không giới hạn độ dài)",
lines=8,
placeholder="Dán hoặc nhập văn bản vào đây..."
)
ref_wav = gr.Audio(
sources=["upload", "microphone"],
type="filepath",
label="Âm thanh mẫu (tùy chọn)",
value="brian.wav"
)
exaggeration = gr.Slider(
minimum=0.25, maximum=2, step=0.05,
value=0.5,
label="Mức nhấn nhá (Exaggeration)"
)
cfg_weight = gr.Slider(
minimum=0.2, maximum=1, step=0.05,
value=0.5,
label="Trọng số CFG / Tốc độ"
)
with gr.Accordion("Tùy chọn thêm", open=False):
seed_num = gr.Number(0, label="Seed (0 = random)")
temperature = gr.Slider(
minimum=0.05, maximum=5, step=0.05,
value=0.8,
label="Nhiệt độ (Temperature)"
)
run = gr.Button("Chuyển giọng", variant="primary")
with gr.Column():
out_audio = gr.Audio(label="Kết quả âm thanh")
run.click(
fn=generate_tts_audio,
inputs=[device_choice, text, ref_wav, exaggeration, temperature, seed_num, cfg_weight],
outputs=[out_audio],
)
if __name__ == "__main__":
# Phát hiện Colab qua biến môi trường
is_colab = "COLAB_GPU" in os.environ
if is_colab:
demo.launch(share=True)
else:
# Dùng host/port để hỗ trợ HuggingFace Spaces
demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))