import os import tempfile import gradio as gr from huggingface_hub import login from cached_path import cached_path from vinorm import TTSnorm from f5_tts.model import DiT from f5_tts.infer.utils_infer import ( preprocess_ref_audio_text, load_vocoder, load_model, infer_process, save_spectrogram, ) # ————————————————————————————— # 0. CƠ SỞ DỮ LIỆU TRONG BỘ NHỚ # ————————————————————————————— # Admin mặc định user_db = { "lytran": { "password": "16051998", "approved": True, "is_admin": True } } # Các tài khoản chờ duyệt pending_db = {} # key=username, value=password # ————————————————————————————— # 1. ĐĂNG NHẬP HUGGINGFACE HUB (nếu có TOKEN) # ————————————————————————————— hf_token = os.getenv("HUGGINGFACEHUB_API_TOKEN") if hf_token: login(token=hf_token) # ————————————————————————————— # 2. Hàm tiền xử lý văn bản # ————————————————————————————— def post_process(text: str) -> str: text = f" {text} " for old, new in [(" . . ", " . "), (" .. ", " . "), (" , , ", " , "), (" ,, ", " , ")]: text = text.replace(old, new) text = text.replace('"', "") return " ".join(text.split()) # ————————————————————————————— # 3. Load model và vocoder # ————————————————————————————— vocoder = load_vocoder() model = load_model( DiT, dict(dim=1024, depth=22, heads=16, ff_mult=2, text_dim=512, conv_layers=4), ckpt_path=str(cached_path("hf://LTTEAM/100h-VN/model_100h.pt")), vocab_file=str(cached_path("hf://LTTEAM/100h-VN/vocab.txt")), ) # ————————————————————————————— # 4. Hàm chuyển TTS # ————————————————————————————— def infer_tts(ref_audio_path: str, gen_text: str, speed: float = 1.0): if not ref_audio_path: raise gr.Error("Vui lòng tải lên hoặc chọn tệp âm thanh mẫu.") if not gen_text.strip(): raise gr.Error("Vui lòng nhập nội dung văn bản cần chuyển thành giọng nói.") if len(gen_text.split()) > 1000: raise gr.Error("Vui lòng nhập văn bản có ít hơn 1000 từ.") try: ref_audio, ref_text = preprocess_ref_audio_text(ref_audio_path, "") wave, sr, spec = infer_process( ref_audio, ref_text.lower(), post_process(TTSnorm(gen_text)).lower(), model, vocoder, speed=speed ) # Lưu tạm spectrogram with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp: save_spectrogram(spec, tmp.name) spec_path = tmp.name return (sr, wave), spec_path except Exception as e: raise gr.Error(f"Lỗi khi chuyển văn bản sang giọng nói: {e}") # ————————————————————————————— # 5. Hàm đăng ký (đưa vào pending_db) # ————————————————————————————— def register_user(username: str, password: str): username = username.strip() if not username or not password: return "Vui lòng nhập đủ tên và mật khẩu." if username in user_db: return "Tên này đã tồn tại." if username in pending_db: return "Tên này đang chờ admin duyệt." pending_db[username] = password return "Đăng ký thành công! Vui lòng chờ admin duyệt." # ————————————————————————————— # 6. Hàm đăng nhập (kiểm tra pending vs user_db) # ————————————————————————————— def login_user(username: str, password: str): username = username.strip() if username in pending_db: return False, "Tài khoản đang chờ admin duyệt." u = user_db.get(username) if not u or u["password"] != password: return False, "Tên đăng nhập hoặc mật khẩu không đúng." if not u["approved"]: return False, "Tài khoản chưa được duyệt." return True, "" # ————————————————————————————— # 7. Hàm duyệt/từ chối (chỉ admin) # ————————————————————————————— def approve_user(username: str): if username not in pending_db: return gr.update(choices=list(pending_db.keys()), value=None), "Không tìm thấy user." # chuyển từ pending_db sang user_db user_db[username] = { "password": pending_db.pop(username), "approved": True, "is_admin": False } return gr.update(choices=list(pending_db.keys()), value=None), f"Đã duyệt {username}." def reject_user(username: str): if username not in pending_db: return gr.update(choices=list(pending_db.keys()), value=None), "Không tìm thấy user." pending_db.pop(username) return gr.update(choices=list(pending_db.keys()), value=None), f"Đã từ chối {username}." # ————————————————————————————— # 8. Xây giao diện Gradio # ————————————————————————————— with gr.Blocks(theme=gr.themes.Soft()) as demo: # === Login + Register column === with gr.Column(visible=True) as login_col: gr.Markdown("## Đăng nhập / Đăng ký") # -- form login -- username_input = gr.Textbox(label="Tên đăng nhập", placeholder="Nhập tên đăng nhập...") password_input = gr.Textbox(label="Mật khẩu", type="password", placeholder="Nhập mật khẩu...") login_btn = gr.Button("Đăng nhập", variant="primary") login_msg = gr.Textbox(interactive=False, label="", placeholder="") gr.Markdown("---") # -- form register -- reg_username = gr.Textbox(label="Tên đăng ký", placeholder="Chọn tên đăng nhập mới...") reg_password = gr.Textbox(label="Mật khẩu", type="password", placeholder="Chọn mật khẩu...") register_btn = gr.Button("Đăng ký tài khoản") register_msg = gr.Textbox(interactive=False, label="") gr.Markdown("---") # -- profile card giới thiệu -- gr.HTML("""
Quản trị viên LT TEAM