Chatteraudio / app.py
lomasdai's picture
Create app.py
3eddc37 verified
Raw History Blame Contribute Delete
5.59 kB
import os
import random
import numpy as np
import torch
import librosa
import soundfile as sf
import gradio as gr
try:
import spaces
GPU_DECORATOR = spaces.GPU(duration=60)
except ImportError:
def GPU_DECORATOR(func):
return func
from chatterbox.tts import ChatterboxTTS
from chatterbox.vc import ChatterboxVC
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Initializing Chatterbox on {DEVICE}...")
tts_model = ChatterboxTTS.from_pretrained("cpu")
vc_model = ChatterboxVC.from_pretrained("cpu")
if hasattr(tts_model, "t3") and hasattr(tts_model.t3, "tfmr"):
if hasattr(tts_model.t3.tfmr, "config"):
tts_model.t3.tfmr.config._attn_implementation = "eager"
def sanitize_reference_audio(audio_path, max_duration=20.0):
if not audio_path:
return None
wav, sr = librosa.load(audio_path, sr=24000, mono=True)
max_samples = int(max_duration * sr)
if len(wav) > max_samples:
wav = wav[:max_samples]
max_val = np.max(np.abs(wav))
if max_val > 0:
wav = (wav / max_val) * 0.95
clean_path = "/tmp/clean_ref_prompt.wav"
sf.write(clean_path, wav, sr, subtype="PCM_16")
return clean_path
@GPU_DECORATOR
def generate_tts(text, audio_prompt_path, exaggeration, temperature, seed_num, cfgw, min_p, top_p, repetition_penalty):
text = text.strip()
if not text:
raise gr.Error("Please enter text to synthesize.")
if len(text) > 450:
text = text[:450]
target_dev = "cuda" if torch.cuda.is_available() else "cpu"
tts_model.device = target_dev
tts_model.t3.to(target_dev)
tts_model.s3gen.to(target_dev)
tts_model.ve.to(target_dev)
if tts_model.conds is not None:
tts_model.conds.to(target_dev)
if int(seed_num) != 0:
torch.manual_seed(int(seed_num))
if torch.cuda.is_available():
torch.cuda.manual_seed_all(int(seed_num))
random.seed(int(seed_num))
np.random.seed(int(seed_num))
clean_prompt = sanitize_reference_audio(audio_prompt_path)
with torch.inference_mode():
wav = tts_model.generate(
text,
audio_prompt_path=clean_prompt,
exaggeration=float(exaggeration),
temperature=float(temperature),
cfg_weight=float(cfgw),
min_p=float(min_p),
top_p=float(top_p),
repetition_penalty=float(repetition_penalty),
)
return (tts_model.sr, wav.squeeze(0).cpu().numpy())
@GPU_DECORATOR
def convert_voice(input_audio, target_voice_audio):
if input_audio is None or target_voice_audio is None:
raise gr.Error("Please upload both source audio and target voice audio.")
target_dev = "cuda" if torch.cuda.is_available() else "cpu"
vc_model.device = target_dev
vc_model.s3gen.to(target_dev)
clean_src = sanitize_reference_audio(input_audio, max_duration=30.0)
clean_tgt = sanitize_reference_audio(target_voice_audio, max_duration=20.0)
with torch.inference_mode():
wav = vc_model.generate(
audio=clean_src,
target_voice_path=clean_tgt,
)
return (vc_model.sr, wav.squeeze(0).cpu().numpy())
with gr.Blocks(title="Chatterbox Web Studio") as demo:
gr.Markdown("# πŸŽ™οΈ Chatterbox Standalone Web Studio")
with gr.Tabs():
with gr.TabItem("πŸ—£οΈ Text-to-Speech (TTS)"):
with gr.Row():
with gr.Column():
text = gr.Textbox(label="Text to Synthesize", lines=5, value="Welcome to Chatterbox Web Studio!")
ref_wav = gr.Audio(sources=["upload", "microphone"], type="filepath", label="Reference Voice Audio (Optional - 10 to 20s WAV)", value=None)
with gr.Row():
exaggeration = gr.Slider(0.25, 2.0, step=0.05, value=0.5, label="Exaggeration")
cfg_weight = gr.Slider(0.0, 1.0, step=0.05, value=0.5, label="CFG / Pace Control")
with gr.Accordion("βš™οΈ Advanced Sampler Settings", open=False):
seed_num = gr.Number(value=0, label="Random Seed", precision=0)
temp = gr.Slider(0.05, 2.0, step=0.05, value=0.8, label="Temperature")
min_p = gr.Slider(0.00, 1.00, step=0.01, value=0.05, label="min_p")
top_p = gr.Slider(0.00, 1.00, step=0.01, value=1.00, label="top_p")
rep_penalty = gr.Slider(1.00, 2.00, step=0.05, value=1.20, label="Repetition Penalty")
tts_btn = gr.Button("Generate Speech ⚑", variant="primary")
with gr.Column():
tts_output = gr.Audio(label="Generated Output", interactive=False)
tts_btn.click(fn=generate_tts, inputs=[text, ref_wav, exaggeration, temp, seed_num, cfg_weight, min_p, top_p, rep_penalty], outputs=tts_output)
with gr.TabItem("πŸ”„ Voice Conversion (VC)"):
with gr.Row():
with gr.Column():
src_audio = gr.Audio(sources=["upload", "microphone"], type="filepath", label="Source Audio")
tgt_audio = gr.Audio(sources=["upload", "microphone"], type="filepath", label="Target Voice Audio")
vc_btn = gr.Button("Convert Voice πŸ”„", variant="primary")
with gr.Column():
vc_output = gr.Audio(label="Converted Audio Output", interactive=False)
vc_btn.click(fn=convert_voice, inputs=[src_audio, tgt_audio], outputs=vc_output)
if __name__ == "__main__":
demo.queue().launch()