File size: 4,543 Bytes
f69f95d
 
 
 
 
 
1c7e284
f69f95d
227305c
f69f95d
 
1c7e284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227305c
1c7e284
 
 
 
 
 
 
 
f69f95d
1c7e284
227305c
1c7e284
 
227305c
 
1c7e284
227305c
1c7e284
 
 
 
227305c
f69f95d
1c7e284
93957e5
f69f95d
1c7e284
 
f69f95d
93957e5
1c7e284
93957e5
f69f95d
1c7e284
 
 
 
 
93957e5
1c7e284
227305c
1c7e284
f69f95d
1c7e284
 
 
 
f69f95d
 
1c7e284
93957e5
 
1c7e284
f69f95d
1c7e284
 
 
f69f95d
1c7e284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f69f95d
1c7e284
f69f95d
1c7e284
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import gradio as gr
import onnxruntime as ort
import numpy as np
import json
import pysrt
import re
import os
from vinorm import TTSnorm
from phonemizer import phonemize
from scipy.io import wavfile

# --- 1. DANH SÁCH GIỌNG NÓI TỪ ẢNH GOOGLE DRIVE ---
# Bạn có thể thêm hoặc sửa tên hiển thị ở đây
VOICE_MAP = {
    "Phương Mai 1": "phuongmai1.onnx",
    "Ngọc Ngân 3701": "ngocngan3701.onnx",
    "Lạc Phi": "lacphi.onnx",
    "Ngọc Huyền": "ngochuyen.onnx",
    "Duy Oryx 3175": "duyoryx3175.onnx",
    # Thêm các giọng khác nếu bạn đã upload tệp lên
}

# Biến toàn cục lưu trữ session để tiết kiệm RAM
current_sess = None
current_phoneme_map = None
current_sample_rate = 22050

def load_voice_model(name):
    global current_sess, current_phoneme_map, current_sample_rate
    onnx_file = VOICE_MAP[name]
    json_file = onnx_file + ".json"
    
    if not os.path.exists(onnx_file) or not os.path.exists(json_file):
        raise FileNotFoundError(f"Thiếu tệp {onnx_file} hoặc {json_file} trên Space!")

    with open(json_file, "r", encoding="utf-8") as f:
        cfg = json.load(f)
    current_phoneme_map = cfg["phoneme_id_map"]
    current_sample_rate = cfg.get("audio", {}).get("sample_rate", 22050)
    current_sess = ort.InferenceSession(onnx_file, providers=['CPUExecutionProvider'])

# --- 2. XỬ LÝ ÂM VỊ & ĐỒNG BỘ SRT ---
def process_text(text):
    text = re.sub(r'<[^>]*>', '', text) # Làm sạch HTML
    text = TTSnorm(text.replace('\n', ' ').strip()) # Chuẩn hóa tiếng Việt
    phonemes = phonemize(text, language='vi', backend='espeak', strip=True)
    
    ids = [current_phoneme_map.get("^", [1])[0]]
    for p in phonemes:
        if p in current_phoneme_map:
            ids.extend(current_phoneme_map[p])
            ids.append(current_phoneme_map.get("_", [0])[0])
    ids.append(current_phoneme_map.get("$", [2])[0])
    return ids

def srt_to_audio_sync(voice_name, srt_file, speed=1.30):
    if srt_file is None: return "Chưa chọn file SRT", None
    try:
        load_voice_model(voice_name) # Nạp model được chọn
        
        subs = pysrt.open(srt_file.name, encoding='utf-8')
        final_audio_stream = []
        current_sample_idx = 0

        for sub in subs:
            # Đồng bộ mốc thời gian SRT
            start_sample = int((sub.start.ordinal / 1000.0) * current_sample_rate)
            if start_sample > current_sample_idx:
                final_audio_stream.append(np.zeros(start_sample - current_sample_idx, dtype=np.float32))
                current_sample_idx = start_sample

            # Inference ONNX
            ids = process_text(sub.text)
            scales = np.array([0.667, 0.8, 1.0/speed], dtype=np.float32)
            
            outputs = current_sess.run(None, {
                "input": np.array([ids], dtype=np.int64),
                "input_lengths": np.array([len(ids)], dtype=np.int64),
                "scales": scales
            })
            
            # Làm phẳng mảng 4D
            audio_segment = outputs[0].flatten().astype(np.float32)
            final_audio_stream.append(audio_segment)
            current_sample_idx += len(audio_segment)

        output_path = "synced_voice.wav"
        wavfile.write(output_path, current_sample_rate, np.concatenate(final_audio_stream))
        return f"Hoàn thành lồng tiếng với giọng: {voice_name}", output_path
    except Exception as e:
        return f"Lỗi: {str(e)}", None

# --- 3. GIAO DIỆN CHỌN TÊN GIỌNG ---
with gr.Blocks(title="Multi-Voice SRT Dubbing") as demo:
    gr.Markdown("# 🗣️ Hệ thống lồng tiếng 7 giọng Tiếng Việt")
    
    with gr.Row():
        with gr.Column():
            # Menu chọn tên giọng như trong ảnh Drive của bạn
            voice_select = gr.Dropdown(choices=list(VOICE_MAP.keys()), value="Phương Mai 1", label="Chọn giọng đọc")
            file_input = gr.File(label="Tải file SRT từ SD Card", file_types=[".srt"])
            speed_input = gr.Slider(0.5, 2.0, value=1.30, label="Tốc độ (Mặc định 1.30)")
            btn = gr.Button("🚀 Chạy lồng tiếng", variant="primary")
        
        with gr.Column():
            status = gr.Textbox(label="Trạng thái")
            audio_out = gr.Audio(label="Audio hoàn chỉnh (Khớp thời gian)")

    btn.click(srt_to_audio_sync, [voice_select, file_input, speed_input], [status, audio_out])

demo.launch(server_name="0.0.0.0")