| | import gradio as gr |
| | from subtitle import subtitle_maker,LANGUAGE_CODE |
| | source_lang_list = ['Automatic', "English", "Hindi", "Bengali"] |
| | available_language = LANGUAGE_CODE.keys() |
| | source_lang_list.extend(available_language) |
| |
|
| | target_lang_list = ["English", "Hindi", "Bengali"] |
| | target_lang_list.extend(available_language) |
| |
|
| |
|
| | def update_target_lang(selected_src): |
| | """Update target language automatically when source changes.""" |
| | if selected_src == "Automatic": |
| | return "English" |
| | else: |
| | return selected_src |
| |
|
| |
|
| | def ui1(): |
| | with gr.Blocks() as demo: |
| | gr.HTML(""" |
| | <div style="text-align: center; margin: 20px auto; max-width: 800px;"> |
| | <h1 style="font-size: 2.5em; margin-bottom: 10px;">π¬ Auto Subtitle Generator</h1> |
| | <p style="font-size: 1.2em; color: #555; margin-bottom: 15px;">If you have a large video, upload the audio instead, it's much faster to upload.</p> |
| | <a href="https://github.com/NeuralFalconYT/Auto-Subtitle-Generator-Free" target="_blank" style="display: inline-block; padding: 10px 20px; background-color: #4285F4; color: white; border-radius: 6px; text-decoration: none; font-size: 1em;">π Run on Google Colab</a> |
| | </div> |
| | """) |
| |
|
| | with gr.Row(): |
| | with gr.Column(): |
| | upload_media = gr.File(label="Upload Audio or Video File") |
| | input_lang = gr.Dropdown(label="Source Language", choices=source_lang_list, value="English") |
| | generate_btn = gr.Button("π Generate Subtitle", variant="primary") |
| | with gr.Accordion("βοΈ Translation using Google Translator", open=False): |
| | output_lang = gr.Dropdown(label="Translate Into", choices=target_lang_list, value="English") |
| |
|
| | with gr.Column(): |
| | default_srt = gr.File(label="π― Original Subtitles (Default Generated by whisper)") |
| | customized_srt = gr.File(label="π Readable Subtitles (Multi-line)") |
| | word_level_srt = gr.File(label="π Word-by-Word Subtitles") |
| |
|
| | with gr.Accordion("π Other Subtitle Formats", open=False): |
| | translated_srt = gr.File(label="π Translated Subtitles") |
| | shorts_srt = gr.File(label="π± Shorts/Reels Subtitles") |
| | transcript_txt = gr.File(label="π Full Transcript (Text File)") |
| | subtitle_json= gr.File(label="π Full Transcript (JSON File) To make .ass file") |
| | word_json= gr.File(label="π Shorts Transcript (JSON File) To make .ass file") |
| | transcript_box = gr.Textbox(label="ποΈ Transcript Preview", lines=4,show_copy_button=True) |
| |
|
| | generate_btn.click( |
| | fn=subtitle_maker, |
| | inputs=[upload_media, input_lang, output_lang], |
| | outputs=[default_srt, translated_srt, customized_srt, word_level_srt, shorts_srt, transcript_txt, subtitle_json,word_json,transcript_box] |
| | ) |
| |
|
| | input_lang.change( |
| | fn=update_target_lang, |
| | inputs=input_lang, |
| | outputs=output_lang |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | return demo |
| |
|
| |
|
| |
|
| | def prompt_translation(language): |
| | """ |
| | Generates a dubbing-friendly translation prompt for an .srt subtitle file. |
| | Tailored for natural speech and timing accuracy. |
| | """ |
| | prompt = f""" |
| | -------------- You are a professional subtitle translator for **video dubbing**. |
| | Translate the following `.srt` subtitle file into **{language}** while preserving timing, meaning, and emotional tone. |
| | |
| | Output in JSON format exactly like this: |
| | |
| | ```json |
| | {{ |
| | "subtitle sequence number": {{ |
| | "timestamp": "original timestamp", |
| | "actual subtitle text": "original English subtitle line", |
| | "dubbing": "natural, dubbing-friendly {language} translation" |
| | }} |
| | }} |
| | ``` |
| | |
| | **Guidelines for Translation:** |
| | |
| | 1. **Understand the full context** before translating β read the entire subtitle file first. |
| | 2. Translate into **natural, conversational {language}**, not a direct word-for-word translation. |
| | 6. Keep translations **roughly similar in length** to the original so lip movements sync naturally. |
| | """ |
| | return prompt |
| |
|
| |
|
| | def prompt_fix_grammar(language="English"): |
| | """ |
| | Generates a dubbing-friendly grammar correction prompt for an .srt subtitle file. |
| | Tailored for natural speech and timing accuracy. |
| | """ |
| | prompt = f""" |
| | -------------- You are a professional subtitle editor for **video dubbing**. |
| | Fix the grammar, spelling, and awkward phrasing in the following `.srt` subtitle file while preserving timing, meaning, and emotional tone. Β |
| | Do NOT translate β keep everything in {language}. |
| | |
| | Output in JSON format exactly like this: |
| | |
| | ```json |
| | {{ |
| | "subtitle sequence number": {{ |
| | "timestamp": "original timestamp", |
| | "actual subtitle text": "original {language} subtitle line", |
| | "dubbing": "natural, dubbing-friendly corrected {language} line" |
| | }} |
| | }} |
| | ``` |
| | |
| | **Guidelines for Grammar Fixing:** |
| | |
| | 1. **Understand the full context** before editing β read the entire subtitle file first. |
| | 2. Correct grammar, spelling, and phrasing errors while keeping the same meaning. |
| | 4. Keep corrections **roughly similar in length** to the original so lip movements sync naturally. |
| | """ |
| | return prompt |
| |
|
| |
|
| | def prompt_srt_to_romanized(language="Hindi"): |
| | """ |
| | Generates a prompt for converting a .srt subtitle file |
| | from any language to a Romanized (Latin letters) version, |
| | preserving timing, meaning, punctuation, and formatting. |
| | """ |
| | prompt = f""" |
| | -------------- You are a professional subtitle editor tasked with converting subtitles to Romanized text. |
| | Your task is to convert a `.srt` subtitle file from {language} to **Romanized {language}**, |
| | keeping everything exactly the same except using Latin letters for all words. |
| | |
| | **Instructions:** |
| | 1. Preserve the original timestamp of each subtitle. |
| | 2. Keep the original meaning, punctuation, and formatting intact. |
| | 3. Convert **only the original subtitle text** to Roman letters, word by word. |
| | 4. Do not add, remove, or change any words. |
| | 5. Output in strict JSON format exactly like this: |
| | |
| | ```json |
| | {{ |
| | "subtitle sequence number": {{ |
| | "timestamp": "original timestamp", |
| | "original subtitle text": "original {language} subtitle line", |
| | "dubbing": "Romanized, {language} line of original subtitle text" |
| | }} |
| | }} |
| | ```` |
| | |
| | Focus entirely on **accurate Romanization**; do not modify anything else. |
| | """ |
| | return prompt |
| |
|
| |
|
| |
|
| | import pysrt |
| |
|
| | def prompt_maker(srt_path, target_language, task="Translation"): |
| | txt_path = srt_path.replace(".srt", ".txt") |
| | subs = pysrt.open(srt_path, encoding='utf-8') |
| |
|
| | with open(txt_path, 'w', encoding='utf-8') as f: |
| | for sub in subs: |
| | f.write(f"{sub.index}\n") |
| | f.write(f"{sub.start} --> {sub.end}\n") |
| | f.write(f"{sub.text}\n\n") |
| | if task == "Translation": |
| | f.write(prompt_translation(target_language)) |
| | if task=="Romanization": |
| | f.write(prompt_srt_to_romanized(target_language)) |
| | else: |
| | f.write(prompt_fix_grammar(target_language)) |
| |
|
| | with open(txt_path, 'r', encoding='utf-8') as f: |
| | content = f.read() |
| |
|
| | |
| | return content, srt_path |
| |
|
| |
|
| |
|
| |
|
| | import pysrt |
| | import json |
| | import os |
| | def json_to_srt(json_script, srt_path): |
| | """ |
| | Convert dubbing-friendly JSON back into .srt |
| | Uses original srt_path to name output <name>_dubbing.srt |
| | """ |
| | os.makedirs("./dubbing_srt", exist_ok=True) |
| |
|
| | base_name = os.path.basename(srt_path) |
| | name_no_ext, _ = os.path.splitext(base_name) |
| | output_srt_path = os.path.join("./dubbing_srt", f"{name_no_ext}_dubbing.srt") |
| |
|
| | |
| | if isinstance(json_script, str): |
| | json_object = json.loads(json_script) |
| | else: |
| | json_object = json_script |
| |
|
| | |
| | with open(output_srt_path, "w", encoding="utf-8") as f: |
| | for i, (key, value) in enumerate(json_object.items(), start=1): |
| | f.write(f"{i}\n") |
| | f.write(f"{value['timestamp']}\n") |
| | f.write(f"{value['dubbing']}\n\n") |
| |
|
| | return output_srt_path |
| |
|
| |
|
| |
|
| |
|
| | def ui2(): |
| | with gr.Blocks() as demo: |
| | gr.Markdown("<center><h1 style='font-size: 32px;'>π¬ Subtitle Translation Using LLM</h1></center>") |
| |
|
| | |
| | srt_state = gr.State("") |
| |
|
| | with gr.Row(): |
| | with gr.Column(): |
| | gr.Markdown("### Step 1: Generate Prompt") |
| | srt_file = gr.File(label="Upload .srt file generated by Whisper", file_types=[".srt"]) |
| | task = gr.Dropdown( |
| | ["Translation","Romanization","Fix Grammar [English to English for dubbing]"], |
| | label="Select Task", |
| | value="Translation", |
| | ) |
| | language = gr.Dropdown(target_lang_list, label="Select the language you want to translate into", value="English") |
| | generate_btn = gr.Button("Generate Prompt") |
| | output_prompt = gr.Textbox( |
| | label="Copy & Paste this prompt in https://aistudio.google.com/", |
| | lines=20, |
| | show_copy_button=True |
| | |
| | ) |
| |
|
| | with gr.Column(): |
| | gr.Markdown("### Step 2: Paste JSON & Convert Back to SRT") |
| | json_input = gr.Textbox( |
| | label="Paste JSON script from https://aistudio.google.com/ ", |
| | lines=20, |
| | placeholder="Paste the JSON output here..." |
| | ) |
| | convert_btn = gr.Button("Convert JSON β SRT") |
| | srt_file_out = gr.File(label="Download new .srt") |
| |
|
| | |
| | generate_btn.click( |
| | fn=prompt_maker, |
| | inputs=[srt_file, language, task], |
| | outputs=[output_prompt, srt_state], |
| | ) |
| |
|
| | convert_btn.click( |
| | fn=json_to_srt, |
| | inputs=[json_input, srt_state], |
| | outputs=srt_file_out, |
| | ) |
| |
|
| | return demo |
| |
|
| |
|
| |
|
| |
|
| | import click |
| | @click.command() |
| | @click.option("--debug", is_flag=True, default=False, help="Enable debug mode.") |
| | @click.option("--share", is_flag=True, default=False, help="Enable sharing of the interface.") |
| | def main(share,debug): |
| | |
| | demo1 = ui1() |
| | demo2 = ui2() |
| | custom_css = """.gradio-container { font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif; }""" |
| | demo = gr.TabbedInterface([demo1, demo2], ["Generate SRT File", "SRT Translation"], title="",theme=gr.themes.Soft(),css=custom_css) |
| | demo.queue().launch(share=share,debug=debug) |
| | if __name__ == "__main__": |
| | main() |