Spaces:
Running
on
Zero
Running
on
Zero
| """ | |
| Main Gradio application for Quran recitation practice. | |
| """ | |
| import argparse | |
| import os | |
| import sys | |
| from pathlib import Path | |
| # CRITICAL: Import spaces FIRST to avoid CUDA initialization before ZeroGPU setup | |
| try: | |
| import spaces | |
| except ImportError: | |
| pass | |
| import gradio as gr | |
| # Add parent directory to path for imports | |
| app_path = str(Path(__file__).parent) | |
| sys.path.insert(0, app_path) | |
| from config import IS_HF_SPACE, GRADIO_CONCURRENCY_LIMIT | |
| from recitation_engine.model_loader import get_model, get_models | |
| from recitation_engine.segment_processor import initialize_segment_models | |
| from recitation_engine.zero_gpu import ZERO_GPU_AVAILABLE | |
| from utils.phonemizer_utils import get_chapter_list | |
| from shared_state import ( | |
| is_initialized, | |
| set_initialized, | |
| set_processor as state_set_processor, | |
| set_model as state_set_model, | |
| set_chapters as state_set_chapters, | |
| set_model_bundles as state_set_model_bundles, | |
| ) | |
| def initialize_app(): | |
| """Initialize the application by loading model and data. | |
| Safe to call multiple times under Gradio reload. | |
| """ | |
| if is_initialized(): | |
| print("App already initialized. Skipping initialization.") | |
| return | |
| set_initialized(True) | |
| print("=" * 60) | |
| print("Initializing Recitation Application...") | |
| print("=" * 60) | |
| # Load primary model | |
| processor, model, error = get_model() | |
| state_set_processor(processor) | |
| state_set_model(model) | |
| bundles, bundle_errors = get_models() | |
| if error: | |
| print(f"\nWarning: {error}") | |
| print("The app will run, but transcription will not work.\n") | |
| elif ZERO_GPU_AVAILABLE: | |
| print("ZeroGPU support available: GPU time will be requested for audio processing.") | |
| # Multi-model bundles | |
| if not bundles: | |
| print("No ASR models loaded. Check MODEL_PATHS in config.py.") | |
| state_set_model_bundles([]) | |
| else: | |
| state_set_model_bundles(bundles) | |
| loaded_count = len([b for b in bundles if b.get("model")]) | |
| print(f"Loaded {loaded_count}/{len(bundles)} ASR models for multi-model mode.") | |
| # Chapters | |
| chapters = get_chapter_list() | |
| state_set_chapters(chapters) | |
| print(f"Loaded {len(chapters)} chapters") | |
| # Segmentation models (always initialized - VAD auto-detects segment count) | |
| initialize_segment_models() | |
| print("=" * 60) | |
| print("Initialization complete!") | |
| print("=" * 60) | |
| # ----------------------------------------------------------------------------- | |
| # Configuration | |
| # ----------------------------------------------------------------------------- | |
| DEFAULT_PORT = 7860 | |
| PORT = int(os.environ.get("GRADIO_SERVER_PORT", DEFAULT_PORT)) | |
| # HF Spaces auth | |
| HF_PASSWORD = os.environ.get("PASSWORD") | |
| # ----------------------------------------------------------------------------- | |
| # Argument parsing | |
| # ----------------------------------------------------------------------------- | |
| def parse_args(): | |
| parser = argparse.ArgumentParser( | |
| description="Quran Recitation Practice App" | |
| ) | |
| parser.add_argument( | |
| "--share", | |
| action="store_true", | |
| help="Create a public Gradio link" | |
| ) | |
| parser.add_argument( | |
| "--port", | |
| type=int, | |
| default=None, | |
| help="Port to run the server on" | |
| ) | |
| return parser.parse_args() | |
| # ----------------------------------------------------------------------------- | |
| # App construction | |
| # ----------------------------------------------------------------------------- | |
| # Gradio reload works by importing this file repeatedly. | |
| # Must be created at import time. | |
| initialize_app() | |
| # Initialize locale from environment (fallback for initial render) | |
| # The actual locale is set dynamically via ?__locale query param on page load | |
| # User preference is stored in localStorage and applied automatically | |
| from i8n import set_locale, get_available_locales | |
| env_locale = os.environ.get("TAJWEED_LOCALE", "en") | |
| if env_locale in get_available_locales(): | |
| set_locale(env_locale) | |
| print(f"Default locale: {env_locale}") | |
| # Import after initialization (depends on shared_state being populated) | |
| from ui.builder import build_interface | |
| demo = build_interface() | |
| # ----------------------------------------------------------------------------- | |
| # Launch logic | |
| # ----------------------------------------------------------------------------- | |
| def launch_app(): | |
| args = parse_args() | |
| port = args.port or PORT | |
| # Password protection on HF Space | |
| auth = None | |
| if IS_HF_SPACE and HF_PASSWORD: | |
| auth = lambda u, p: p == HF_PASSWORD | |
| # Enable Gradio's built-in i18n for component translations (e.g., Audio buttons) | |
| # Arabic translations for Gradio's built-in component strings | |
| i18n = gr.I18n( | |
| ar={ | |
| "common.audio.record": "تسجيل", | |
| "common.audio.stop": "إيقاف", | |
| "common.audio.upload": "رفع ملف", | |
| "common.audio.pause": "إيقاف مؤقت", | |
| "common.audio.play": "تشغيل", | |
| "common.clear": "مسح", | |
| } | |
| ) | |
| demo.queue(default_concurrency_limit=GRADIO_CONCURRENCY_LIMIT).launch( | |
| server_name="0.0.0.0", | |
| server_port=port, | |
| share=args.share, | |
| auth=auth, | |
| i18n=i18n, | |
| ) | |
| if __name__ == "__main__": | |
| launch_app() | |