File size: 6,972 Bytes
5a30138
952467c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5a30138
 
 
 
 
b982edb
 
952467c
 
 
 
5a30138
 
 
 
 
 
 
 
 
952467c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5a30138
 
 
 
 
 
 
 
 
 
 
 
 
952467c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5a30138
952467c
 
5a30138
 
 
86b9702
5a30138
 
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

import os
import tempfile
import shutil
from pathlib import Path

import gradio as gr
from tqdm import tqdm

from src.utils.logger import get_logger
from src.audio.extractor import extract_audio, get_video_duration
from src.subtitles.transcriber import generate_subtitles
from src.subtitles.translator import translate_subtitles
from src.audio.generator import generate_translated_audio
from src.video.processor import combine_video_audio_subtitles
from config import LANGUAGES, OUTPUT_DIR, MAX_VIDEO_DURATION, MAX_UPLOAD_SIZE

logger = get_logger(__name__)

def process_video(video_file, source_lang, target_langs, progress=gr.Progress()):
    """
    Process video file and generate translated versions.
    """
    try:
        # Convert language names to codes
        source_lang_code = LANGUAGES[source_lang]
        target_lang_codes = [LANGUAGES[lang] for lang in target_langs]
        
        # Create temporary copy of uploaded file
        temp_dir = Path(tempfile.mkdtemp(prefix="video_processing_", dir=OUTPUT_DIR / "temp"))
        video_path = temp_dir / "input_video.mp4"
        shutil.copy2(video_file, video_path)
        
        logger.info(f"Processing video: {video_path}")
        logger.info(f"Source language: {source_lang} ({source_lang_code})")
        logger.info(f"Target languages: {', '.join(target_langs)} ({', '.join(target_lang_codes)})")
        
        # Check video duration
        progress(0.05, "Checking video duration...")
        duration = get_video_duration(video_path)
        if duration > MAX_VIDEO_DURATION:
            raise ValueError(f"Video is too long ({duration:.1f} seconds). Maximum allowed duration is {MAX_VIDEO_DURATION} seconds.")
        
        # Extract audio
        progress(0.1, "Extracting audio...")
        audio_path = extract_audio(video_path)
        
        # Generate subtitles
        progress(0.2, "Generating subtitles...")
        srt_path = generate_subtitles(audio_path, source_lang_code)
        
        # Translate subtitles
        progress(0.3, "Translating subtitles...")
        translated_srt_paths = translate_subtitles(srt_path, target_lang_codes)
        
        # Generate translated audio
        translated_audio_paths = {}
        for i, (lang_code, srt_path) in enumerate(translated_srt_paths.items()):
            progress_val = 0.3 + (0.4 * (i / len(translated_srt_paths)))
            progress(progress_val, f"Generating {[k for k, v in LANGUAGES.items() if v == lang_code][0]} audio...")
            audio_path = generate_translated_audio(srt_path, lang_code, duration)
            translated_audio_paths[lang_code] = audio_path
        
        # Combine video, audio, and subtitles
        output_videos = []
        for i, (lang_code, audio_path) in enumerate(translated_audio_paths.items()):
            progress_val = 0.7 + (0.25 * (i / len(translated_audio_paths)))
            lang_name = [k for k, v in LANGUAGES.items() if v == lang_code][0]
            progress(progress_val, f"Creating {lang_name} video...")
            
            srt_path = translated_srt_paths[lang_code]
            output_path = combine_video_audio_subtitles(video_path, audio_path, srt_path)
            output_videos.append(output_path)
        
        # Clean up
        try:
            shutil.rmtree(temp_dir)
        except:
            logger.warning(f"Failed to clean up temp directory: {temp_dir}")
            
        progress(1.0, "Translation complete!")
        return output_videos
        
    except Exception as e:
        logger.error(f"Video processing failed: {str(e)}", exc_info=True)
        raise gr.Error(f"Video processing failed: {str(e)}")

def create_app():
    """
    Create and configure the Gradio application.
    """
    # Get path to sample video
    sample_video_path = str(Path(__file__).parent / "samples" / "test_video.mp4")
    sample_exists = Path(sample_video_path).exists()

    with gr.Blocks(title="Video Translator") as app:
        gr.Markdown("# LinguaStream➿")
        gr.Markdown("A Multilingual Audio and Video dubbing tool with supported subtitles.")
        
        with gr.Row():
            with gr.Column(scale=1):
                video_input = gr.Video(label="Upload Video")
                
                # Sample video button
                if sample_exists:
                    with gr.Row():
                        sample_btn = gr.Button("Load Sample Video", variant="secondary")
                        @sample_btn.click(inputs=[], outputs=[video_input])
                        def load_sample():
                            return sample_video_path
                
                source_lang = gr.Dropdown(
                    choices=sorted(list(LANGUAGES.keys())), 
                    value="English", 
                    label="Source Language"
                )
                target_langs = gr.CheckboxGroup(
                    choices=[lang for lang in sorted(list(LANGUAGES.keys())) if lang != "English"],
                    value=["Spanish", "French"],
                    label="Target Languages"
                )
                translate_btn = gr.Button("Translate Video", variant="primary")
                
            with gr.Column(scale=2):
                output_gallery = gr.Gallery(
                    label="Translated Videos",
                    columns=2,
                    object_fit="contain",
                    height="auto"
                )
                
        translate_btn.click(
            fn=process_video,
            inputs=[video_input, source_lang, target_langs],
            outputs=output_gallery
        )
        
        # Add sample download instructions if sample doesn't exist
        if not sample_exists:
            gr.Markdown("""
            ## Sample Video Not Found
            To test the app, please upload your own video or place a test video at:
            `samples/test_video.mp4`
            """)
        else:
            gr.Markdown(f"""
            ## Sample Video Loaded
            Click "Load Sample Video" to test with a {get_video_duration(sample_video_path):.1f}-second sample.
            """)
        
        gr.Markdown("""
        ## How it works
        
        1. Upload a video (max 10 minutes)
        2. Select the source language of your video
        3. Choose the target languages you want to translate to
        4. Click "Translate Video" and wait for processing
        5. Download your translated videos!
        
        ## Features
        
        - Automatic speech recognition using AssemblyAI
        - Translation to multiple languages
        - Generated speech in target languages
        - Embedded subtitles
        """)
        
    return app

if __name__ == "__main__":
    # Create output directories if they don't exist
    (OUTPUT_DIR / "temp").mkdir(parents=True, exist_ok=True)
    (OUTPUT_DIR / "logs").mkdir(parents=True, exist_ok=True)
    
    app = create_app()
    app.launch()