""" config.py - Configuration Management System """ import yaml from pathlib import Path from typing import Any, Dict, Optional class Config: def __init__(self, config_path: str = "config.yaml"): self.config_path = Path(config_path) self.config = self._load_config() print(f"✅ Configuration loaded") def _load_config(self) -> Dict: if not self.config_path.exists(): print(f"⚠️ Config file not found: {self.config_path}") print(" Using default configuration") return self._get_defaults() try: with open(self.config_path, 'r', encoding='utf-8') as f: config = yaml.safe_load(f) print(f" Loaded from: {self.config_path}") return config except Exception as e: print(f"❌ Error loading config: {e}") print(" Using default configuration") return self._get_defaults() def _get_defaults(self) -> Dict: return { 'detection': { 'model': 'yolov8m.pt', 'confidence_threshold': 0.50, 'min_detection_area': 900, 'dog_class_id': 16 }, 'pose_detection': { 'model': 'dog-pose-trained.pt', 'confidence_threshold': 0.5, 'input_size': 640, 'keypoint_8_indices': [0, 3, 7, 10, 12, 14, 17, 19] }, 'tracking': { 'max_iou_distance': 0.5, 'max_age': 90, 'n_init': 1, 'use_appearance': True, 'deletion_threshold_confirmed': 30, 'deletion_threshold_tentative': 5 }, 'reid': { 'model': 'hf-hub:BVRA/MegaDescriptor-L-384', 'threshold': 0.40, 'permanent_db_threshold_offset': 0.15, 'max_features_per_dog': 30 }, 'health': { 'temporal_window': 15, 'min_visible_keypoints': 12, 'min_view_score': 0.7, 'blur_threshold': 75 }, 'dataset': { 'min_images_per_dog': 14, 'max_images_per_dog': 30, 'min_frame_gap': 15, 'sample_rate': 1 }, 'map': { 'default_location': [38.9637, 35.2433], 'default_zoom': 13 }, 'database': { 'path': 'dog_monitoring.db', 'backup_enabled': True }, 'app': { 'max_video_duration': 600, 'max_memory_mb': 2000, 'max_total_dogs': 50 } } def get(self, path: str, default: Any = None) -> Any: keys = path.split('.') value = self.config for key in keys: if isinstance(value, dict) and key in value: value = value[key] else: return default return value def set(self, path: str, value: Any): keys = path.split('.') config = self.config for key in keys[:-1]: if key not in config: config[key] = {} config = config[key] config[keys[-1]] = value def save(self, output_path: Optional[str] = None): save_path = Path(output_path) if output_path else self.config_path try: with open(save_path, 'w', encoding='utf-8') as f: yaml.dump(self.config, f, default_flow_style=False, allow_unicode=True) print(f"✅ Configuration saved to {save_path}") except Exception as e: print(f"❌ Error saving config: {e}") def get_detection_config(self) -> Dict: return self.config.get('detection', self._get_defaults()['detection']) def get_pose_config(self) -> Dict: return self.config.get('pose_detection', self._get_defaults()['pose_detection']) def get_tracking_config(self) -> Dict: return self.config.get('tracking', self._get_defaults()['tracking']) def get_reid_config(self) -> Dict: return self.config.get('reid', self._get_defaults()['reid']) def get_health_config(self) -> Dict: return self.config.get('health', self._get_defaults()['health']) def get_dataset_config(self) -> Dict: return self.config.get('dataset', self._get_defaults()['dataset']) def get_map_config(self) -> Dict: return self.config.get('map', self._get_defaults()['map']) def get_database_config(self) -> Dict: return self.config.get('database', self._get_defaults()['database']) def get_app_config(self) -> Dict: return self.config.get('app', self._get_defaults()['app']) def print_config(self): print("\n" + "="*60) print("CURRENT CONFIGURATION") print("="*60) self._print_dict(self.config, indent=0) print("="*60 + "\n") def _print_dict(self, d: Dict, indent: int = 0): for key, value in d.items(): if isinstance(value, dict): print(" " * indent + f"{key}:") self._print_dict(value, indent + 1) else: print(" " * indent + f"{key}: {value}") def validate(self) -> bool: required_sections = ['detection', 'tracking', 'reid', 'health', 'database'] for section in required_sections: if section not in self.config: print(f"❌ Missing required section: {section}") return False print("✅ Configuration validated successfully") return True