VachanaFlowTTS / app.py
VIZINTZOR's picture
Update app.py
0a4714e verified
Raw
History Blame Contribute Delete
6.68 kB
import gradio as gr
from tts import VachanaFlowTTS
import soundfile as sf
# --- Model initialization
ONNX_DIR = "onnx_model"
DEVICE = "cpu"
tts = VachanaFlowTTS(ONNX_DIR, device=DEVICE)
sample_rate = 44100
def synthesize(text, spk_id=0, step=8, speed=0.9, variation=0.667, normalize=True):
audio = tts.synthesize(text, spk_id, step, speed, variation, normalize)
out_wav = "output.wav"
sf.write(out_wav, audio , sample_rate)
return out_wav, "✅ สร้างเสียงสำเร็จ!"
custom_css = """
@import url('https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;600&family=Space+Mono:wght@400;700&display=swap');
:root {
--bg: #0d0d0f;
--surface: #16161a;
--surface2: #1e1e24;
--border: #2a2a35;
--accent: #c8f55a;
--accent2: #5af5c8;
--text: #f0f0f5;
--muted: #6b6b80;
--radius: 14px;
}
body, .gradio-container {
background: var(--bg) !important;
font-family: 'Sarabun', sans-serif !important;
color: var(--text) !important;
}
.gradio-container {
max-width: 700px !important;
margin: 0 auto !important;
padding: 2rem 1.5rem !important;
}
#header {
text-align: center;
margin-bottom: 2.5rem;
padding: 2.5rem 2rem;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 20px;
position: relative;
overflow: hidden;
}
#header::before {
content: '';
position: absolute;
top: -60px; right: -60px;
width: 200px; height: 200px;
background: radial-gradient(circle, rgba(200,245,90,0.12), transparent 70%);
border-radius: 50%;
}
#header h1 {
font-family: 'Space Mono', monospace !important;
font-size: 2rem !important;
font-weight: 700 !important;
color: var(--accent) !important;
margin: 0 0 0.4rem 0 !important;
letter-spacing: -1px;
}
#header p {
color: var(--muted) !important;
font-size: 0.95rem !important;
margin: 0 !important;
}
.block, .form {
background: var(--surface) !important;
border: 1px solid var(--border) !important;
border-radius: var(--radius) !important;
}
label span {
color: var(--muted) !important;
font-size: 0.8rem !important;
font-family: 'Space Mono', monospace !important;
text-transform: uppercase !important;
letter-spacing: 1px !important;
}
textarea, input[type="text"] {
background: var(--surface2) !important;
border: 1px solid var(--border) !important;
color: var(--text) !important;
border-radius: 10px !important;
font-family: 'Sarabun', sans-serif !important;
font-size: 1rem !important;
line-height: 1.7 !important;
}
textarea:focus, input:focus {
border-color: var(--accent) !important;
box-shadow: 0 0 0 2px rgba(200,245,90,0.12) !important;
}
.radio-group label, .checkbox-group label {
background: var(--surface2) !important;
border: 1px solid var(--border) !important;
border-radius: 8px !important;
color: var(--text) !important;
padding: 0.6rem 1.2rem !important;
cursor: pointer !important;
transition: all 0.2s ease !important;
}
.radio-group label:hover {
border-color: var(--accent) !important;
color: var(--accent) !important;
}
input[type="radio"]:checked + label,
.radio-group label.selected {
border-color: var(--accent) !important;
color: var(--accent) !important;
background: rgba(200,245,90,0.08) !important;
}
button.primary {
background: var(--accent) !important;
color: #0d0d0f !important;
border: none !important;
border-radius: 10px !important;
font-family: 'Space Mono', monospace !important;
font-weight: 700 !important;
font-size: 0.9rem !important;
letter-spacing: 1px !important;
padding: 0.8rem 2rem !important;
width: 100% !important;
cursor: pointer !important;
transition: opacity 0.2s, transform 0.15s !important;
}
button.primary:hover {
opacity: 0.88 !important;
transform: translateY(-1px) !important;
}
.upload-area {
border: 2px dashed var(--border) !important;
border-radius: 10px !important;
background: var(--surface2) !important;
transition: border-color 0.2s !important;
}
.upload-area:hover {
border-color: var(--accent2) !important;
}
audio {
width: 100% !important;
border-radius: 10px !important;
background: var(--surface2) !important;
}
.status-box {
font-family: 'Space Mono', monospace !important;
font-size: 0.82rem !important;
color: var(--accent2) !important;
background: var(--surface2) !important;
border: 1px solid var(--border) !important;
border-radius: 8px !important;
padding: 0.6rem 1rem !important;
}
.gap { gap: 1rem !important; }
footer { display: none !important; }
"""
with gr.Blocks(css=custom_css, title="Thai TTS") as demo:
gr.HTML("""
<div id="header">
<h1>Vachana-Flow-TTS</h1>
<p>Thai Text-to-Speech · Fast with Flow Matching with CPU,GPU</p>
</div>
""")
with gr.Column(elem_classes="gap"):
text_input = gr.Textbox(
label="ข้อความ",
placeholder="พิมพ์ข้อความภาษาไทยที่ต้องการแปลงเป็นเสียง...",
lines=4,
value="วันนี้อากาศปลอดโปร่ง ลมพัดเย็นสบาย รู้สึกเหมาะกับการออกไปเดินเล่นหรือจิบกาแฟข้างนอกมากเลย"
)
speaker_id = gr.Radio(label="Speaker ID",choices=[0,1],value=0)
step = gr.Slider(label="N Step",value=8, step=1,minimum=4, maximum=15)
speed = gr.Slider(label="Speed",value=0.9,step=0.01,minimum=0.3,maximum=1.8)
variation = gr.Slider(label="Variation",value=0.667,step=0.001, minimum=0.1,maximum=0.8)
normalize = gr.Checkbox(label="Normalize Audio", value=True)
run_btn = gr.Button("▶ สร้างเสียง", variant="primary")
with gr.Column(elem_classes="gap"):
audio_output = gr.Audio(label="เสียงที่สร้างขึ้น", type="filepath")
status_output = gr.Textbox(label="สถานะ", elem_classes="status-box", show_label=False, interactive=False)
run_btn.click(
fn=synthesize,
inputs=[text_input, speaker_id, step, speed, variation, normalize],
outputs=[audio_output, status_output],
)
demo.launch()