from __future__ import annotations from pathlib import Path from typing import Type from app.core.config import Settings, get_settings from app.schemas.detection import DetectionModelCapability from app.services.yolo_adapter import YoloDetectionAdapter class ModelRegistryService: @staticmethod def list_model_capabilities( settings: Settings | None = None, yolo_adapter_class: Type[YoloDetectionAdapter] = YoloDetectionAdapter, task_type: str = "object_detection", ) -> list[DetectionModelCapability]: resolved_settings = settings or get_settings() if task_type == "segmentation": return ModelRegistryService.list_segmentation_model_capabilities() if task_type != "object_detection": return [] return [ DetectionModelCapability( model_id="yolo-placeholder", display_name="YOLO detector placeholder", framework="ultralytics/pytorch", task_type="object_detection", supported_classes=["building", "road", "water", "landuse"], configured=False, status="not_configured", limitation_message="YOLO/PyTorch inference is not configured in Sprint 8; no model is downloaded or executed.", version=None, ), ModelRegistryService._configured_yolo_capability(resolved_settings, yolo_adapter_class), DetectionModelCapability( model_id="manual-fixture-detector", display_name="Manual fixture detector", framework="fixture", task_type="object_detection", supported_classes=["building"], configured=True, status="configured", limitation_message="Fixture detector is for explicit tests/demo fixtures only and is not production inference.", version="fixture-v1", ), ] @staticmethod def get_model_capability( model_id: str, settings: Settings | None = None, yolo_adapter_class: Type[YoloDetectionAdapter] = YoloDetectionAdapter, task_type: str = "object_detection", ) -> DetectionModelCapability | None: normalized = model_id.strip() for model in ModelRegistryService.list_model_capabilities(settings=settings, yolo_adapter_class=yolo_adapter_class, task_type=task_type): if model.model_id == normalized: return model return None @staticmethod def list_segmentation_model_capabilities() -> list[DetectionModelCapability]: return [ DetectionModelCapability( model_id="segmentation-placeholder", display_name="Segmentation placeholder", framework="placeholder", task_type="segmentation", supported_classes=["building", "vegetation", "water", "landuse"], configured=False, status="not_configured", limitation_message="Segmentation inference is not configured in Sprint 9; no SAM/YOLO-seg model is downloaded or executed.", version=None, ), DetectionModelCapability( model_id="fixture-segmenter", display_name="Fixture segmenter", framework="fixture", task_type="segmentation", supported_classes=["building", "vegetation", "water", "landuse"], configured=True, status="configured", limitation_message="Fixture segmenter is for explicit tests/demo fixtures only and is not production inference.", version="fixture-v1", ), DetectionModelCapability( model_id="yolo-seg-configured", display_name="Configured YOLO segmentation", framework="ultralytics/pytorch", task_type="segmentation", supported_classes=["building", "vegetation", "water", "landuse"], configured=False, status="not_configured", limitation_message="YOLO-seg is not configured in Sprint 9. GeoIntel will not download segmentation model weights automatically.", version=None, ), DetectionModelCapability( model_id="sam-configured", display_name="Configured SAM segmentation", framework="sam", task_type="segmentation", supported_classes=["building", "vegetation", "water", "landuse"], configured=False, status="not_configured", limitation_message="SAM is not configured in Sprint 9 and is not installed as a backend dependency.", version=None, ), ] @staticmethod def _configured_yolo_capability( settings: Settings, yolo_adapter_class: Type[YoloDetectionAdapter], ) -> DetectionModelCapability: configured = False status = "not_configured" limitation = "YOLO is disabled. Set YOLO_ENABLED=true and YOLO_MODEL_PATH to a local model file to enable inference." model_path = Path(settings.yolo_model_path).expanduser() if settings.yolo_model_path else None if settings.yolo_enabled: if not yolo_adapter_class.dependencies_available(): status = "dependency_unavailable" limitation = "YOLO dependencies are not installed. Install backend optional extras with geointel-backend[ai]." elif model_path is None: limitation = "YOLO_MODEL_PATH is not set. GeoIntel will not download model weights automatically." elif not model_path.exists() or not model_path.is_file(): limitation = "YOLO_MODEL_PATH does not point to an existing local model file. GeoIntel will not download model weights automatically." else: configured = True status = "configured" limitation = "Configured for local YOLO inference over an existing raster tile manifest." return DetectionModelCapability( model_id=settings.yolo_model_id, display_name=settings.yolo_model_display_name, framework="ultralytics/pytorch", task_type="object_detection", supported_classes=["building", "road", "water", "landuse"], configured=configured, status=status, limitation_message=limitation, version=settings.yolo_model_version, )