Athspi commited on
Commit
74d8a08
·
verified ·
1 Parent(s): 5c69bfc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -33
app.py CHANGED
@@ -1,22 +1,23 @@
1
  import os
 
2
  import tempfile
3
  import google.generativeai as genai
4
  import requests
5
- from flask import Flask, request, render_template, send_from_directory, url_for
6
- from moviepy.video.io.VideoFileClip import VideoFileClip
7
- from moviepy.audio.io.AudioFileClip import AudioFileClip
8
- from pydub import AudioSegment
9
  from werkzeug.utils import secure_filename
10
- from google.generativeai.types import HarmCategory, HarmBlockThreshold
11
 
12
  # --- 1. INITIALIZE FLASK APP AND LOAD SECRETS ---
13
  app = Flask(__name__)
14
 
15
- # Load secrets from environment variables
16
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
17
  TTS_API_URL = os.getenv("TTS_API_URL")
18
 
19
- # Check if secrets were loaded correctly
 
 
 
20
  if not GEMINI_API_KEY:
21
  raise ValueError("GEMINI_API_KEY secret not found! Please set it as an environment variable.")
22
  if not TTS_API_URL:
@@ -25,7 +26,7 @@ if not TTS_API_URL:
25
  # Configure the Gemini API with the loaded key
26
  genai.configure(api_key=GEMINI_API_KEY)
27
 
28
- # Configure directories for file uploads and downloads
29
  UPLOAD_FOLDER = 'uploads'
30
  DOWNLOAD_FOLDER = 'downloads'
31
  os.makedirs(UPLOAD_FOLDER, exist_ok=True)
@@ -60,10 +61,10 @@ def generate_tamil_script(video_file_path):
60
 
61
  print("Waiting for file processing...")
62
  while video_file.state.name == "PROCESSING":
63
- time.sleep(10)
64
  video_file = genai.get_file(video_file.name)
65
  if video_file.state.name != "ACTIVE":
66
- raise Exception(f"File {video_file.name} failed to process")
67
 
68
  print("Generating single narrator script...")
69
  model = genai.GenerativeModel(model_name="models/gemini-1.5-pro-latest")
@@ -74,13 +75,13 @@ def generate_tamil_script(video_file_path):
74
 
75
  if response.text:
76
  return " ".join(response.text.strip().splitlines())
77
- raise Exception("No valid script was generated by Gemini.")
78
 
79
  def generate_single_audio_track(dialogue_text, voice_name, is_cheerful, output_path):
80
  """Generates one continuous audio track for the entire script."""
81
  print(f"Generating audio with voice '{voice_name}' | Cheerful: {is_cheerful}")
82
  payload = {"text": dialogue_text, "voice_name": voice_name, "cheerful": is_cheerful}
83
- response = requests.post(TTS_API_URL, json=payload)
84
  if response.status_code == 200:
85
  with open(output_path, "wb") as f:
86
  f.write(response.content)
@@ -91,13 +92,19 @@ def generate_single_audio_track(dialogue_text, voice_name, is_cheerful, output_p
91
  def replace_video_audio(video_path, new_audio_path, output_path):
92
  """Replaces the audio of a video with a new audio file."""
93
  print("Replacing video audio...")
94
- video_clip = VideoFileClip(video_path)
95
- audio_clip = AudioFileClip(new_audio_path)
96
- final_clip = video_clip.set_audio(audio_clip)
97
- final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac")
98
- video_clip.close()
99
- audio_clip.close()
100
- final_clip.close()
 
 
 
 
 
 
101
  print(f"Final video saved to {output_path}")
102
 
103
  # --- 4. FLASK ROUTES ---
@@ -111,26 +118,32 @@ def index():
111
  def process_video():
112
  """Handles the video upload and dubbing process."""
113
  if 'video' not in request.files:
114
- return "No video file part", 400
 
 
115
  file = request.files['video']
116
  if file.filename == '':
117
- return "No selected file", 400
 
118
 
119
  if file:
120
  filename = secure_filename(file.filename)
121
  upload_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
122
- file.save(upload_path)
123
-
124
- voice_choice = request.form['voice_choice']
125
- is_cheerful = 'cheerful' in request.form
126
- voice_name = VOICE_CHOICES[voice_choice]
127
 
128
  try:
 
 
 
 
 
 
129
  # Generate the script
130
  script = generate_tamil_script(upload_path)
131
 
132
- # Generate the audio track
133
- temp_audio_path = tempfile.mktemp(suffix=".wav")
 
134
  generate_single_audio_track(script, voice_name, is_cheerful, temp_audio_path)
135
 
136
  # Create the final video
@@ -138,17 +151,19 @@ def process_video():
138
  final_video_path = os.path.join(app.config['DOWNLOAD_FOLDER'], final_video_name)
139
  replace_video_audio(upload_path, temp_audio_path, final_video_path)
140
 
141
- # Clean up temporary audio file
142
- os.remove(temp_audio_path)
143
-
144
- # Render the same page but now with the results
145
  return render_template('index.html',
146
  result_video=url_for('serve_video', filename=final_video_name),
147
  script=script)
148
 
149
  except Exception as e:
150
  print(f"An error occurred: {e}")
151
- return f"An error occurred during processing: {e}", 500
 
 
 
 
 
152
 
153
  @app.route('/downloads/<filename>')
154
  def serve_video(filename):
 
1
  import os
2
+ import time
3
  import tempfile
4
  import google.generativeai as genai
5
  import requests
6
+ from flask import Flask, request, render_template, send_from_directory, url_for, flash
7
+ from moviepy.editor import VideoFileClip, AudioFileClip
 
 
8
  from werkzeug.utils import secure_filename
 
9
 
10
  # --- 1. INITIALIZE FLASK APP AND LOAD SECRETS ---
11
  app = Flask(__name__)
12
 
13
+ # Load secrets from environment variables for security
14
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
15
  TTS_API_URL = os.getenv("TTS_API_URL")
16
 
17
+ # Application needs a secret key for flashing messages
18
+ app.config['SECRET_KEY'] = os.urandom(24)
19
+
20
+ # Check if the secrets were loaded correctly
21
  if not GEMINI_API_KEY:
22
  raise ValueError("GEMINI_API_KEY secret not found! Please set it as an environment variable.")
23
  if not TTS_API_URL:
 
26
  # Configure the Gemini API with the loaded key
27
  genai.configure(api_key=GEMINI_API_KEY)
28
 
29
+ # Configure directories for file uploads and processed downloads
30
  UPLOAD_FOLDER = 'uploads'
31
  DOWNLOAD_FOLDER = 'downloads'
32
  os.makedirs(UPLOAD_FOLDER, exist_ok=True)
 
61
 
62
  print("Waiting for file processing...")
63
  while video_file.state.name == "PROCESSING":
64
+ time.sleep(5)
65
  video_file = genai.get_file(video_file.name)
66
  if video_file.state.name != "ACTIVE":
67
+ raise Exception(f"File {video_file.name} failed to process on Gemini's side.")
68
 
69
  print("Generating single narrator script...")
70
  model = genai.GenerativeModel(model_name="models/gemini-1.5-pro-latest")
 
75
 
76
  if response.text:
77
  return " ".join(response.text.strip().splitlines())
78
+ raise Exception("No valid script was generated by Gemini. The video might be silent or have unrecognized speech.")
79
 
80
  def generate_single_audio_track(dialogue_text, voice_name, is_cheerful, output_path):
81
  """Generates one continuous audio track for the entire script."""
82
  print(f"Generating audio with voice '{voice_name}' | Cheerful: {is_cheerful}")
83
  payload = {"text": dialogue_text, "voice_name": voice_name, "cheerful": is_cheerful}
84
+ response = requests.post(TTS_API_URL, json=payload, timeout=300) # Added timeout
85
  if response.status_code == 200:
86
  with open(output_path, "wb") as f:
87
  f.write(response.content)
 
92
  def replace_video_audio(video_path, new_audio_path, output_path):
93
  """Replaces the audio of a video with a new audio file."""
94
  print("Replacing video audio...")
95
+ try:
96
+ video_clip = VideoFileClip(video_path)
97
+ audio_clip = AudioFileClip(new_audio_path)
98
+ final_clip = video_clip.set_audio(audio_clip)
99
+ final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", logger='bar')
100
+ finally:
101
+ # Ensure clips are closed to release file handles
102
+ if 'video_clip' in locals():
103
+ video_clip.close()
104
+ if 'audio_clip' in locals():
105
+ audio_clip.close()
106
+ if 'final_clip' in locals():
107
+ final_clip.close()
108
  print(f"Final video saved to {output_path}")
109
 
110
  # --- 4. FLASK ROUTES ---
 
118
  def process_video():
119
  """Handles the video upload and dubbing process."""
120
  if 'video' not in request.files:
121
+ flash("No video file part in the request.", "error")
122
+ return render_template('index.html')
123
+
124
  file = request.files['video']
125
  if file.filename == '':
126
+ flash("No file was selected. Please choose a video to upload.", "error")
127
+ return render_template('index.html')
128
 
129
  if file:
130
  filename = secure_filename(file.filename)
131
  upload_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
132
+ temp_audio_path = None
 
 
 
 
133
 
134
  try:
135
+ file.save(upload_path)
136
+
137
+ voice_choice = request.form['voice_choice']
138
+ is_cheerful = 'cheerful' in request.form
139
+ voice_name = VOICE_CHOICES[voice_choice]
140
+
141
  # Generate the script
142
  script = generate_tamil_script(upload_path)
143
 
144
+ # Generate the audio track in a temporary file
145
+ temp_audio_fd, temp_audio_path = tempfile.mkstemp(suffix=".wav")
146
+ os.close(temp_audio_fd) # Close file descriptor
147
  generate_single_audio_track(script, voice_name, is_cheerful, temp_audio_path)
148
 
149
  # Create the final video
 
151
  final_video_path = os.path.join(app.config['DOWNLOAD_FOLDER'], final_video_name)
152
  replace_video_audio(upload_path, temp_audio_path, final_video_path)
153
 
154
+ # Render the page again with the results
 
 
 
155
  return render_template('index.html',
156
  result_video=url_for('serve_video', filename=final_video_name),
157
  script=script)
158
 
159
  except Exception as e:
160
  print(f"An error occurred: {e}")
161
+ flash(f"An error occurred during processing: {e}", "error")
162
+ return render_template('index.html')
163
+ finally:
164
+ # Clean up temporary audio file if it exists
165
+ if temp_audio_path and os.path.exists(temp_audio_path):
166
+ os.remove(temp_audio_path)
167
 
168
  @app.route('/downloads/<filename>')
169
  def serve_video(filename):