File size: 6,622 Bytes
41b946f c095744 |
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 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
import os
import tempfile
import gradio as gr
import moviepy.editor as mp
import subprocess
import assemblyai as aai
import yt_dlp
import shutil
import time
from pathlib import Path
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
# # AssemblyAI API settings
# API_KEY = os.getenv("ASSEMBLYAI_API_KEY", "335c7fb7f8544ec58299700d43d8a592")
# aai.settings.api_key = API_KEY
API_KEY = os.getenv("ASSEMBLYAI_API_KEY")
if not API_KEY:
raise ValueError("API key for AssemblyAI is not set. Please check your .env file.")
aai.settings.api_key = API_KEY
# Step 1: Download YouTube video if URL is provided
def download_youtube(youtube_url, output_path):
ydl_opts = {
'format': 'best[ext=mp4]',
'outtmpl': output_path,
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([youtube_url])
return output_path
# Step 2: Extract audio from video
def extract_audio(video_path, audio_path):
video = mp.VideoFileClip(video_path)
video.audio.write_audiofile(audio_path, verbose=False, logger=None)
return audio_path
# Step 3: Transcribe the audio with AssemblyAI
def transcribe_audio(audio_path):
transcriber = aai.Transcriber()
transcript = transcriber.transcribe(audio_path)
if transcript.status == aai.TranscriptStatus.error:
return None, f"Transcription Error: {transcript.error}"
subtitle_path = os.path.join(tempfile.gettempdir(), "subtitle.srt")
with open(subtitle_path, 'w', encoding='utf-8') as f:
f.write(transcript.export_subtitles_srt())
return subtitle_path, "Transcription completed successfully"
# Step 4: Add subtitles to video with improved path handling
def add_subtitles(video_path, subtitle_path, output_path):
# Create a temporary copy of the subtitle file in the same directory as the output
output_dir = os.path.dirname(output_path)
temp_subtitle = os.path.join(output_dir, "temp_subtitle.srt")
# Copy subtitle file to output directory
shutil.copy(subtitle_path, temp_subtitle)
# Use the file name only for the subtitles filter
subtitle_filename = os.path.basename(temp_subtitle)
# Escape any special characters in paths
subtitle_filename = subtitle_filename.replace("'", "'\\''")
# Build the FFmpeg command with proper path handling
command = [
"ffmpeg",
"-i", video_path,
"-vf", f"subtitles={subtitle_filename}:force_style='Fontname=Arial,Fontsize=30,PrimaryColour=&HFFFFFF,OutlineColour=&H000000,BorderStyle=3,Outline=1'",
"-c:a", "copy",
"-y", # Override output file if it exists
output_path
]
# Change working directory to where the subtitle file is
current_dir = os.getcwd()
os.chdir(output_dir)
try:
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
if result.returncode == 0:
return output_path, "Subtitles added successfully!"
else:
return None, f"Error adding subtitles: {result.stderr}"
finally:
# Change back to original directory and clean up
os.chdir(current_dir)
try:
os.remove(temp_subtitle)
except:
pass
# Main processing function for Gradio with progress tracking
def process_video(video_input, youtube_url, progress=gr.Progress()):
# Create temp directory for processing
temp_dir = tempfile.mkdtemp()
# Start progress tracking (0-100%)
progress(0, desc="Starting process...")
# Input handling
if youtube_url:
input_video = os.path.join(temp_dir, "youtube_video.mp4")
status_msg = f"Downloading YouTube video: {youtube_url}"
progress(5, desc="Downloading YouTube video...")
yield None, status_msg
try:
download_youtube(youtube_url, input_video)
except Exception as e:
yield None, f"Error downloading YouTube video: {str(e)}"
return
else:
input_video = video_input
if not input_video:
yield None, "Please provide either a video file or a YouTube URL"
return
# Extract audio
audio_path = os.path.join(temp_dir, "extracted_audio.mp3")
status_msg = "Extracting audio from video..."
progress(20, desc="Extracting audio...")
yield None, status_msg
try:
extract_audio(input_video, audio_path)
except Exception as e:
yield None, f"Error extracting audio: {str(e)}"
return
# Transcribe audio
status_msg = "Transcribing audio..."
progress(40, desc="Transcribing audio...")
yield None, status_msg
try:
subtitle_path, msg = transcribe_audio(audio_path)
if not subtitle_path:
yield None, msg
return
except Exception as e:
yield None, f"Error during transcription: {str(e)}"
return
# Add subtitles to video
output_path = os.path.join(temp_dir, "output_with_subtitles.mp4")
status_msg = "Adding subtitles to video..."
progress(70, desc="Adding subtitles...")
yield None, status_msg
try:
result_path, msg = add_subtitles(input_video, subtitle_path, output_path)
if not result_path:
yield None, msg
return
progress(95, desc="Finalizing...")
time.sleep(1) # Small delay to ensure UI updates
progress(100, desc="Complete!")
yield result_path, "Process completed successfully! Your video with subtitles is ready."
except Exception as e:
yield None, f"Error adding subtitles: {str(e)}"
# Create Gradio Interface
with gr.Blocks(title="Video Subtitle Generator") as app:
gr.Markdown(
"""
# 🎬 Video Subtitle Generator
Upload a video file or provide a YouTube URL to generate subtitles.
"""
)
with gr.Row():
with gr.Column(scale=1):
video_input = gr.Video(label="Upload Video")
youtube_url = gr.Textbox(label="Or Enter YouTube URL")
submit_btn = gr.Button("Generate Subtitles", variant="primary")
with gr.Column(scale=1):
output_video = gr.Video(label="Video with Subtitles")
status = gr.Textbox(label="Status", value="Ready to process")
submit_btn.click(
fn=process_video,
inputs=[video_input, youtube_url],
outputs=[output_video, status],
show_progress=True
)
# Launch app
if __name__ == "__main__":
app.launch(debug=True) |