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.Markdown(f"**Error Details:** {str(e)}") gr.Markdown("Please check your connection and try again.") 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 select a target language.", None, "", "", None, "", gr.update(visible=False), 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 ( f"✅ {result[0]}", result[2], result[3], result[4], result[5], result[6], gr.update(visible=True), gr.update(visible=True) ) except Exception as e: logger.error("Error in start_processing: %s", e, exc_info=True) return ( f"❌ Error: {str(e)}", None, "", "", None, "", gr.update(visible=False), gr.update(visible=False) ) def navigate_chunk(transcription, translation, direction): 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) return result[1], result[2], result[3], result[4], result[5] except Exception as e: logger.error("Error navigating chunks: %s", e, exc_info=True) return None, f"❌ Navigation error: {str(e)}", "", None, "" def generate_dubbed_chunk(transcription, translation): if not transcription and not translation: return 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 except Exception as e: logger.error("Error generating dubbed chunk: %s", e, exc_info=True) return 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 f"✅ {progress}" except Exception as e: logger.error("Error finalizing chunk: %s", e, exc_info=True) return f"❌ Error finalizing: {str(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 f"🎉 {final_status}", final_audio except Exception as e: logger.error("Error merging audio files: %s", e, exc_info=True) return f"❌ Merge error: {str(e)}", None # Create custom theme with enhanced styling custom_theme = gr_themes.Soft( primary_hue="orange", secondary_hue="red", neutral_hue="slate" ) # Enhanced CSS with creative design elements enhanced_css = """ /* Main container styling */ .gradio-container { background: linear-gradient(135deg, #fff8e6 0%, #fef3e2 50%, #fff8e6 100%); font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; min-height: 100vh; } /* Header styling with animated gradient */ .main-header { background: linear-gradient(45deg, #f97316, #ef4444, #f97316); background-size: 300% 300%; animation: gradientShift 6s ease infinite; -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; text-align: center; font-weight: 800; font-size: 2.5rem; margin-bottom: 1rem; } @keyframes gradientShift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } /* Card-like sections */ .step-card { background: rgba(255, 255, 255, 0.9); border: 2px solid rgba(249, 115, 22, 0.2); border-radius: 16px; padding: 24px; margin: 16px 0; box-shadow: 0 8px 32px rgba(249, 115, 22, 0.1); backdrop-filter: blur(8px); transition: all 0.3s ease; } .step-card:hover { transform: translateY(-2px); box-shadow: 0 12px 48px rgba(249, 115, 22, 0.15); border-color: rgba(249, 115, 22, 0.4); } /* Enhanced primary buttons */ .gr-button[variant="primary"] { background: linear-gradient(45deg, #f97316, #ef4444) !important; border: none !important; color: white !important; font-weight: 600 !important; padding: 12px 24px !important; border-radius: 12px !important; font-size: 1rem !important; transition: all 0.3s ease !important; box-shadow: 0 4px 16px rgba(249, 115, 22, 0.3) !important; } .gr-button[variant="primary"]:hover { background: linear-gradient(45deg, #ea580c, #dc2626) !important; transform: translateY(-2px) !important; box-shadow: 0 8px 24px rgba(239, 68, 68, 0.4) !important; } /* Enhanced secondary buttons */ .gr-button[variant="secondary"] { background: rgba(255, 248, 230, 0.9) !important; border: 2px solid #f97316 !important; color: #f97316 !important; font-weight: 600 !important; padding: 10px 20px !important; border-radius: 10px !important; transition: all 0.3s ease !important; } .gr-button[variant="secondary"]:hover { background: linear-gradient(45deg, #f97316, #ef4444) !important; color: white !important; transform: translateY(-1px) !important; box-shadow: 0 4px 12px rgba(249, 115, 22, 0.3) !important; } /* Navigation buttons */ .nav-button { background: linear-gradient(45deg, #f97316, #ef4444) !important; border: none !important; color: white !important; font-weight: 600 !important; padding: 8px 16px !important; border-radius: 8px !important; font-size: 0.9rem !important; min-width: 120px !important; } /* Input styling */ .gr-textbox, .gr-dropdown { border: 2px solid rgba(249, 115, 22, 0.3) !important; border-radius: 12px !important; background: rgba(255, 255, 255, 0.95) !important; transition: all 0.3s ease !important; font-size: 1rem !important; } .gr-textbox:focus, .gr-dropdown:focus { border-color: #ef4444 !important; box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.1) !important; outline: none !important; } /* Audio player styling */ .gr-audio { border: 2px solid rgba(249, 115, 22, 0.3) !important; border-radius: 12px !important; background: rgba(255, 255, 255, 0.95) !important; padding: 12px !important; } /* Progress indicators */ .progress-text { background: linear-gradient(45deg, #f97316, #ef4444); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-weight: 600; } /* Step numbers */ .step-number { background: linear-gradient(45deg, #f97316, #ef4444); color: white; border-radius: 50%; width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; font-weight: bold; margin-right: 8px; } /* Section headers */ .section-header { color: #f97316; font-weight: 700; font-size: 1.25rem; margin-bottom: 16px; display: flex; align-items: center; } /* Responsive design */ @media (max-width: 768px) { .main-header { font-size: 2rem; } .step-card { padding: 16px; } } /* Loading animation */ .loading { animation: pulse 2s infinite; } @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.7; } 100% { opacity: 1; } } """ # Define the enhanced Gradio interface with gr.Blocks(theme=custom_theme, title="DubIndic - AI Audio Dubbing", css=enhanced_css) as demo: # Main header gr.HTML('