File size: 10,312 Bytes
06f92fc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8de7fa2
 
 
 
 
 
 
 
 
 
9de0758
 
 
 
 
 
 
8de7fa2
9de0758
2a190c5
8de7fa2
9de0758
 
8de7fa2
 
 
 
9de0758
8de7fa2
 
 
 
5ef7568
7a8f40a
 
3765580
7a8f40a
19673f9
 
 
6dc088c
 
 
 
2648649
b54375c
7a8f40a
9de0758
 
 
 
 
 
 
5ef7568
9de0758
2a190c5
5ef7568
9de0758
 
5ef7568
9de0758
6dc088c
2648649
6dc088c
 
 
 
 
 
 
 
2648649
6dc088c
 
 
 
7a8f40a
2648649
7a8f40a
 
9de0758
3765580
7a8f40a
06f92fc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9de0758
06f92fc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9de0758
06f92fc
 
 
 
 
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
import gradio as gr
from transformers import MarianMTModel, MarianTokenizer, pipeline
import pysrt
import tempfile
from tqdm import tqdm
from langdetect import detect
import os
from datetime import timedelta

# Danh sách các ngôn ngữ và model tương ứng
LANGUAGE_MODELS = {
    "Tiếng Anh": "en",
    "Tiếng Việt": "vi",
    "Tiếng Pháp": "fr",
    "Tiếng Đức": "de",
    "Tiếng Tây Ban Nha": "es",
    "Tiếng Bồ Đào Nha": "pt",
    "Tiếng Ý": "it",
    "Tiếng Nga": "ru",
    "Tiếng Hà Lan": "nl",
    "Tiếng Thụy Điển": "sv",
    "Tiếng Phần Lan": "fi",
    "Tiếng Đan Mạch": "da",
    "Tiếng Na Uy": "no",
    "Tiếng Ba Lan": "pl",
    "Tiếng Séc": "cs",
    "Tiếng Hungary": "hu",
    "Tiếng Romania": "ro",
    "Tiếng Hy Lạp": "el",
    "Tiếng Thổ Nhĩ Kỳ": "tr",
    "Tiếng Hindi": "hi",
    "Tiếng Ả Rập": "ar",
    "Tiếng Trung (Giản thể)": "zh",
    "Tiếng Nhật": "ja",
    "Tiếng Hàn": "ko"
}

# Đảo ngược dictionary để lấy code từ tên ngôn ngữ
LANGUAGE_CODES = {v: k for k, v in LANGUAGE_MODELS.items()}

# Cache models để tăng tốc độ
model_cache = {}
detector = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection")

def detect_subtitle_language(file_path):
    try:
        subs = pysrt.open(file_path)
        sample_text = " ".join([sub.text for sub in subs[:10] if sub.text.strip()])
        
        if not sample_text:
            return "en"  # Mặc định là tiếng Anh nếu không phát hiện được
        
        try:
            # Sử dụng langdetect cho đơn giản
            lang_code = detect(sample_text)
            return lang_code
        except:
            # Fallback sử dụng model xlm-roberta
            result = detector(sample_text[:512])[0]  # Giới hạn độ dài đầu vào
            return result['label'].split('__')[-1]
    except Exception as e:
        print(f"Error detecting language: {e}")
        return "en"

def get_model(source_lang, target_lang):
    model_key = f"{source_lang}-{target_lang}"
    
    if model_key not in model_cache:
        model_name = f"Helsinki-NLP/opus-mt-{model_key}"
        try:
            tokenizer = MarianTokenizer.from_pretrained(model_name)
            model = MarianMTModel.from_pretrained(model_name)
            model_cache[model_key] = (model, tokenizer)
        except:
            # Fallback: Dịch qua tiếng Anh nếu không có model trực tiếp
            if source_lang != "en":
                # Dịch từ ngôn ngữ nguồn -> tiếng Anh -> ngôn ngữ đích
                model1_name = f"Helsinki-NLP/opus-mt-{source_lang}-en"
                model2_name = f"Helsinki-NLP/opus-mt-en-{target_lang}"
                
                tokenizer1 = MarianTokenizer.from_pretrained(model1_name)
                model1 = MarianMTModel.from_pretrained(model1_name)
                tokenizer2 = MarianTokenizer.from_pretrained(model2_name)
                model2 = MarianMTModel.from_pretrained(model2_name)
                
                model_cache[model_key] = ((model1, tokenizer1), (model2, tokenizer2))
            else:
                raise gr.Error(f"Không tìm thấy model dịch từ {source_lang} sang {target_lang}")
    
    return model_cache[model_key]

def translate_text(text, model, tokenizer):
    inputs = tokenizer(text, return_tensors="pt", truncation=True, padding=True)
    translated = model.generate(**inputs)
    return tokenizer.batch_decode(translated, skip_special_tokens=True)[0]

def add_time_to_subtitle(input_file, hours, minutes, seconds):
    if input_file is None:
        raise gr.Error("Vui lòng upload file phụ đề!")
    
    try:
        if not os.path.exists(input_file):
            raise gr.Error("File không tồn tại hoặc không thể đọc!")
        
        subs = pysrt.open(input_file)
        
        # Chuyển đổi thời gian nhập vào thành mili giây (hỗ trợ số thập phân)
        try:
            seconds_float = float(seconds)
        except ValueError:
            seconds_float = 0
            
        total_milliseconds = int((int(hours) * 3600 + int(minutes) * 60 + seconds_float) * 1000)
        
        # Thêm thời gian vào tất cả các phụ đề
        if total_milliseconds > 0:
            for sub in subs:
                sub.start.ordinal += total_milliseconds
                sub.end.ordinal += total_milliseconds
        
        # Lưu file tạm
        output_path = tempfile.NamedTemporaryFile(suffix=".srt", delete=False).name
        subs.save(output_path, encoding='utf-8')
        return output_path, f"Đã thêm {hours}h {minutes}m {seconds_float}s vào file gốc"
    
    except Exception as e:
        raise gr.Error(f"Có lỗi xảy ra khi thêm thời gian: {str(e)}")

def translate_subtitle(input_file, source_language, target_language, hours, minutes, seconds):
    if input_file is None:
        raise gr.Error("Vui lòng upload file phụ đề!")
    
    try:
        if not os.path.exists(input_file):
            raise gr.Error("File không tồn tại hoặc không thể đọc!")
        
        source_code = LANGUAGE_MODELS.get(source_language, "en")
        target_code = LANGUAGE_MODELS[target_language]
        
        model_info = get_model(source_code, target_code)
        
        subs = pysrt.open(input_file)
        
        # Chuyển đổi thời gian nhập vào thành mili giây (hỗ trợ số thập phân)
        try:
            seconds_float = float(seconds)
        except ValueError:
            seconds_float = 0
            
        total_milliseconds = int((int(hours) * 3600 + int(minutes) * 60 + seconds_float) * 1000)
        
        # Thêm thời gian vào tất cả các phụ đề
        if total_milliseconds > 0:
            for sub in subs:
                sub.start.ordinal += total_milliseconds
                sub.end.ordinal += total_milliseconds
        
        # Xử lý dịch thuật
        if isinstance(model_info[0], tuple):
            # Dịch qua tiếng Anh
            model1, tokenizer1 = model_info[0]
            model2, tokenizer2 = model_info[1]
            
            for sub in tqdm(subs, desc="Đang dịch"):
                if sub.text.strip():
                    en_text = translate_text(sub.text, model1, tokenizer1)
                    sub.text = translate_text(en_text, model2, tokenizer2)
        else:
            # Dịch trực tiếp
            model, tokenizer = model_info
            for sub in tqdm(subs, desc="Đang dịch"):
                if sub.text.strip():
                    sub.text = translate_text(sub.text, model, tokenizer)
        
        # Lưu file tạm
        output_path = tempfile.NamedTemporaryFile(suffix=".srt", delete=False).name
        subs.save(output_path, encoding='utf-8')
        return output_path, f"Dịch từ {source_language} sang {target_language} thành công! Đã thêm {hours}h {minutes}m {seconds_float}s"
    
    except Exception as e:
        raise gr.Error(f"Có lỗi xảy ra: {str(e)}")

# Giao diện Gradio
with gr.Blocks(title="Subtitle Translator Pro", theme="soft") as demo:
    gr.Markdown("# 🎬 Subtitle Translator Pro")
    gr.Markdown("Dịch phụ đề (.srt) giữa nhiều ngôn ngữ khác nhau")
    
    with gr.Row():
        with gr.Column():
            file_input = gr.File(label="Upload file phụ đề (.srt)", file_types=[".srt"])
            
            with gr.Row():
                source_lang = gr.Dropdown(
                    choices=list(LANGUAGE_MODELS.keys()),
                    value="Tiếng Anh",
                    label="Ngôn ngữ nguồn",
                    interactive=True
                )
                auto_detect = gr.Checkbox(label="Tự động phát hiện ngôn ngữ", value=True)
            
            target_lang = gr.Dropdown(
                choices=list(LANGUAGE_MODELS.keys()),
                value="Tiếng Việt",
                label="Ngôn ngữ đích"
            )
            
            with gr.Row():
                hours = gr.Number(label="Giờ", value=0, precision=0, minimum=0)
                minutes = gr.Number(label="Phút", value=0, precision=0, minimum=0, maximum=59)
                seconds = gr.Number(label="Giây", value=0, minimum=0, step=0.1)
            
            with gr.Row():
                add_time_btn = gr.Button("Chỉ thêm thời gian", variant="secondary")
                translate_btn = gr.Button("Dịch phụ đề", variant="primary")
        
        with gr.Column():
            file_output = gr.File(label="File phụ đề đã xử lý", interactive=False)
            status = gr.Textbox(label="Trạng thái")
    
    # Xử lý khi upload file
    def on_file_upload(file, auto_detect_flag):
        if file and auto_detect_flag:
            try:
                lang_code = detect_subtitle_language(file.name)
                detected_lang = LANGUAGE_CODES.get(lang_code, "Tiếng Anh")
                return gr.Dropdown(value=detected_lang)
            except:
                return gr.Dropdown(value="Tiếng Anh")
        return gr.Dropdown()
    
    file_input.upload(
        fn=on_file_upload,
        inputs=[file_input, auto_detect],
        outputs=source_lang
    )
    
    # Xử lý khi nhấn nút thêm thời gian
    add_time_btn.click(
        fn=add_time_to_subtitle,
        inputs=[file_input, hours, minutes, seconds],
        outputs=[file_output, status]
    )
    
    # Xử lý khi nhấn nút dịch phụ đề
    translate_btn.click(
        fn=translate_subtitle,
        inputs=[file_input, source_lang, target_lang, hours, minutes, seconds],
        outputs=[file_output, status]
    )
    
    gr.Markdown("### Thông tin")
    gr.Markdown("""
    - Hỗ trợ định dạng .srt
    - Tự động phát hiện ngôn ngữ nguồn
    - Dịch giữa 24 ngôn ngữ khác nhau
    - Hỗ trợ dịch qua tiếng Anh nếu không có model trực tiếp
    - Thêm thời gian vào tất cả phụ đề (hỗ trợ giây thập phân)
    - Có nút riêng để chỉ thêm thời gian trước khi dịch
    """)

if __name__ == "__main__":
    demo.launch()