Spaces:
Sleeping
Sleeping
| import os | |
| import logging | |
| import gradio as gr | |
| from gradio_client import Client, handle_file | |
| import gradio.themes as gr_themes | |
| # Set up logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # It's recommended to set the HUGGINGFACE_TOKEN as an environment variable | |
| token = os.getenv("HUGGINGFACE_TOKEN") | |
| def create_DubIndic_interface(): | |
| """ | |
| Creates and configures the Gradio interface for the DubIndic application. | |
| """ | |
| try: | |
| # Connect to the Gradio client on Hugging Face Spaces | |
| client = Client("Tamiloneto8/Test1", hf_token=token, verbose=True) | |
| logger.info("Successfully connected to Gradio client.") | |
| except Exception as e: | |
| logger.error("Error connecting to the private space: %s", e, exc_info=True) | |
| # Create a fallback interface to show the connection error | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# π¬ DubIndic - Connection Error") | |
| gr.Textbox( | |
| value=f"Failed to connect to the Hugging Face Space. Please ensure the Space is running and the token is correct. Error: {e}", | |
| label="Error", | |
| interactive=False | |
| ) | |
| return demo | |
| # Define wrapper functions to call the API endpoints | |
| def start_processing(audio_file, target_language): | |
| if not audio_file or not target_language: | |
| return ( | |
| "Please provide both an audio file and a target language.", | |
| None, "", "", None, "", | |
| gr.update(visible=False), gr.update(visible=False), | |
| None, gr.update(visible=False), None, gr.update(visible=False) | |
| ) | |
| try: | |
| logger.info("Calling /process_audio_pipeline_step1 with file: %s", audio_file) | |
| result = client.predict( | |
| audio_file=handle_file(audio_file), | |
| target_lang=target_language, | |
| api_name="/process_audio_pipeline_step1" | |
| ) | |
| logger.info("Received result from step 1: %s", result) | |
| # API returns a 7-element tuple, we map it to our UI outputs | |
| # [status, internal_val, orig_audio, trans, transl, dubbed_audio, progress] | |
| return ( | |
| result[0], result[2], result[3], result[4], result[5], result[6], | |
| gr.update(visible=True), gr.update(visible=True), # Make edit and merge sections visible | |
| result[2] if result[2] else None, gr.update(visible=True if result[2] else False), | |
| result[5] if result[5] else None, gr.update(visible=True if result[5] else False) | |
| ) | |
| except Exception as e: | |
| logger.error("Error in start_processing: %s", e, exc_info=True) | |
| return ( | |
| f"Error starting the process: {e}", | |
| None, "", "", None, "", | |
| gr.update(visible=False), gr.update(visible=False), | |
| None, gr.update(visible=False), None, gr.update(visible=False) | |
| ) | |
| def navigate_chunk(transcription, translation, direction): | |
| # The API uses different endpoints for next/previous navigation | |
| # We assume /lambda is for previous and /lambda_1 is for next | |
| api_to_call = "/lambda" if direction == "prev" else "/lambda_1" | |
| try: | |
| logger.info("Calling %s to navigate.", api_to_call) | |
| result = client.predict( | |
| t=transcription, | |
| tr=translation, | |
| api_name=api_to_call | |
| ) | |
| logger.info("Received result from navigation: %s", result) | |
| # API returns a 6-element tuple | |
| # [internal_val, orig_audio, trans, transl, dubbed_audio, progress] | |
| return (result[1], result[2], result[3], result[4], result[5], | |
| result[1] if result[1] else None, | |
| result[4] if result[4] else None) | |
| except Exception as e: | |
| logger.error("Error navigating chunks: %s", e, exc_info=True) | |
| return None, f"Error navigating chunks: {e}", "", None, "", None, None | |
| def generate_dubbed_chunk(transcription, translation): | |
| if not transcription and not translation: | |
| return None, None | |
| try: | |
| logger.info("Calling /generate_dubbed_chunk.") | |
| dubbed_path = client.predict( | |
| transcription=transcription, | |
| translation=translation, | |
| api_name="/generate_dubbed_chunk" | |
| ) | |
| logger.info("Received dubbed chunk: %s", dubbed_path) | |
| return dubbed_path, gr.update(value=dubbed_path, visible=True) if dubbed_path else gr.update(visible=False) | |
| except Exception as e: | |
| logger.error("Error generating dubbed chunk: %s", e, exc_info=True) | |
| return None, None | |
| def finalize_current_chunk(): | |
| try: | |
| logger.info("Calling /finalize_current_chunk.") | |
| progress = client.predict(api_name="/finalize_current_chunk") | |
| logger.info("Received finalization progress: %s", progress) | |
| return progress | |
| except Exception as e: | |
| logger.error("Error finalizing chunk: %s", e, exc_info=True) | |
| return f"Error finalizing chunk: {e}" | |
| def merge_all_chunks(): | |
| try: | |
| logger.info("Calling /merge_audio_files.") | |
| final_status, final_audio = client.predict(api_name="/merge_audio_files") | |
| logger.info("Received final merged audio.") | |
| return final_status, final_audio | |
| except Exception as e: | |
| logger.error("Error merging audio files: %s", e, exc_info=True) | |
| return f"Error merging audio: {e}", None | |
| # Create custom theme with orange-red gradient colors | |
| custom_theme = gr_themes.Soft( | |
| primary_hue="orange", | |
| secondary_hue="red", | |
| neutral_hue="gray" | |
| ).set( | |
| button_primary_background_fill="linear-gradient(45deg, #f97316, #ef4444)", | |
| button_primary_background_fill_hover="linear-gradient(45deg, #ea580c, #dc2626)", | |
| button_primary_text_color="white", | |
| block_background_fill="rgba(255, 255, 255, 0.05)", | |
| block_border_color="rgba(249, 115, 22, 0.2)", | |
| input_background_fill="rgba(255, 255, 255, 0.9)", | |
| input_border_color="rgba(249, 115, 22, 0.3)", | |
| input_border_color_focus="rgba(239, 68, 68, 0.6)" | |
| ) | |
| # Define the Gradio Interface using Blocks for a custom layout | |
| with gr.Blocks(theme=custom_theme, title="DubIndic - AI Audio Dubbing", css=""" | |
| .gradio-container { | |
| background: linear-gradient(135deg, rgba(249, 115, 22, 0.1), rgba(239, 68, 68, 0.1)); | |
| } | |
| .gr-button[variant="primary"] { | |
| background: linear-gradient(45deg, #f97316, #ef4444) !important; | |
| border: none !important; | |
| color: white !important; | |
| font-weight: bold !important; | |
| } | |
| .gr-button[variant="primary"]:hover { | |
| background: linear-gradient(45deg, #ea580c, #dc2626) !important; | |
| transform: translateY(-1px); | |
| box-shadow: 0 4px 8px rgba(239, 68, 68, 0.3); | |
| } | |
| .gr-button[variant="secondary"] { | |
| background: linear-gradient(45deg, rgba(249, 115, 22, 0.1), rgba(239, 68, 68, 0.1)) !important; | |
| border: 2px solid #f97316 !important; | |
| color: #f97316 !important; | |
| font-weight: bold !important; | |
| } | |
| .gr-button[variant="secondary"]:hover { | |
| background: linear-gradient(45deg, #f97316, #ef4444) !important; | |
| color: white !important; | |
| } | |
| h1 { | |
| background: linear-gradient(45deg, #f97316, #ef4444); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| font-weight: bold; | |
| } | |
| .gr-textbox { | |
| border: 2px solid rgba(249, 115, 22, 0.3) !important; | |
| } | |
| .gr-textbox:focus { | |
| border-color: #ef4444 !important; | |
| box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1) !important; | |
| } | |
| """) as demo: | |
| gr.Markdown("# π¬ DubIndic - AI Audio Dubbing Pipeline") | |
| gr.Markdown("Transform your audio into another Indian language with full editing control.") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π€ Step 1: Upload & Configure") | |
| audio_input = gr.Audio(sources=["upload"], type="filepath", label="π΅ Upload Audio File") | |
| lang_dropdown = gr.Dropdown( | |
| choices=["Assamese", "Bengali", "Gujarati", "Hindi", "Kannada", "Malayalam", "Marathi", "Odia", "Punjabi", "Tamil", "Telugu"], | |
| label="π Target Language" | |
| ) | |
| process_btn = gr.Button("π― Start Processing", variant="primary") | |
| step1_output = gr.Textbox(label="π Processing Status", interactive=False) | |
| with gr.Column(visible=False) as edit_section: | |
| gr.Markdown("### βοΈ Step 2: Edit, Generate & Finalize Chunks") | |
| with gr.Row(): | |
| prev_btn = gr.Button("βοΈ Previous") | |
| next_btn = gr.Button("Next βΆοΈ") | |
| with gr.Row(): | |
| with gr.Column(): | |
| original_audio = gr.Audio(label="π§ Original Chunk Audio", type="filepath", interactive=False) | |
| download_original_audio = gr.File(label="πΎ Download Original Chunk", visible=False) | |
| with gr.Column(): | |
| dubbed_audio = gr.Audio(label="π Dubbed Chunk Audio", type="filepath", interactive=False) | |
| download_dubbed_audio = gr.File(label="πΎ Download Dubbed Chunk", visible=False) | |
| transcription_text = gr.Textbox(label="Transcription (edit if needed)", lines=2, interactive=True) | |
| translation_text = gr.Textbox(label="Translation (edit if needed)", lines=2, interactive=True) | |
| with gr.Row(): | |
| generate_btn = gr.Button("π Generate Dubbed Chunk") | |
| finalize_btn = gr.Button("βοΈ Finalize Chunk", variant="secondary") | |
| progress_text = gr.Textbox(label="Progress", interactive=False) | |
| with gr.Row(visible=False) as merge_section: | |
| gr.Markdown("### π Step 3: Merge Final Audio") | |
| merge_btn = gr.Button("π Merge All Finalized Chunks", variant="primary") | |
| final_output = gr.Textbox(label="π Final Results", interactive=False) | |
| output_audio = gr.Audio(label="π Final Dubbed Audio", type="filepath", interactive=False) | |
| # Connect functions to UI components | |
| process_btn.click( | |
| fn=start_processing, | |
| inputs=[audio_input, lang_dropdown], | |
| outputs=[step1_output, original_audio, transcription_text, translation_text, dubbed_audio, progress_text, | |
| edit_section, merge_section, download_original_audio, download_original_audio, | |
| download_dubbed_audio, download_dubbed_audio] | |
| ) | |
| prev_btn.click( | |
| fn=lambda t, tr: navigate_chunk(t, tr, "prev"), | |
| inputs=[transcription_text, translation_text], | |
| outputs=[original_audio, transcription_text, translation_text, dubbed_audio, progress_text, | |
| download_original_audio, download_dubbed_audio] | |
| ) | |
| next_btn.click( | |
| fn=lambda t, tr: navigate_chunk(t, tr, "next"), | |
| inputs=[transcription_text, translation_text], | |
| outputs=[original_audio, transcription_text, translation_text, dubbed_audio, progress_text, | |
| download_original_audio, download_dubbed_audio] | |
| ) | |
| generate_btn.click( | |
| fn=generate_dubbed_chunk, | |
| inputs=[transcription_text, translation_text], | |
| outputs=[dubbed_audio, download_dubbed_audio] | |
| ) | |
| finalize_btn.click( | |
| fn=finalize_current_chunk, | |
| inputs=[], | |
| outputs=[progress_text] | |
| ) | |
| merge_btn.click( | |
| fn=merge_all_chunks, | |
| inputs=[], | |
| outputs=[final_output, output_audio] | |
| ) | |
| return demo | |
| if __name__ == "__main__": | |
| DubIndic_interface = create_DubIndic_interface() | |
| if DubIndic_interface: | |
| DubIndic_interface.launch(show_error=True, share=False, server_name="0.0.0.0", server_port=7860) | |
| else: | |
| logger.error("Failed to create the Gradio interface.") |