File size: 6,037 Bytes
a30e87b d24a2f3 74d8a08 8a409a5 08c3547 d24a2f3 d6208ae 202112a 8a409a5 08c3547 d24a2f3 a30e87b 08c3547 8a409a5 a30e87b d24a2f3 8a409a5 d24a2f3 a30e87b d24a2f3 a30e87b d24a2f3 a30e87b 8a409a5 a30e87b d6208ae d24a2f3 ab46005 a30e87b ab46005 d24a2f3 a30e87b 8a409a5 74d8a08 8a409a5 a30e87b 8a409a5 a30e87b 202112a 8a409a5 a30e87b 08c3547 8a409a5 a30e87b 1dc264f 8a409a5 a30e87b d24a2f3 a30e87b 74d8a08 a30e87b 1dc264f a30e87b 74d8a08 08c3547 8a409a5 9814147 8a409a5 a30e87b d6208ae a30e87b 9814147 a30e87b 9814147 a30e87b 9814147 a30e87b d6208ae a30e87b d6208ae a30e87b d6208ae ab46005 a30e87b d6208ae a30e87b 9814147 a30e87b 08c3547 a30e87b 8a409a5 d61bf06 |
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 |
# app.py
import os
import time
import tempfile
import uuid
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 and load secrets
load_dotenv()
app = Flask(__name__)
# Configuration
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
TTS_API_URL = os.getenv("TTS_API_URL")
if not GEMINI_API_KEY:
raise ValueError("GEMINI_API_KEY not found in .env file!")
if not TTS_API_URL:
raise ValueError("TTS_API_URL not found in .env file!")
genai.configure(api_key=GEMINI_API_KEY)
# Setup directories
UPLOAD_FOLDER = 'uploads'
DOWNLOAD_FOLDER = 'downloads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(DOWNLOAD_FOLDER, exist_ok=True)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['DOWNLOAD_FOLDER'] = DOWNLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024
app.secret_key = os.urandom(24)
# Constants
VOICE_CHOICES = {
"Male (Charon)": "Charon",
"Female (Zephyr)": "Zephyr"
}
GEMINI_PROMPT = """
You are an expert AI scriptwriter. Your task is to watch the provided video and transcribe ALL spoken dialogue into a SINGLE, CONTINUOUS block of modern, colloquial Tamil.
**CRITICAL INSTRUCTIONS:**
1. Combine all dialogue into one continuous script.
2. NO timestamps or speaker labels.
3. Add performance directions (e.g., `Say happily:`, `[laugh]`) directly in the text.
**EXAMPLE OUTPUT:**
Say happily: வணக்கம்! [laugh] எப்படி இருக்கீங்க? Whisper mysteriously: அந்த ரகசியம் எனக்கு மட்டும் தான் தெரியும்.
"""
def generate_tamil_script(video_path):
"""Generate Tamil script from video using Gemini AI"""
print("Uploading video to Gemini...")
video_file = genai.upload_file(video_path, mime_type="video/mp4")
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(f"Gemini processing failed: {video_file.state.name}")
model = genai.GenerativeModel(model_name="models/gemini-2.5-flash")
response = model.generate_content([GEMINI_PROMPT, video_file])
genai.delete_file(video_file.name)
if hasattr(response, 'text') and response.text:
return " ".join(response.text.strip().splitlines())
raise Exception("No valid script generated")
def generate_audio(script, voice, is_cheerful, output_path):
"""Generate audio from script using TTS API"""
print(f"Generating audio (Voice: {voice}, Cheerful: {is_cheerful})")
payload = {
"text": script,
"voice_name": voice,
"cheerful": is_cheerful
}
response = requests.post(TTS_API_URL, json=payload, timeout=300)
if response.status_code == 200:
with open(output_path, "wb") as f:
f.write(response.content)
return True
raise Exception(f"TTS API error: {response.status_code} - {response.text}")
def dub_video(video_path, audio_path, output_path):
"""Replace video audio with generated audio"""
print("Dubbing video...")
video_clip = AudioFileClip = None
try:
video_clip = VideoFileClip(video_path)
audio_clip = AudioFileClip(audio_path)
video_clip.audio = audio_clip
video_clip.write_videofile(
output_path,
codec="libx264",
audio_codec="aac",
logger='bar'
)
finally:
if audio_clip: audio_clip.close()
if video_clip: video_clip.close()
@app.route('/', methods=['GET'])
def index():
return render_template('index.html')
@app.route('/process', methods=['POST'])
def process_video():
input_path = audio_path = None
try:
# Validate upload
if 'video' not in request.files:
flash("No file selected", "error")
return render_template('index.html')
file = request.files['video']
if file.filename == '':
flash("No file selected", "error")
return render_template('index.html')
# Save uploaded file
filename = secure_filename(file.filename)
input_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(input_path)
# Process options
voice = VOICE_CHOICES[request.form['voice_choice']]
cheerful = 'cheerful' in request.form
# Generate script and audio
script = generate_tamil_script(input_path)
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
audio_path = f.name
generate_audio(script, voice, cheerful, audio_path)
# Create dubbed video
output_filename = f"dubbed_{filename}"
output_path = os.path.join(app.config['DOWNLOAD_FOLDER'], output_filename)
dub_video(input_path, audio_path, output_path)
flash("Video processing complete!", "success")
return render_template('index.html',
result_video=url_for('serve_video', filename=output_filename),
script=script)
except Exception as e:
print(f"Error: {e}")
flash(f"Processing failed: {str(e)}", "error")
return render_template('index.html')
finally:
# Cleanup temp files
if input_path and os.path.exists(input_path):
os.remove(input_path)
if audio_path and os.path.exists(audio_path):
os.remove(audio_path)
@app.route('/downloads/<filename>')
def serve_video(filename):
return send_from_directory(app.config['DOWNLOAD_FOLDER'], filename)
if __name__ == '__main__':
app.run(host="0.0.0.0", port=7860) |