Spaces:
Running
Running
| 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() |