DAI_Project / app.py
younes21000's picture
Update app.py
476a03d verified
raw
history blame
8.04 kB
import gradio as gr
import moviepy.editor as mp
import librosa
from transformers import pipeline
from concurrent.futures import ThreadPoolExecutor
import tempfile
import docx # To create Word documents
from moviepy.video.tools.subtitles import SubtitlesClip
from moviepy.editor import TextClip
# Load Whisper model for speech-to-text (using smaller 'tiny' model for faster performance)
asr = pipeline("automatic-speech-recognition", model="openai/whisper-tiny")
# MarianMT or M2M100 for translation (multi-language)
translator = pipeline("translation", model="facebook/m2m100_418M")
# Store generated subtitles and translations
subtitle_storage = {}
# Supported languages with their codes
languages = {
"Persian": "fa",
"French": "fr",
"Spanish": "es",
"German": "de",
"Chinese": "zh",
"Arabic": "ar",
"Hindi": "hi",
"Russian": "ru"
}
def transcribe_audio(chunk):
"""Transcribe a single audio chunk."""
return asr(chunk)["text"]
def add_subtitle(video):
try:
# The video is passed as a file path string, so we use it directly
video_path = video if isinstance(video, str) else None
if not video_path:
return "No video provided!"
video_clip = mp.VideoFileClip(video_path)
audio = video_clip.audio
# Use a temporary file for audio extraction
with tempfile.NamedTemporaryFile(delete=True, suffix='.wav') as tmp_audio_file:
audio.write_audiofile(tmp_audio_file.name, codec='pcm_s16le')
waveform, sr = librosa.load(tmp_audio_file.name, sr=16000)
# Transcribe in chunks (parallel)
chunk_duration = 15 # seconds
chunk_size = sr * chunk_duration
chunks = [
waveform[i:i + chunk_size]
for i in range(0, len(waveform), chunk_size)
if len(waveform[i:i + chunk_size]) > 0
]
with ThreadPoolExecutor() as executor:
transcriptions = list(executor.map(transcribe_audio, chunks))
full_transcription = " ".join(transcriptions)
subtitle_storage["original"] = full_transcription # Store the original subtitle (English or other)
subtitle_storage["video_path"] = video_path # Store the video path
return f"Subtitle added: {full_transcription[:100]}..." # Display first 100 characters
except Exception as e:
return f"Error in adding subtitle: {e}"
def translate_subtitle(video, language):
try:
# Translate the stored subtitle
original_subtitle = subtitle_storage.get("original")
if not original_subtitle:
return "No subtitle to translate!"
# Translate using the selected language
translated_subtitle = translator(
original_subtitle,
src_lang="en", # Source language (assuming the subtitle is in English)
tgt_lang=languages[language] # Get the language code from the dropdown selection
)[0]["translation_text"]
subtitle_storage["translated"] = translated_subtitle # Store the translated subtitle
return f"Subtitle translated to {language} successfully!"
except Exception as e:
return f"Error in translating subtitle: {e}"
def download_word():
try:
# Save translated subtitles to a Word document
translated_subtitle = subtitle_storage.get("translated")
if not translated_subtitle:
return "No translated subtitle to save!"
# Prepare the document
doc = docx.Document()
doc.add_heading('Translated Subtitles', 0)
# Create timestamps and subtitles
for i in range(0, len(translated_subtitle), 40): # Adjusted chunk size
start_time = (i // 40) * 2.5 # Each subtitle lasts for 2.5 seconds
subtitle_text = translated_subtitle[i:i + 40].strip() # Get the next 40 characters
# Add a formatted string with timestamp and subtitle to the document
if subtitle_text:
doc.add_paragraph(f"{start_time:.3f}s - {subtitle_text}")
file_path = "translated_subtitles.docx"
doc.save(file_path)
# Return the file for download
return file_path # Gradio will handle this as a downloadable file
except Exception as e:
return f"Error in saving subtitles as Word: {e}"
def download_original_subtitled_video():
"""Download video with original subtitles (no translation)."""
try:
# Add original subtitles to the video
original_subtitle = subtitle_storage.get("original")
if not original_subtitle:
return "No original subtitles available!"
video_path = subtitle_storage.get("video_path")
video = mp.VideoFileClip(video_path)
# Function to generate subtitle text
generator = lambda txt: TextClip(txt, font='Arial', fontsize=24, color='white')
# Generate original subtitles with start_time, end_time, and text
subs = []
subtitle_length = 2.5 # seconds each subtitle will be displayed
for i in range(0, len(original_subtitle), 40): # Adjusted chunk size
start_time = (i // 40) * subtitle_length
end_time = start_time + subtitle_length
subtitle_text = original_subtitle[i:i + 40].strip() # Get the next 40 characters
if subtitle_text:
subs.append((start_time, end_time, subtitle_text)) # Create a tuple for start time, end time, and text
# Debugging: Print the generated subtitles
print("Generated subtitles:", subs)
# Create subtitle clips
subtitles = SubtitlesClip(subs, generator)
# Overlay subtitles on video
subtitled_video = mp.CompositeVideoClip([video, subtitles.set_position(('center', 'bottom'))])
output_video_path = "original_subtitled_video.mp4"
subtitled_video.write_videofile(output_video_path, codec='libx264') # Use libx264 for better compatibility
# Return the file path for download
return output_video_path
except Exception as e:
return f"Error in generating original subtitled video: {e}"
# Gradio UI Interface
with gr.Blocks() as demo:
# Title
gr.Markdown("<h1 style='text-align: center;'>Video Subtitle Translator</h1>")
# Video Upload
with gr.Row():
video_input = gr.Video(label="Upload Video")
upload_button = gr.Button("Upload Video")
upload_status = gr.Textbox(label="Upload Status")
upload_button.click(add_subtitle, inputs=video_input, outputs=upload_status)
# Add Subtitle
with gr.Row():
add_subtitle_button = gr.Button("Add Subtitle")
subtitle_status = gr.Textbox(label="Subtitle Status")
add_subtitle_button.click(add_subtitle, inputs=video_input, outputs=subtitle_status)
# Translate Subtitle
with gr.Row():
language_dropdown = gr.Dropdown(choices=list(languages.keys()), label="Choose Target Language", value="Persian")
translate_button = gr.Button("Translate Subtitle")
translate_status = gr.Textbox(label="Translation Status")
translate_button.click(translate_subtitle, inputs=[video_input, language_dropdown], outputs=translate_status)
# Download as Word
with gr.Row():
download_button = gr.Button("Download as Word")
download_status = gr.File(label="Download Translated Word File") # File output for Word download
download_button.click(download_word, inputs=None, outputs=download_status)
# Download Original Subtitled Video (no translation)
with gr.Row():
download_original_video_button = gr.Button("Download Original Subtitled Video")
download_original_video_status = gr.File(label="Download Original Subtitled Video") # File output for original subtitled video
download_original_video_button.click(download_original_subtitled_video, inputs=None, outputs=download_original_video_status)
# Launch the Gradio app
demo.launch()