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("