Spaces:
Paused
Paused
| """ | |
| Configuration Management - Optimized for HF Spaces | |
| """ | |
| import os | |
| import sys | |
| from pathlib import Path | |
| from dotenv import load_dotenv | |
| from dataclasses import dataclass, field | |
| from typing import Dict, Any | |
| # Load environment variables | |
| load_dotenv() | |
| class Config: | |
| """Configuration management for the application""" | |
| # ==================== Platform Detection ==================== | |
| IS_WINDOWS: bool = sys.platform == "win32" | |
| IS_DOCKER: bool = os.path.exists("/.dockerenv") | |
| IS_HF_SPACE: bool = os.getenv("SPACE_ID") is not None or os.getenv("SPACE_AUTHOR_NAME") is not None | |
| # ==================== API Configuration ==================== | |
| API_HOST: str = os.getenv("API_HOST", "0.0.0.0") | |
| API_PORT: int = int(os.getenv("PORT", os.getenv("API_PORT", "7860"))) # HF uses PORT env var | |
| DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true" | |
| # CORS Settings | |
| CORS_ORIGINS: list = field(default_factory=lambda: os.getenv( | |
| "CORS_ORIGINS", "*" | |
| ).split(",")) | |
| # ==================== File Configuration ==================== | |
| BASE_DIR: Path = Path(__file__).parent.parent | |
| UPLOAD_FOLDER: Path = BASE_DIR / "uploads" | |
| OUTPUT_FOLDER: Path = BASE_DIR / "outputs" | |
| SAMPLE_FOLDER: Path = BASE_DIR / "sample_videos" | |
| # File limits | |
| # MAX_FILE_SIZE: int = int(os.getenv("MAX_FILE_SIZE", 104857600)) # 100MB | |
| # MAX_VIDEO_DURATION: int = int(os.getenv("MAX_VIDEO_DURATION", 60)) # seconds | |
| MAX_FILE_SIZE: int = int(os.getenv("MAX_FILE_SIZE", 52428800)) # 50MB for HF | |
| MAX_VIDEO_DURATION: int = int(os.getenv("MAX_VIDEO_DURATION", 30)) # 30s for HF | |
| # Supported formats | |
| SUPPORTED_VIDEO_FORMATS: tuple = (".mp4", ".webm", ".avi", ".mov") | |
| SUPPORTED_MIME_TYPES: tuple = ( | |
| "video/mp4", | |
| "video/webm", | |
| "video/x-msvideo", | |
| "video/quicktime" | |
| ) | |
| # ==================== MediaPipe Configuration ==================== | |
| # Use lightweight model for HF Spaces | |
| MEDIAPIPE_MODEL_COMPLEXITY: int = int( | |
| os.getenv("MEDIAPIPE_MODEL_COMPLEXITY", 0 if IS_HF_SPACE else 1) | |
| ) | |
| MEDIAPIPE_MIN_DETECTION_CONFIDENCE: float = float( | |
| os.getenv("MEDIAPIPE_MIN_DETECTION_CONFIDENCE", 0.5) | |
| ) | |
| MEDIAPIPE_MIN_TRACKING_CONFIDENCE: float = float( | |
| os.getenv("MEDIAPIPE_MIN_TRACKING_CONFIDENCE", 0.5) | |
| ) | |
| MEDIAPIPE_SMOOTH_LANDMARKS: bool = os.getenv( | |
| "MEDIAPIPE_SMOOTH_LANDMARKS", "True" | |
| ).lower() == "true" | |
| # ==================== Processing Configuration ==================== | |
| TARGET_FPS: int = int(os.getenv("TARGET_FPS", 30)) | |
| FRAME_SKIP: int = int(os.getenv("FRAME_SKIP", 1)) | |
| BATCH_SIZE: int = int(os.getenv("BATCH_SIZE", 30)) | |
| # Use compatible codec for HF | |
| OUTPUT_VIDEO_CODEC: str = os.getenv("OUTPUT_VIDEO_CODEC", "mp4v") | |
| OUTPUT_VIDEO_FPS: int = int(os.getenv("OUTPUT_VIDEO_FPS", 30)) | |
| OUTPUT_VIDEO_QUALITY: int = int(os.getenv("OUTPUT_VIDEO_QUALITY", 90)) | |
| # ==================== Movement Classification ==================== | |
| VELOCITY_STANDING: float = 0.01 | |
| VELOCITY_WALKING: float = 0.03 | |
| VELOCITY_DANCING: float = 0.06 | |
| VELOCITY_JUMPING: float = 0.12 | |
| MOVEMENT_INTENSITY_LOW: float = 0.02 | |
| MOVEMENT_INTENSITY_MEDIUM: float = 0.05 | |
| MOVEMENT_INTENSITY_HIGH: float = 0.08 | |
| MOVEMENT_SMOOTHING_WINDOW: int = 5 | |
| # ==================== Visualization Configuration ==================== | |
| SKELETON_COLOR_HIGH_CONF: tuple = (0, 255, 0) | |
| SKELETON_COLOR_MED_CONF: tuple = (0, 255, 255) | |
| SKELETON_COLOR_LOW_CONF: tuple = (0, 165, 255) | |
| SKELETON_LINE_THICKNESS: int = 2 | |
| SKELETON_CIRCLE_RADIUS: int = 4 | |
| SKELETON_CONFIDENCE_THRESHOLD: float = 0.5 | |
| STATUS_BOX_POSITION: tuple = (10, 30) | |
| STATUS_BOX_FONT_SCALE: float = 0.6 | |
| STATUS_BOX_FONT_THICKNESS: int = 2 | |
| STATUS_BOX_COLOR: tuple = (255, 255, 255) | |
| # ==================== Session Management ==================== | |
| SESSION_TIMEOUT: int = int(os.getenv("SESSION_TIMEOUT", 3600)) | |
| MAX_CONCURRENT_SESSIONS: int = int( | |
| os.getenv("MAX_CONCURRENT_SESSIONS", 5 if IS_HF_SPACE else 10) | |
| ) | |
| AUTO_CLEANUP_ENABLED: bool = os.getenv( | |
| "AUTO_CLEANUP_ENABLED", "True" | |
| ).lower() == "true" | |
| CLEANUP_AFTER_HOURS: int = int(os.getenv("CLEANUP_AFTER_HOURS", 24)) | |
| # ==================== WebSocket Configuration ==================== | |
| WS_HEARTBEAT_INTERVAL: int = 20 | |
| WS_MAX_MESSAGE_SIZE: int = 10 * 1024 * 1024 | |
| WS_PING_TIMEOUT: int = 30 | |
| # ==================== Logging Configuration ==================== | |
| LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO") | |
| LOG_FORMAT: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" | |
| LOG_FILE: Path = BASE_DIR / "app.log" | |
| LOG_MAX_BYTES: int = 10 * 1024 * 1024 | |
| LOG_BACKUP_COUNT: int = 5 | |
| # ==================== Performance Configuration ==================== | |
| ENABLE_PROFILING: bool = os.getenv( | |
| "ENABLE_PROFILING", "False" | |
| ).lower() == "true" | |
| MAX_WORKERS: int = int(os.getenv("MAX_WORKERS", 1 if IS_HF_SPACE else 2)) | |
| # ==================== Helper Methods ==================== | |
| def initialize_folders(cls): | |
| """Create necessary directories if they don't exist""" | |
| try: | |
| cls.UPLOAD_FOLDER.mkdir(parents=True, exist_ok=True) | |
| cls.OUTPUT_FOLDER.mkdir(parents=True, exist_ok=True) | |
| # Don't create sample folder on HF Spaces | |
| if not cls.IS_HF_SPACE: | |
| cls.SAMPLE_FOLDER.mkdir(parents=True, exist_ok=True) | |
| except Exception as e: | |
| print(f"⚠️ Warning: Could not create directories: {e}") | |
| def get_mediapipe_config(cls) -> Dict[str, Any]: | |
| """Get MediaPipe configuration dictionary""" | |
| return { | |
| "model_complexity": cls.MEDIAPIPE_MODEL_COMPLEXITY, | |
| "min_detection_confidence": cls.MEDIAPIPE_MIN_DETECTION_CONFIDENCE, | |
| "min_tracking_confidence": cls.MEDIAPIPE_MIN_TRACKING_CONFIDENCE, | |
| "smooth_landmarks": cls.MEDIAPIPE_SMOOTH_LANDMARKS | |
| } | |
| def get_video_output_config(cls) -> Dict[str, Any]: | |
| """Get video output configuration""" | |
| return { | |
| "codec": cls.OUTPUT_VIDEO_CODEC, | |
| "fps": cls.OUTPUT_VIDEO_FPS, | |
| "quality": cls.OUTPUT_VIDEO_QUALITY | |
| } | |
| def get_api_config(cls) -> Dict[str, Any]: | |
| """Get API configuration""" | |
| return { | |
| "host": cls.API_HOST, | |
| "port": cls.API_PORT, | |
| "debug": cls.DEBUG, | |
| "cors_origins": cls.CORS_ORIGINS | |
| } | |
| def validate_config(cls) -> bool: | |
| """Validate configuration settings""" | |
| try: | |
| assert 0 <= cls.MEDIAPIPE_MODEL_COMPLEXITY <= 2, \ | |
| "Model complexity must be 0, 1, or 2" | |
| assert 0.0 <= cls.MEDIAPIPE_MIN_DETECTION_CONFIDENCE <= 1.0, \ | |
| "Detection confidence must be between 0.0 and 1.0" | |
| assert 0.0 <= cls.MEDIAPIPE_MIN_TRACKING_CONFIDENCE <= 1.0, \ | |
| "Tracking confidence must be between 0.0 and 1.0" | |
| assert cls.MAX_FILE_SIZE > 0, "Max file size must be positive" | |
| assert cls.TARGET_FPS > 0, "Target FPS must be positive" | |
| assert 1 <= cls.API_PORT <= 65535, "Port must be between 1 and 65535" | |
| return True | |
| except AssertionError as e: | |
| print(f"❌ Configuration validation failed: {e}") | |
| return False | |
| def print_config(cls): | |
| """Print current configuration""" | |
| print("=" * 70) | |
| print("Current Configuration") | |
| print("=" * 70) | |
| print(f"Platform: {'Windows' if cls.IS_WINDOWS else 'Linux/Mac'}") | |
| print(f"Docker: {cls.IS_DOCKER}") | |
| print(f"HF Space: {cls.IS_HF_SPACE}") | |
| print(f"API Host: {cls.API_HOST}") | |
| print(f"API Port: {cls.API_PORT}") | |
| print(f"Debug Mode: {cls.DEBUG}") | |
| print(f"Max File Size: {cls.MAX_FILE_SIZE / (1024*1024):.0f} MB") | |
| print(f"Max Video Duration: {cls.MAX_VIDEO_DURATION}s") | |
| print(f"MediaPipe Model: Complexity {cls.MEDIAPIPE_MODEL_COMPLEXITY}") | |
| print(f"Detection Confidence: {cls.MEDIAPIPE_MIN_DETECTION_CONFIDENCE}") | |
| print(f"Upload Folder: {cls.UPLOAD_FOLDER}") | |
| print(f"Output Folder: {cls.OUTPUT_FOLDER}") | |
| print("=" * 70) | |
| # ==================== Instantiate Global Config ==================== | |
| config = Config() | |
| # Validate configuration on import | |
| if not config.validate_config(): | |
| print("⚠️ Warning: Invalid configuration detected") | |
| # Initialize folders on import | |
| config.initialize_folders() | |
| if __name__ == "__main__": | |
| config.print_config() |