import gradio as gr from pathlib import Path from ui.handlers import handle_verify, handle_upload, handle_reset, handle_audio_change # Đọc CSS và JS từ file thật # Bỏ @import trong CSS vì Gradio không cho phép _CSS = (Path(__file__).parent / "styles.css").read_text() _JS = (Path(__file__).parent / "recorder.js").read_text() _RECORDER_HTML = """
Nhấn để bắt đầu ghi âm
 Đang xử lý âm thanh...
🎧 Nghe lại bản ghi:
""" def build_ui() -> gr.Blocks: with gr.Blocks(theme=gr.themes.Base(), css=_CSS, title="Lumi Voice Collector") as demo: # --- Font + permissions (thay thế @import trong CSS) --- gr.HTML(""" """) # --- Header --- gr.HTML("""
🎙️

Thu thập giọng nói "Lumi ơi"

Giúp huấn luyện wake word cho trợ lý Lumi

""") # --- Steps --- gr.HTML("""
1
Ghi âm
2
Kiểm tra
3
Gửi lên
""") # --- Instruction --- gr.HTML("""
📋 Hướng dẫn

1. Nhấn nút mic để bắt đầu ghi âm
2. Nói rõ "Lumi ơi" vào micro
3. Nhấn lại để dừng — đợi thanh xử lý biến mất
4. Nhấn Kiểm tra → đạt ≥ 0.8 → nhấn Gửi

""") # --- Recorder card --- with gr.Group(elem_classes="lumi-card"): gr.HTML(_RECORDER_HTML) gr.HTML(f"") # --- Hidden Gradio audio --- with gr.Group(elem_classes="hidden-audio-wrap"): audio_inst = gr.Audio( sources=["upload"], type="filepath", label="hidden", visible=False ) # --- Status --- status_txt = gr.Label( value='🎙️ Sẵn sàng — Nhấn mic và đọc "Lumi ơi"', elem_classes="lumi-status", show_label=False ) # --- Buttons --- with gr.Row(elem_classes="lumi-btn-row"): btn_check = gr.Button("🔍 Kiểm tra mẫu", variant="secondary", elem_classes="lb-check") btn_reset = gr.Button("🗑 Ghi lại", variant="stop", elem_classes="lb-reset") btn_send = gr.Button( "🚀 Gửi lên hệ thống", variant="primary", interactive=False, elem_classes="lb-send" ) # --- State --- score_state = gr.State(0.0) # --- Event bindings --- btn_check.click( fn=handle_verify, inputs=audio_inst, outputs=[status_txt, btn_send, score_state] ) btn_send.click( fn=handle_upload, inputs=[audio_inst, score_state], outputs=[status_txt, btn_send, audio_inst] ) btn_reset.click( fn=handle_reset, outputs=[audio_inst, status_txt, btn_send, score_state] ) audio_inst.change( fn=handle_audio_change, outputs=btn_send ) return demo