Athspi commited on
Commit
1d3d329
·
verified ·
1 Parent(s): 92e0210

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +141 -115
app.py CHANGED
@@ -7,18 +7,18 @@ import logging
7
  import srt
8
  import datetime
9
  from gtts import gTTS
10
- from flask import Flask, request, render_template, send_from_directory, url_for, flash, session
11
  from werkzeug.utils import secure_filename
12
  import uuid
13
 
14
  # --- Configuration ---
15
 
16
- # Suppress moviepy logs
 
17
  logging.getLogger("moviepy").setLevel(logging.ERROR)
18
 
19
  # Configure Gemini API
20
  # IMPORTANT: Set your GEMINI_API_KEY as an environment variable
21
- # For example, in your terminal: export GEMINI_API_KEY="YOUR_API_KEY"
22
  try:
23
  genai.configure(api_key=os.environ["GEMINI_API_KEY"])
24
  except KeyError:
@@ -28,10 +28,10 @@ except KeyError:
28
  # --- Flask App Initialization ---
29
  app = Flask(__name__)
30
  app.config['SECRET_KEY'] = os.urandom(24)
31
- app.config['UPLOAD_FOLDER'] = os.path.join(os.getcwd(), 'temp_uploads')
32
-
33
- # Ensure the upload folder exists
34
- os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
35
 
36
 
37
  # --- Model and Language Configuration ---
@@ -46,11 +46,11 @@ generation_config = {
46
  }
47
 
48
  model = genai.GenerativeModel(
49
- model_name="gemini-1.5-pro-latest", # Using a stable and capable model
50
  generation_config=generation_config,
51
  )
52
 
53
- # List of all supported languages
54
  SUPPORTED_LANGUAGES = [
55
  "Auto Detect", "English", "Chinese", "German", "Spanish", "Russian", "Korean",
56
  "French", "Japanese", "Portuguese", "Turkish", "Polish", "Catalan", "Dutch",
@@ -70,61 +70,47 @@ SUPPORTED_LANGUAGES = [
70
  "Sundanese"
71
  ]
72
 
73
- # Language code mapping for gTTS
74
  LANGUAGE_CODES = {
75
- "English": "en", "Chinese": "zh", "German": "de", "Spanish": "es",
76
- "Russian": "ru", "Korean": "ko", "French": "fr", "Japanese": "ja",
77
- "Portuguese": "pt", "Turkish": "tr", "Polish": "pl", "Catalan": "ca",
78
- "Dutch": "nl", "Arabic": "ar", "Swedish": "sv", "Italian": "it",
79
- "Indonesian": "id", "Hindi": "hi", "Finnish": "fi", "Vietnamese": "vi",
80
- "Hebrew": "he", "Ukrainian": "uk", "Greek": "el", "Malay": "ms",
81
- "Czech": "cs", "Romanian": "ro", "Danish": "da", "Hungarian": "hu",
82
- "Tamil": "ta", "Norwegian": "no", "Thai": "th", "Urdu": "ur",
83
- "Croatian": "hr", "Bulgarian": "bg", "Lithuanian": "lt", "Latin": "la",
84
- "Maori": "mi", "Malayalam": "ml", "Welsh": "cy", "Slovak": "sk",
85
- "Telugu": "te", "Persian": "fa", "Latvian": "lv", "Bengali": "bn",
86
- "Serbian": "sr", "Azerbaijani": "az", "Slovenian": "sl", "Kannada": "kn",
87
- "Estonian": "et", "Macedonian": "mk", "Breton": "br", "Basque": "eu",
88
- "Icelandic": "is", "Armenian": "hy", "Nepali": "ne", "Mongolian": "mn",
89
- "Bosnian": "bs", "Kazakh": "kk", "Albanian": "sq", "Swahili": "sw",
90
- "Galician": "gl", "Marathi": "mr", "Punjabi": "pa", "Sinhala": "si",
91
- "Khmer": "km", "Shona": "sn", "Yoruba": "yo", "Somali": "so",
92
- "Afrikaans": "af", "Occitan": "oc", "Georgian": "ka", "Belarusian": "be",
93
- "Tajik": "tg", "Sindhi": "sd", "Gujarati": "gu", "Amharic": "am",
94
- "Yiddish": "yi", "Lao": "lo", "Uzbek": "uz", "Faroese": "fo",
95
- "Haitian Creole": "ht", "Pashto": "ps", "Turkmen": "tk", "Nynorsk": "nn",
96
- "Maltese": "mt", "Sanskrit": "sa", "Luxembourgish": "lb", "Burmese": "my",
97
- "Tibetan": "bo", "Tagalog": "tl", "Malagasy": "mg", "Assamese": "as",
98
- "Tatar": "tt", "Hawaiian": "haw", "Lingala": "ln", "Hausa": "ha",
99
- "Bashkir": "ba", "Javanese": "jv", "Sundanese": "su"
100
  }
101
 
102
 
103
  # --- Core Processing Functions ---
104
 
105
- def time_to_seconds(time_obj):
106
- """Convert datetime.time object to seconds."""
107
- return time_obj.hour * 3600 + time_obj.minute * 60 + time_obj.second + time_obj.microsecond / 1e6
108
-
109
  def extract_audio_from_video(video_path, audio_path):
110
- """Extract audio from a video file and save it as a WAV file."""
111
  try:
112
- video = VideoFileClip(video_path)
113
- video.audio.write_audiofile(audio_path, fps=16000, logger=None)
114
  return audio_path
115
  except Exception as e:
116
  logging.error(f"Error extracting audio: {e}")
117
  return None
118
 
119
  def transcribe_audio_with_gemini(audio_path, source_language):
120
- """Transcribe audio using Gemini with a prompt for accurate timestamps."""
121
  try:
 
122
  audio_file = genai.upload_file(path=audio_path)
 
123
  language_prompt = f"in {source_language}" if source_language != "Auto Detect" else ""
124
 
125
  prompt = f"""
126
  You are a professional transcriber. Transcribe this audio accurately and verbatim {language_prompt}.
127
- Include timestamps for each sentence in the SRT (SubRip) format.
128
  Example:
129
  1
130
  00:00:01,234 --> 00:00:05,678
@@ -134,12 +120,14 @@ def transcribe_audio_with_gemini(audio_path, source_language):
134
  00:00:06,123 --> 00:00:09,456
135
  This is the second sentence.
136
 
137
- Ensure the timestamps are precise and correspond to the start and end of each spoken sentence.
138
- Respond ONLY with the transcription in the SRT format. Do not add explanations or any extra text.
139
  """
140
 
141
- response = model.generate_content([prompt, audio_file])
 
142
  genai.delete_file(audio_file.name) # Clean up the uploaded file
 
143
  return response.text.strip()
144
  except Exception as e:
145
  logging.error(f"Error during Gemini transcription: {e}")
@@ -147,61 +135,98 @@ def transcribe_audio_with_gemini(audio_path, source_language):
147
 
148
 
149
  def translate_srt(srt_text, target_language):
150
- """Translate an SRT file using Gemini while preserving timestamps."""
151
  try:
152
  prompt = f"""
153
  Translate the following SRT subtitles into {target_language}.
154
  Preserve the SRT format perfectly (index numbers, timestamps, and structure).
155
- Translate only the subtitle text on the lines after the timestamps.
156
- Do not add any explanations or extra text. Your output must be a valid SRT file.
157
- Here is the SRT file content:
 
 
158
  {srt_text}
159
  """
 
160
  response = model.generate_content(prompt)
 
161
  return response.text.strip()
162
  except Exception as e:
163
  logging.error(f"Error during translation: {e}")
164
  return None
165
 
166
  def generate_tts_audio(srt_text, language, tts_audio_path):
167
- """Generate TTS audio from SRT text."""
168
  try:
169
  subtitles = list(srt.parse(srt_text))
170
- all_text = " ".join([sub.content for sub in subtitles])
171
 
172
- lang_code = LANGUAGE_CODES.get(language, "en")
 
 
 
 
 
 
173
 
174
- tts = gTTS(text=all_text, lang=lang_code, slow=False)
 
175
  tts.save(tts_audio_path)
 
176
  return tts_audio_path
177
  except Exception as e:
178
  logging.error(f"Error generating TTS audio: {e}")
179
  return None
180
 
181
- def add_subtitles_to_video(video_path, srt_text, output_video_path):
182
- """Add subtitles to video and return the path to the new video."""
 
 
 
 
183
  try:
184
- def generator(txt):
185
- return TextClip(txt, font='Arial-Bold', fontsize=24, color='white',
186
- stroke_color='black', stroke_width=1)
187
 
188
- # MoviePy's SubtitlesClip requires a file path
189
- with tempfile.NamedTemporaryFile(mode='w', suffix='.srt', delete=False, encoding='utf-8') as temp_srt:
190
- temp_srt.write(srt_text)
191
- srt_path = temp_srt.name
 
 
192
 
193
- video = VideoFileClip(video_path)
194
- subtitles = SubtitlesClip(srt_path, generator)
195
-
196
- result = CompositeVideoClip([video, subtitles.set_position(('center', 'bottom'))])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
 
198
- # Write output with original audio
199
- result.write_videofile(output_video_path, codec='libx264', audio_codec='aac', threads=4, logger=None)
 
 
200
 
201
- os.remove(srt_path) # Clean up temp srt file
202
- return output_video_path
203
  except Exception as e:
204
- logging.error(f"Error adding subtitles to video: {e}")
205
  return None
206
 
207
 
@@ -209,22 +234,19 @@ def add_subtitles_to_video(video_path, srt_text, output_video_path):
209
 
210
  @app.route('/')
211
  def index():
212
- """Render the main page."""
213
- session.clear() # Clear any old data
214
  return render_template('index.html', supported_languages=SUPPORTED_LANGUAGES)
215
 
216
  @app.route('/process', methods=['POST'])
217
  def process():
218
- """Handle the video processing request."""
219
- if 'video' not in request.files:
220
  flash('No video file selected. Please upload a video.', 'error')
221
- return render_template('index.html', supported_languages=SUPPORTED_LANGUAGES)
222
 
223
  video_file = request.files['video']
224
- if video_file.filename == '':
225
- flash('No video file selected. Please upload a video.', 'error')
226
- return render_template('index.html', supported_languages=SUPPORTED_LANGUAGES)
227
-
228
  # --- Get form options ---
229
  source_language = request.form.get('source_language', 'Auto Detect')
230
  translate_to = request.form.get('translate_to', 'None')
@@ -238,68 +260,72 @@ def process():
238
  os.makedirs(session_dir, exist_ok=True)
239
 
240
  filename = secure_filename(video_file.filename)
241
- video_path = os.path.join(session_dir, filename)
242
- video_file.save(video_path)
243
 
244
  results = {}
245
 
246
  # 1. Extract Audio
247
  audio_path = os.path.join(session_dir, "extracted_audio.wav")
248
- if not extract_audio_from_video(video_path, audio_path):
249
- flash('Failed to extract audio from the video.', 'error')
250
- return render_template('index.html', supported_languages=SUPPORTED_LANGUAGES)
251
 
252
  # 2. Transcribe Audio
253
  original_srt_text = transcribe_audio_with_gemini(audio_path, source_language)
 
254
  if not original_srt_text:
255
- flash('Failed to transcribe the audio. The API call might have failed.', 'error')
256
- return render_template('index.html', supported_languages=SUPPORTED_LANGUAGES)
257
-
258
  original_srt_path = os.path.join(session_dir, "original_subtitles.srt")
259
  with open(original_srt_path, "w", encoding="utf-8") as f:
260
  f.write(original_srt_text)
261
  results['original_srt_file'] = "original_subtitles.srt"
262
 
263
- # Keep track of the final SRT to use for TTS and video burn-in
 
264
  final_srt_text = original_srt_text
265
 
266
  # 3. Translate Subtitles (if requested)
267
- if translate_to and translate_to != "None":
268
  translated_srt_text = translate_srt(original_srt_text, translate_to)
269
  if translated_srt_text:
270
  translated_srt_path = os.path.join(session_dir, "translated_subtitles.srt")
271
  with open(translated_srt_path, "w", encoding="utf-8") as f:
272
  f.write(translated_srt_text)
273
  results['translated_srt_file'] = "translated_subtitles.srt"
274
- final_srt_text = translated_srt_text # Use translated text for next steps
275
  else:
276
- flash(f'Failed to translate subtitles to {translate_to}.', 'warning')
277
 
278
  # 4. Generate TTS Audio (if requested)
279
  if add_tts:
280
- tts_lang = translate_to if translate_to and translate_to != "None" else source_language
281
- # If source was auto-detect, we can't reliably guess the TTS language. Default to English.
282
  if tts_lang == 'Auto Detect':
283
- flash('TTS language cannot be "Auto Detect". Defaulting to English. For better results, please specify the source language.', 'warning')
284
- tts_lang = 'English'
285
-
286
- tts_audio_path = os.path.join(session_dir, "tts_audio.mp3")
287
- if generate_tts_audio(final_srt_text, tts_lang, tts_audio_path):
288
- results['tts_audio_file'] = "tts_audio.mp3"
 
289
  else:
290
- flash('Failed to generate Text-to-Speech audio.', 'warning')
291
-
292
- # 5. Add Subtitles to Video (if requested)
 
293
  if add_subtitles:
294
- output_video_path = os.path.join(session_dir, "output_video.mp4")
295
- if add_subtitles_to_video(video_path, final_srt_text, output_video_path):
296
- results['output_video_file'] = "output_video.mp4"
 
 
 
 
297
  else:
298
- flash('Failed to add subtitles to the video.', 'warning')
299
-
300
- # Clean up original extracted audio
301
- os.remove(audio_path)
302
-
303
  return render_template('index.html',
304
  supported_languages=SUPPORTED_LANGUAGES,
305
  results=results,
@@ -307,11 +333,11 @@ def process():
307
 
308
  @app.route('/download/<session_id>/<path:filename>')
309
  def download_file(session_id, filename):
310
- """Serve files from the session directory for download."""
311
  directory = os.path.join(app.config['UPLOAD_FOLDER'], session_id)
312
  return send_from_directory(directory, filename, as_attachment=True)
313
 
314
 
315
  # --- Run the App ---
316
  if __name__ == '__main__':
317
- app.run(debug=True)
 
7
  import srt
8
  import datetime
9
  from gtts import gTTS
10
+ from flask import Flask, request, render_template, send_from_directory, url_for, flash, session, redirect
11
  from werkzeug.utils import secure_filename
12
  import uuid
13
 
14
  # --- Configuration ---
15
 
16
+ # Suppress moviepy logs which can be verbose
17
+ logging.basicConfig(level=logging.INFO)
18
  logging.getLogger("moviepy").setLevel(logging.ERROR)
19
 
20
  # Configure Gemini API
21
  # IMPORTANT: Set your GEMINI_API_KEY as an environment variable
 
22
  try:
23
  genai.configure(api_key=os.environ["GEMINI_API_KEY"])
24
  except KeyError:
 
28
  # --- Flask App Initialization ---
29
  app = Flask(__name__)
30
  app.config['SECRET_KEY'] = os.urandom(24)
31
+ # Create a permanent directory for uploads if it doesn't exist
32
+ UPLOAD_FOLDER = os.path.join(os.getcwd(), 'user_uploads')
33
+ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
34
+ app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
35
 
36
 
37
  # --- Model and Language Configuration ---
 
46
  }
47
 
48
  model = genai.GenerativeModel(
49
+ model_name="gemini-1.5-pro-latest",
50
  generation_config=generation_config,
51
  )
52
 
53
+ # List of all supported languages for the UI
54
  SUPPORTED_LANGUAGES = [
55
  "Auto Detect", "English", "Chinese", "German", "Spanish", "Russian", "Korean",
56
  "French", "Japanese", "Portuguese", "Turkish", "Polish", "Catalan", "Dutch",
 
70
  "Sundanese"
71
  ]
72
 
73
+ # Language code mapping for Google Text-to-Speech (gTTS)
74
  LANGUAGE_CODES = {
75
+ "English": "en", "Chinese": "zh", "German": "de", "Spanish": "es", "Russian": "ru",
76
+ "Korean": "ko", "French": "fr", "Japanese": "ja", "Portuguese": "pt", "Turkish": "tr",
77
+ "Polish": "pl", "Catalan": "ca", "Dutch": "nl", "Arabic": "ar", "Swedish": "sv",
78
+ "Italian": "it", "Indonesian": "id", "Hindi": "hi", "Finnish": "fi", "Vietnamese": "vi",
79
+ "Hebrew": "iw", "Ukrainian": "uk", "Greek": "el", "Malay": "ms", "Czech": "cs",
80
+ "Romanian": "ro", "Danish": "da", "Hungarian": "hu", "Tamil": "ta", "Norwegian": "no",
81
+ "Thai": "th", "Urdu": "ur", "Croatian": "hr", "Bulgarian": "bg", "Lithuanian": "lt",
82
+ "Latin": "la", "Malayalam": "ml", "Welsh": "cy", "Slovak": "sk", "Telugu": "te",
83
+ "Persian": "fa", "Latvian": "lv", "Bengali": "bn", "Serbian": "sr", "Slovenian": "sl",
84
+ "Kannada": "kn", "Estonian": "et", "Macedonian": "mk", "Armenian": "hy", "Nepali": "ne",
85
+ "Mongolian": "mn", "Bosnian": "bs", "Kazakh": "kk", "Albanian": "sq", "Swahili": "sw",
86
+ "Gujarati": "gu", "Lao": "lo", "Uzbek": "uz", "Maltese": "mt", "Burmese": "my",
87
+ "Tagalog": "tl", "Javanese": "jw", "Sundanese": "su", "Afrikaans": "af"
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
89
 
90
 
91
  # --- Core Processing Functions ---
92
 
 
 
 
 
93
  def extract_audio_from_video(video_path, audio_path):
94
+ """Extract audio from a video file into a WAV file."""
95
  try:
96
+ with VideoFileClip(video_path) as video:
97
+ video.audio.write_audiofile(audio_path, fps=16000, logger=None)
98
  return audio_path
99
  except Exception as e:
100
  logging.error(f"Error extracting audio: {e}")
101
  return None
102
 
103
  def transcribe_audio_with_gemini(audio_path, source_language):
104
+ """Transcribe audio using Gemini, requesting output in SRT format."""
105
  try:
106
+ logging.info(f"Uploading audio file: {audio_path}")
107
  audio_file = genai.upload_file(path=audio_path)
108
+
109
  language_prompt = f"in {source_language}" if source_language != "Auto Detect" else ""
110
 
111
  prompt = f"""
112
  You are a professional transcriber. Transcribe this audio accurately and verbatim {language_prompt}.
113
+ Your output MUST be in the SRT (SubRip) format.
114
  Example:
115
  1
116
  00:00:01,234 --> 00:00:05,678
 
120
  00:00:06,123 --> 00:00:09,456
121
  This is the second sentence.
122
 
123
+ Ensure timestamps are precise. Respond ONLY with the transcription in the SRT format.
124
+ Do not add explanations, notes, or any other text outside of the valid SRT content.
125
  """
126
 
127
+ logging.info("Sending transcription request to Gemini...")
128
+ response = model.generate_content([prompt, audio_file], request_options={"timeout": 600})
129
  genai.delete_file(audio_file.name) # Clean up the uploaded file
130
+ logging.info("Transcription received from Gemini.")
131
  return response.text.strip()
132
  except Exception as e:
133
  logging.error(f"Error during Gemini transcription: {e}")
 
135
 
136
 
137
  def translate_srt(srt_text, target_language):
138
+ """Translate an SRT file using Gemini while preserving its structure."""
139
  try:
140
  prompt = f"""
141
  Translate the following SRT subtitles into {target_language}.
142
  Preserve the SRT format perfectly (index numbers, timestamps, and structure).
143
+ Translate only the subtitle text itself.
144
+ Your output must be only the translated and valid SRT file content.
145
+ Do not add any explanations or extra text.
146
+
147
+ SRT Content to Translate:
148
  {srt_text}
149
  """
150
+ logging.info(f"Sending translation request to Gemini for {target_language}...")
151
  response = model.generate_content(prompt)
152
+ logging.info("Translation received.")
153
  return response.text.strip()
154
  except Exception as e:
155
  logging.error(f"Error during translation: {e}")
156
  return None
157
 
158
  def generate_tts_audio(srt_text, language, tts_audio_path):
159
+ """Generate a single TTS audio file from the text content of an SRT file."""
160
  try:
161
  subtitles = list(srt.parse(srt_text))
162
+ full_text = " ".join([sub.content.replace('\n', ' ') for sub in subtitles])
163
 
164
+ if not full_text:
165
+ return None
166
+
167
+ lang_code = LANGUAGE_CODES.get(language)
168
+ if not lang_code:
169
+ flash(f"Language '{language}' not supported for TTS, defaulting to English.", "warning")
170
+ lang_code = "en"
171
 
172
+ logging.info(f"Generating TTS audio in '{language}' ({lang_code})...")
173
+ tts = gTTS(text=full_text, lang=lang_code, slow=False)
174
  tts.save(tts_audio_path)
175
+ logging.info(f"TTS audio saved to {tts_audio_path}")
176
  return tts_audio_path
177
  except Exception as e:
178
  logging.error(f"Error generating TTS audio: {e}")
179
  return None
180
 
181
+ def create_final_video(original_video_path, srt_text, new_audio_path, output_path):
182
+ """
183
+ Creates the final video.
184
+ - If srt_text is provided, subtitles are burned in.
185
+ - If new_audio_path is provided, the original audio is replaced.
186
+ """
187
  try:
188
+ logging.info("Creating final video...")
189
+ original_clip = VideoFileClip(original_video_path)
 
190
 
191
+ # If new audio is provided, replace the original audio track
192
+ if new_audio_path:
193
+ tts_audio_clip = AudioFileClip(new_audio_path)
194
+ final_clip = original_clip.set_audio(tts_audio_clip)
195
+ else:
196
+ final_clip = original_clip
197
 
198
+ # If subtitle text is provided, burn it into the video
199
+ if srt_text:
200
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.srt', delete=False, encoding='utf-8') as temp_srt:
201
+ temp_srt.write(srt_text)
202
+ srt_filepath = temp_srt.name
203
+
204
+ # Subtitle styling
205
+ generator = lambda txt: TextClip(
206
+ txt, font='Arial-Bold', fontsize=24, color='white',
207
+ stroke_color='black', stroke_width=1.5, method='caption',
208
+ size=(final_clip.w * 0.8, None) # Subtitles take 80% of video width
209
+ )
210
+
211
+ subtitles_clip = SubtitlesClip(srt_filepath, generator)
212
+ # Composite the video with the subtitles
213
+ final_video = CompositeVideoClip([final_clip, subtitles_clip.set_position(('center', 'bottom'))])
214
+ os.remove(srt_filepath) # Clean up temp srt file
215
+ else:
216
+ final_video = final_clip
217
+
218
+ # Write the final video file
219
+ final_video.write_videofile(output_path, codec='libx264', audio_codec='aac', threads=4, logger=None)
220
 
221
+ # Close all clips to release memory
222
+ if 'tts_audio_clip' in locals():
223
+ tts_audio_clip.close()
224
+ final_video.close()
225
 
226
+ logging.info(f"Final video saved to {output_path}")
227
+ return output_path
228
  except Exception as e:
229
+ logging.error(f"Error creating final video: {e}")
230
  return None
231
 
232
 
 
234
 
235
  @app.route('/')
236
  def index():
237
+ """Render the main page. Clear session for a fresh start."""
238
+ session.clear()
239
  return render_template('index.html', supported_languages=SUPPORTED_LANGUAGES)
240
 
241
  @app.route('/process', methods=['POST'])
242
  def process():
243
+ """Handle the video processing request from the form."""
244
+ if 'video' not in request.files or request.files['video'].filename == '':
245
  flash('No video file selected. Please upload a video.', 'error')
246
+ return redirect(url_for('index'))
247
 
248
  video_file = request.files['video']
249
+
 
 
 
250
  # --- Get form options ---
251
  source_language = request.form.get('source_language', 'Auto Detect')
252
  translate_to = request.form.get('translate_to', 'None')
 
260
  os.makedirs(session_dir, exist_ok=True)
261
 
262
  filename = secure_filename(video_file.filename)
263
+ original_video_path = os.path.join(session_dir, filename)
264
+ video_file.save(original_video_path)
265
 
266
  results = {}
267
 
268
  # 1. Extract Audio
269
  audio_path = os.path.join(session_dir, "extracted_audio.wav")
270
+ if not extract_audio_from_video(original_video_path, audio_path):
271
+ flash('Failed to extract audio from the video. The file might be corrupted or in an unsupported format.', 'error')
272
+ return redirect(url_for('index'))
273
 
274
  # 2. Transcribe Audio
275
  original_srt_text = transcribe_audio_with_gemini(audio_path, source_language)
276
+ os.remove(audio_path) # Clean up extracted audio immediately
277
  if not original_srt_text:
278
+ flash('Failed to transcribe the audio. The API call might have failed or the audio is silent.', 'error')
279
+ return redirect(url_for('index'))
280
+
281
  original_srt_path = os.path.join(session_dir, "original_subtitles.srt")
282
  with open(original_srt_path, "w", encoding="utf-8") as f:
283
  f.write(original_srt_text)
284
  results['original_srt_file'] = "original_subtitles.srt"
285
 
286
+ srt_for_final_video = None
287
+ tts_audio_path = None
288
  final_srt_text = original_srt_text
289
 
290
  # 3. Translate Subtitles (if requested)
291
+ if translate_to != "None":
292
  translated_srt_text = translate_srt(original_srt_text, translate_to)
293
  if translated_srt_text:
294
  translated_srt_path = os.path.join(session_dir, "translated_subtitles.srt")
295
  with open(translated_srt_path, "w", encoding="utf-8") as f:
296
  f.write(translated_srt_text)
297
  results['translated_srt_file'] = "translated_subtitles.srt"
298
+ final_srt_text = translated_srt_text # Use translated text for subsequent steps
299
  else:
300
+ flash(f'Failed to translate subtitles to {translate_to}. Using original subtitles.', 'warning')
301
 
302
  # 4. Generate TTS Audio (if requested)
303
  if add_tts:
304
+ tts_lang = translate_to if translate_to != "None" else source_language
 
305
  if tts_lang == 'Auto Detect':
306
+ flash('TTS language cannot be "Auto Detect". Defaulting to English.', 'warning')
307
+ tts_lang = 'English'
308
+
309
+ tts_audio_path_out = os.path.join(session_dir, "tts_audio.mp3")
310
+ tts_audio_path = generate_tts_audio(final_srt_text, tts_lang, tts_audio_path_out)
311
+ if tts_audio_path:
312
+ results['tts_audio_file'] = "tts_audio.mp3"
313
  else:
314
+ flash('Failed to generate Text-to-Speech audio.', 'warning')
315
+ tts_audio_path = None # Ensure it's None if generation failed
316
+
317
+ # 5. Determine which subtitles to burn into the video (if requested)
318
  if add_subtitles:
319
+ srt_for_final_video = final_srt_text
320
+
321
+ # 6. Create the final output video if any processing was requested
322
+ if add_subtitles or add_tts:
323
+ output_video_path = os.path.join(session_dir, "final_video.mp4")
324
+ if create_final_video(original_video_path, srt_for_final_video, tts_audio_path, output_video_path):
325
+ results['output_video_file'] = "final_video.mp4"
326
  else:
327
+ flash('Failed to create the final processed video.', 'error')
328
+
 
 
 
329
  return render_template('index.html',
330
  supported_languages=SUPPORTED_LANGUAGES,
331
  results=results,
 
333
 
334
  @app.route('/download/<session_id>/<path:filename>')
335
  def download_file(session_id, filename):
336
+ """Serve files from the session-specific directory for download."""
337
  directory = os.path.join(app.config['UPLOAD_FOLDER'], session_id)
338
  return send_from_directory(directory, filename, as_attachment=True)
339
 
340
 
341
  # --- Run the App ---
342
  if __name__ == '__main__':
343
+ app.run(debug=True, port=5000)