Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -1,205 +1,24 @@
|
|
1 |
import gradio as gr
|
2 |
-
|
3 |
-
import librosa
|
4 |
-
from transformers import pipeline
|
5 |
-
from concurrent.futures import ThreadPoolExecutor
|
6 |
-
import tempfile
|
7 |
-
import docx # To create Word documents
|
8 |
-
from moviepy.video.tools.subtitles import SubtitlesClip
|
9 |
-
from moviepy.editor import TextClip
|
10 |
-
from pytube import YouTube # For downloading YouTube videos
|
11 |
|
12 |
-
#
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
translator = pipeline("translation", model="facebook/m2m100_418M")
|
17 |
-
|
18 |
-
# Store generated subtitles and translations
|
19 |
-
subtitle_storage = {}
|
20 |
-
|
21 |
-
# Supported languages with their codes
|
22 |
-
languages = {
|
23 |
-
"Persian": "fa",
|
24 |
-
"French": "fr",
|
25 |
-
"Spanish": "es",
|
26 |
-
"German": "de",
|
27 |
-
"Chinese": "zh",
|
28 |
-
"Arabic": "ar",
|
29 |
-
"Hindi": "hi",
|
30 |
-
"Russian": "ru"
|
31 |
-
}
|
32 |
-
|
33 |
-
def download_video_from_link(link):
|
34 |
-
"""Download a video from a YouTube link and return the file path."""
|
35 |
-
try:
|
36 |
-
yt = YouTube(link)
|
37 |
-
stream = yt.streams.filter(file_extension="mp4").first() # Downloading in mp4 format
|
38 |
-
video_file = stream.download() # Download to the current directory
|
39 |
-
return video_file
|
40 |
-
except Exception as e:
|
41 |
-
return f"Error downloading video: {e}"
|
42 |
-
|
43 |
-
def transcribe_audio(chunk):
|
44 |
-
"""Transcribe a single audio chunk."""
|
45 |
-
return asr(chunk)["text"]
|
46 |
-
|
47 |
-
def add_subtitle(video):
|
48 |
-
try:
|
49 |
-
video_path = video if isinstance(video, str) else None
|
50 |
-
if not video_path:
|
51 |
-
return "No video provided!"
|
52 |
-
|
53 |
-
video = mp.VideoFileClip(video_path)
|
54 |
-
audio = video.audio
|
55 |
-
|
56 |
-
# Extract audio to a temporary file
|
57 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as tmp_audio_file:
|
58 |
-
audio.write_audiofile(tmp_audio_file.name, codec='pcm_s16le')
|
59 |
-
waveform, sr = librosa.load(tmp_audio_file.name, sr=16000)
|
60 |
-
|
61 |
-
# Transcribe in chunks (parallel)
|
62 |
-
chunk_duration = 15 # seconds
|
63 |
-
chunk_size = sr * chunk_duration
|
64 |
-
chunks = [waveform[i:i + chunk_size] for i in range(0, len(waveform), chunk_size)]
|
65 |
-
|
66 |
-
with ThreadPoolExecutor() as executor:
|
67 |
-
transcriptions = list(executor.map(transcribe_audio, chunks))
|
68 |
-
|
69 |
-
full_transcription = " ".join(transcriptions)
|
70 |
-
subtitle_storage["original"] = full_transcription
|
71 |
-
subtitle_storage["video_path"] = video_path
|
72 |
-
|
73 |
-
return f"Subtitle added: {full_transcription[:100]}..." # Display first 100 characters
|
74 |
-
|
75 |
-
except Exception as e:
|
76 |
-
return f"Error in adding subtitle: {e}"
|
77 |
-
|
78 |
-
def translate_subtitle(language):
|
79 |
-
try:
|
80 |
-
# Translate the stored subtitle
|
81 |
-
original_subtitle = subtitle_storage.get("original")
|
82 |
-
if not original_subtitle:
|
83 |
-
return "No subtitle to translate!"
|
84 |
-
|
85 |
-
# Translate using the selected language
|
86 |
-
translated_subtitle = translator(
|
87 |
-
original_subtitle,
|
88 |
-
src_lang="en", # Source language (assuming the subtitle is in English)
|
89 |
-
tgt_lang=languages[language] # Get the language code from the dropdown selection
|
90 |
-
)[0]["translation_text"]
|
91 |
-
|
92 |
-
subtitle_storage["translated"] = translated_subtitle # Store the translated subtitle
|
93 |
-
|
94 |
-
return f"Subtitle translated to {language} successfully!"
|
95 |
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
def download_word():
|
100 |
-
try:
|
101 |
-
# Save translated subtitles to a Word document
|
102 |
-
translated_subtitle = subtitle_storage.get("translated")
|
103 |
-
if not translated_subtitle:
|
104 |
-
return "No translated subtitle to save!"
|
105 |
-
|
106 |
-
# Prepare the document
|
107 |
-
doc = docx.Document()
|
108 |
-
doc.add_heading('Translated Subtitles', 0)
|
109 |
-
|
110 |
-
# Create timestamps and subtitles
|
111 |
-
for i in range(0, len(translated_subtitle), 50):
|
112 |
-
start_time = (i // 50) * 5 # Each subtitle lasts for 5 seconds
|
113 |
-
subtitle_text = translated_subtitle[i:i + 50] # Get the next 50 characters
|
114 |
-
|
115 |
-
# Add a formatted string with timestamp and subtitle to the document
|
116 |
-
doc.add_paragraph(f"{start_time}s - {subtitle_text}")
|
117 |
-
|
118 |
-
file_path = "translated_subtitles.docx"
|
119 |
-
doc.save(file_path)
|
120 |
-
|
121 |
-
# Return the file for download
|
122 |
-
return file_path # Return the file path to allow Gradio to serve it as a downloadable file
|
123 |
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
def download_video():
|
128 |
-
try:
|
129 |
-
original_subtitle = subtitle_storage.get("original")
|
130 |
-
translated_subtitle = subtitle_storage.get("translated")
|
131 |
-
|
132 |
-
if not original_subtitle or not translated_subtitle:
|
133 |
-
return "No subtitles to overlay on video!"
|
134 |
-
|
135 |
-
video_path = subtitle_storage.get("video_path")
|
136 |
-
video = mp.VideoFileClip(video_path)
|
137 |
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
end_time = start_time + subtitle_length # Each subtitle lasts for 'subtitle_length' seconds
|
146 |
-
subtitle_text = translated_subtitle[i:i + 50]
|
147 |
-
subs.append(((start_time, end_time), subtitle_text))
|
148 |
-
|
149 |
-
subtitles = SubtitlesClip(subs, generator)
|
150 |
-
|
151 |
-
subtitled_video = mp.CompositeVideoClip([video, subtitles.set_position(('center', 'bottom'))])
|
152 |
-
|
153 |
-
output_video_path = "subtitled_video.mp4"
|
154 |
-
subtitled_video.write_videofile(output_video_path)
|
155 |
-
|
156 |
-
return f"Subtitled video is ready for download: {output_video_path}"
|
157 |
-
|
158 |
-
except Exception as e:
|
159 |
-
return f"Error in generating subtitled video: {e}"
|
160 |
-
|
161 |
-
# Gradio UI Interface
|
162 |
-
with gr.Blocks() as demo:
|
163 |
-
# Title
|
164 |
-
gr.Markdown("<h1 style='text-align: center;'>Video Subtitle Translator</h1>")
|
165 |
-
|
166 |
-
# Video Upload or URL Input
|
167 |
-
with gr.Row():
|
168 |
-
video_input = gr.Video(label="Upload Video")
|
169 |
-
video_url_input = gr.Textbox(label="Or Enter Video URL")
|
170 |
-
download_video_button = gr.Button("Download Video from URL")
|
171 |
-
download_status = gr.Textbox(label="Download Status")
|
172 |
-
|
173 |
-
download_video_button.click(download_video_from_link, inputs=video_url_input, outputs=download_status)
|
174 |
-
|
175 |
-
# Add Subtitle
|
176 |
-
with gr.Row():
|
177 |
-
add_subtitle_button = gr.Button("Add Subtitle")
|
178 |
-
subtitle_status = gr.Textbox(label="Subtitle Status")
|
179 |
-
|
180 |
-
add_subtitle_button.click(add_subtitle, inputs=video_input, outputs=subtitle_status)
|
181 |
-
|
182 |
-
# Translate Subtitle
|
183 |
-
with gr.Row():
|
184 |
-
language_dropdown = gr.Dropdown(choices=list(languages.keys()), label="Choose Target Language", value="Persian")
|
185 |
-
translate_button = gr.Button("Translate Subtitle")
|
186 |
-
translate_status = gr.Textbox(label="Translation Status")
|
187 |
-
|
188 |
-
translate_button.click(translate_subtitle, inputs=language_dropdown, outputs=translate_status) # Update inputs
|
189 |
-
|
190 |
-
# Download as Word
|
191 |
-
with gr.Row():
|
192 |
-
download_word_button = gr.Button("Download as Word") # Renamed the button to avoid conflict
|
193 |
-
download_word_status = gr.File(label="Download Translated Word File") # File output for Word download
|
194 |
-
|
195 |
-
download_word_button.click(download_word, inputs=None, outputs=download_word_status)
|
196 |
-
|
197 |
-
# Download Subtitled Video
|
198 |
-
with gr.Row():
|
199 |
-
download_video_button2 = gr.Button("Download Subtitled Video") # Renamed the button to avoid conflict
|
200 |
-
download_video_status = gr.Textbox(label="Download Video Status")
|
201 |
-
|
202 |
-
download_video_button2.click(download_video, inputs=None, outputs=download_video_status)
|
203 |
|
204 |
-
# Launch the
|
205 |
-
|
|
|
1 |
import gradio as gr
|
2 |
+
from moviepy.editor import VideoFileClip
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
+
# Function to process and return the video
|
5 |
+
def display_video(video_file):
|
6 |
+
# Load the video using MoviePy (optional for processing)
|
7 |
+
clip = VideoFileClip(video_file)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
9 |
+
# Optionally, you can print video details or process it
|
10 |
+
print(f"Duration: {clip.duration} seconds")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
+
# Return the video file to be displayed in Gradio
|
13 |
+
return video_file
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
|
15 |
+
# Create the Gradio interface
|
16 |
+
interface = gr.Interface(
|
17 |
+
fn=display_video,
|
18 |
+
inputs=gr.Video(label="Upload your video"),
|
19 |
+
outputs=gr.Video(label="Uploaded Video"),
|
20 |
+
title="Video Uploader",
|
21 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
+
# Launch the interface
|
24 |
+
interface.launch()
|