Spaces:
Sleeping
Sleeping
Commit ·
93957e5
1
Parent(s): 227305c
Update app.py
Browse files
app.py
CHANGED
|
@@ -8,76 +8,90 @@ from vinorm import TTSnorm
|
|
| 8 |
from phonemizer import phonemize
|
| 9 |
from scipy.io import wavfile
|
| 10 |
|
| 11 |
-
# --- 1. TẢI
|
| 12 |
try:
|
| 13 |
with open("config.json", "r", encoding="utf-8") as f:
|
| 14 |
config = json.load(f)
|
| 15 |
-
# Lấy bản đồ ID âm vị từ config của bạn
|
| 16 |
phoneme_id_map = config["phoneme_id_map"]
|
| 17 |
sample_rate = config.get("audio", {}).get("sample_rate", 22050)
|
| 18 |
|
| 19 |
sess = ort.InferenceSession("model.onnx", providers=['CPUExecutionProvider'])
|
| 20 |
-
print("✅ Hệ thống đã sẵn sàng")
|
| 21 |
except Exception as e:
|
| 22 |
print(f"❌ Lỗi khởi động: {e}")
|
| 23 |
|
| 24 |
-
# --- 2.
|
| 25 |
def process_text(text):
|
| 26 |
-
#
|
| 27 |
text = re.sub(r'<[^>]*>', '', text)
|
| 28 |
-
# Chuẩn hóa tiếng Việt (100k -> một trăm nghìn)
|
| 29 |
text = TTSnorm(text.replace('\n', ' ').strip())
|
| 30 |
-
# Chuyển sang âm vị IPA
|
| 31 |
phonemes = phonemize(text, language='vi', backend='espeak', strip=True)
|
| 32 |
|
| 33 |
-
ids = [phoneme_id_map.get("^", [1])[0]]
|
| 34 |
for p in phonemes:
|
| 35 |
if p in phoneme_id_map:
|
| 36 |
ids.extend(phoneme_id_map[p])
|
| 37 |
-
ids.append(phoneme_id_map.get("_", [0])[0])
|
| 38 |
-
ids.append(phoneme_id_map.get("$", [2])[0])
|
| 39 |
return ids
|
| 40 |
|
| 41 |
-
# --- 3.
|
| 42 |
-
def
|
| 43 |
-
if srt_file is None: return "Chưa
|
| 44 |
try:
|
| 45 |
subs = pysrt.open(srt_file.name, encoding='utf-8')
|
| 46 |
-
|
| 47 |
-
|
|
|
|
| 48 |
for sub in subs:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
ids = process_text(sub.text)
|
| 50 |
input_ids = np.array([ids], dtype=np.int64)
|
| 51 |
input_lens = np.array([len(ids)], dtype=np.int64)
|
| 52 |
-
# Tốc độ 1.30 được đưa vào tham số scale cuối cùng
|
| 53 |
scales = np.array([noise, noise_w, 1.0/speed], dtype=np.float32)
|
| 54 |
|
| 55 |
outputs = sess.run(None, {
|
| 56 |
"input": input_ids, "input_lengths": input_lens, "scales": scales
|
| 57 |
})
|
| 58 |
|
| 59 |
-
# Làm phẳng mảng 4D thành 1D
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
|
|
|
|
|
|
| 63 |
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
|
|
|
|
|
|
| 67 |
except Exception as e:
|
| 68 |
-
return f"Lỗi: {str(e)}", None
|
| 69 |
|
| 70 |
# --- 4. GIAO DIỆN ---
|
| 71 |
demo = gr.Interface(
|
| 72 |
-
fn=
|
| 73 |
inputs=[
|
| 74 |
-
gr.File(label="
|
| 75 |
gr.Slider(0.5, 2.0, value=1.30, label="Tốc độ nói"),
|
| 76 |
-
gr.Slider(0.1, 1.0, value=0.667, label="
|
| 77 |
-
gr.Slider(0.1, 1.0, value=0.8, label="
|
| 78 |
],
|
| 79 |
-
outputs=[gr.Textbox(label="Trạng thái"), gr.Audio(label="
|
| 80 |
-
title="SRT
|
|
|
|
| 81 |
)
|
| 82 |
|
| 83 |
if __name__ == "__main__":
|
|
|
|
| 8 |
from phonemizer import phonemize
|
| 9 |
from scipy.io import wavfile
|
| 10 |
|
| 11 |
+
# --- 1. TẢI CẤU HÌNH ---
|
| 12 |
try:
|
| 13 |
with open("config.json", "r", encoding="utf-8") as f:
|
| 14 |
config = json.load(f)
|
|
|
|
| 15 |
phoneme_id_map = config["phoneme_id_map"]
|
| 16 |
sample_rate = config.get("audio", {}).get("sample_rate", 22050)
|
| 17 |
|
| 18 |
sess = ort.InferenceSession("model.onnx", providers=['CPUExecutionProvider'])
|
| 19 |
+
print("✅ Hệ thống đồng bộ thời gian đã sẵn sàng")
|
| 20 |
except Exception as e:
|
| 21 |
print(f"❌ Lỗi khởi động: {e}")
|
| 22 |
|
| 23 |
+
# --- 2. XỬ LÝ VĂN BẢN ---
|
| 24 |
def process_text(text):
|
| 25 |
+
# Làm sạch HTML và chuẩn hóa tiếng Việt
|
| 26 |
text = re.sub(r'<[^>]*>', '', text)
|
|
|
|
| 27 |
text = TTSnorm(text.replace('\n', ' ').strip())
|
| 28 |
+
# Chuyển sang âm vị (IPA) để model Piper có thể đọc
|
| 29 |
phonemes = phonemize(text, language='vi', backend='espeak', strip=True)
|
| 30 |
|
| 31 |
+
ids = [phoneme_id_map.get("^", [1])[0]]
|
| 32 |
for p in phonemes:
|
| 33 |
if p in phoneme_id_map:
|
| 34 |
ids.extend(phoneme_id_map[p])
|
| 35 |
+
ids.append(phoneme_id_map.get("_", [0])[0])
|
| 36 |
+
ids.append(phoneme_id_map.get("$", [2])[0])
|
| 37 |
return ids
|
| 38 |
|
| 39 |
+
# --- 3. LOGIC ĐỒNG BỘ THỜI GIAN (SYNC) ---
|
| 40 |
+
def srt_to_audio_sync(srt_file, speed=1.30, noise=0.667, noise_w=0.8):
|
| 41 |
+
if srt_file is None: return "Chưa chọn file SRT", None
|
| 42 |
try:
|
| 43 |
subs = pysrt.open(srt_file.name, encoding='utf-8')
|
| 44 |
+
final_audio_stream = []
|
| 45 |
+
current_sample_index = 0
|
| 46 |
+
|
| 47 |
for sub in subs:
|
| 48 |
+
# 1. Tính toán thời điểm bắt đầu tính bằng Sample
|
| 49 |
+
start_time_seconds = sub.start.ordinal / 1000.0
|
| 50 |
+
start_sample_target = int(start_time_seconds * sample_rate)
|
| 51 |
+
|
| 52 |
+
# 2. Nếu thời điểm hiện tại chưa tới thời điểm bắt đầu, chèn khoảng lặng
|
| 53 |
+
if start_sample_target > current_sample_index:
|
| 54 |
+
silence_len = start_sample_target - current_sample_index
|
| 55 |
+
final_audio_stream.append(np.zeros(silence_len, dtype=np.float32))
|
| 56 |
+
current_sample_index = start_sample_target
|
| 57 |
+
|
| 58 |
+
# 3. Tạo âm thanh cho câu phụ đề
|
| 59 |
ids = process_text(sub.text)
|
| 60 |
input_ids = np.array([ids], dtype=np.int64)
|
| 61 |
input_lens = np.array([len(ids)], dtype=np.int64)
|
|
|
|
| 62 |
scales = np.array([noise, noise_w, 1.0/speed], dtype=np.float32)
|
| 63 |
|
| 64 |
outputs = sess.run(None, {
|
| 65 |
"input": input_ids, "input_lengths": input_lens, "scales": scales
|
| 66 |
})
|
| 67 |
|
| 68 |
+
# Làm phẳng mảng 4D thành 1D
|
| 69 |
+
audio_segment = outputs[0].flatten().astype(np.float32)
|
| 70 |
+
|
| 71 |
+
# 4. Thêm audio vào luồng và cập nhật vị trí hiện tại
|
| 72 |
+
final_audio_stream.append(audio_segment)
|
| 73 |
+
current_sample_index += len(audio_segment)
|
| 74 |
|
| 75 |
+
# Kết hợp tất cả thành một file duy nhất
|
| 76 |
+
full_audio = np.concatenate(final_audio_stream)
|
| 77 |
+
wavfile.write("synced_dubbing.wav", sample_rate, full_audio)
|
| 78 |
+
|
| 79 |
+
return "Đã tạo file dubbing khớp thời gian thành công!", "synced_dubbing.wav"
|
| 80 |
except Exception as e:
|
| 81 |
+
return f"Lỗi xử lý: {str(e)}", None
|
| 82 |
|
| 83 |
# --- 4. GIAO DIỆN ---
|
| 84 |
demo = gr.Interface(
|
| 85 |
+
fn=srt_to_audio_sync,
|
| 86 |
inputs=[
|
| 87 |
+
gr.File(label="Chọn file SRT từ SD Card", file_types=[".srt"]),
|
| 88 |
gr.Slider(0.5, 2.0, value=1.30, label="Tốc độ nói"),
|
| 89 |
+
gr.Slider(0.1, 1.0, value=0.667, label="Noise Scale"),
|
| 90 |
+
gr.Slider(0.1, 1.0, value=0.8, label="Noise W")
|
| 91 |
],
|
| 92 |
+
outputs=[gr.Textbox(label="Trạng thái"), gr.Audio(label="Audio khớp chuẩn thời gian")],
|
| 93 |
+
title="SRT Dubbing - Đồng bộ thời gian chuẩn",
|
| 94 |
+
description="Tự động thêm khoảng lặng để âm thanh khớp hoàn toàn với mốc thời gian trong file SRT."
|
| 95 |
)
|
| 96 |
|
| 97 |
if __name__ == "__main__":
|