# app.py import os import time import tempfile import google.generativeai as genai import requests from flask import Flask, request, render_template, send_from_directory, url_for, flash from moviepy.video.io.VideoFileClip import VideoFileClip from moviepy.audio.io.AudioFileClip import AudioFileClip from werkzeug.utils import secure_filename from dotenv import load_dotenv # Initialize Flask app load_dotenv() app = Flask(__name__) # Configuration app.config.update({ 'GEMINI_API_KEY': os.getenv('GEMINI_API_KEY'), 'TTS_API_URL': os.getenv('TTS_API_URL'), 'UPLOAD_FOLDER': 'uploads', 'DOWNLOAD_FOLDER': 'downloads', 'MAX_CONTENT_LENGTH': 100 * 1024 * 1024, # 100MB 'SECRET_KEY': os.urandom(24), 'ALLOWED_EXTENSIONS': {'mp4', 'mov', 'webm', 'avi'} }) # Create directories if they don't exist os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) os.makedirs(app.config['DOWNLOAD_FOLDER'], exist_ok=True) # Initialize Gemini AI genai.configure(api_key=app.config['GEMINI_API_KEY']) # Constants VOICE_CHOICES = { "Male (Deep Voice)": "deep_male", "Female (Soft Tone)": "soft_female", "Neutral (Professional)": "neutral" } GEMINI_PROMPT = """ You are an expert AI scriptwriter. Analyze this video and: 1. Transcribe ALL dialogue into continuous Tamil 2. Remove timestamps/speaker labels 3. Add expressive directions like [laugh] or [pause] 4. Keep natural flow and cultural context Example Output: [cheerful] வணக்கம்! [laugh] இன்று நிலைமை எப்படி இருக்கிறது? [serious] இதை கவனமாக கேளுங்கள்... """ def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS'] def generate_script(video_path): """Generate Tamil script using Gemini AI""" try: print("Uploading video to Gemini...") video_file = genai.upload_file(video_path, mime_type="video/mp4") # Wait for processing while video_file.state.name == "PROCESSING": time.sleep(5) video_file = genai.get_file(video_file.name) if video_file.state.name != "ACTIVE": raise Exception("Gemini processing failed") model = genai.GenerativeModel("models/gemini-pro-vision") response = model.generate_content([GEMINI_PROMPT, video_file]) genai.delete_file(video_file.name) return response.text.strip() if hasattr(response, 'text') else "" except Exception as e: print(f"Gemini Error: {str(e)}") raise def generate_audio(script, voice, tone): """Generate audio using TTS API""" try: response = requests.post( app.config['TTS_API_URL'], json={ "text": script, "voice": voice, "tone": tone }, timeout=300 ) response.raise_for_status() return response.content except requests.exceptions.RequestException as e: print(f"TTS API Error: {str(e)}") raise def process_video(input_path, audio_data, output_filename): """Combine video with new audio track""" try: with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as audio_temp: audio_temp.write(audio_data) audio_temp_path = audio_temp.name video = VideoFileClip(input_path) audio = AudioFileClip(audio_temp_path) # Ensure audio matches video duration if audio.duration > video.duration: audio = audio.subclip(0, video.duration) video.audio = audio output_path = os.path.join(app.config['DOWNLOAD_FOLDER'], output_filename) video.write_videofile( output_path, codec='libx264', audio_codec='aac', threads=4, logger=None ) return output_path except Exception as e: print(f"Video Processing Error: {str(e)}") raise finally: if 'video' in locals(): video.close() if 'audio' in locals(): audio.close() if os.path.exists(audio_temp_path): os.remove(audio_temp_path) @app.route('/', methods=['GET']) def home(): return render_template('index.html', voices=VOICE_CHOICES) @app.route('/process', methods=['POST']) def process(): if 'video' not in request.files: flash('No file selected', 'error') return render_template('index.html', voices=VOICE_CHOICES) file = request.files['video'] if file.filename == '': flash('No file selected', 'error') return render_template('index.html', voices=VOICE_CHOICES) if not allowed_file(file.filename): flash('Invalid file type. Allowed: MP4, MOV, WEBM, AVI', 'error') return render_template('index.html', voices=VOICE_CHOICES) try: # Save uploaded file filename = secure_filename(file.filename) input_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) file.save(input_path) # Get processing options voice = request.form.get('voice', 'neutral') tone = 'cheerful' if request.form.get('tone') == 'on' else 'neutral' # Generate script and audio script = generate_script(input_path) audio_data = generate_audio(script, voice, tone) # Process video output_filename = f"dubbed_{filename}" output_path = process_video(input_path, audio_data, output_filename) flash('Processing completed successfully!', 'success') return render_template('result.html', video_url=url_for('download', filename=output_filename), script=script) except Exception as e: flash(f'Processing failed: {str(e)}', 'error') return render_template('index.html', voices=VOICE_CHOICES) finally: if 'input_path' in locals() and os.path.exists(input_path): os.remove(input_path) @app.route('/downloads/') def download(filename): return send_from_directory(app.config['DOWNLOAD_FOLDER'], filename) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)