""" DI container — constructs every dependency ONCE at app startup and wires services together. This is the composition root. No globals: the container is created in `create_app()` and stored on `app.state.container`. Route handlers retrieve it via the `get_container` FastAPI dependency. """ from __future__ import annotations from dataclasses import dataclass from config.settings import Settings, DATA_DIR, GALLERY_DIR, UPLOADS_DIR, JOBS_DIR from confidence.engine import ConfidenceEngine from confidence.conflicts import ConflictDetector from metrics.collector import MetricsCollector from orchestrator.health import HealthMonitor from orchestrator.runner import Orchestrator from pipeline import ( InputValidator, ImagePreprocessor, ImageHasher, FeatureExtractor, ) from providers.registry import ProviderRegistry from services.analysis_service import AnalysisService from services.cache_service import CacheService from services.detection_service import DetectionService from services.export_service import ExportService from services.face_index_service import FaceIndexService from services.face_intelligence_service import FaceIntelligenceService from services.forensic_metadata_service import ForensicMetadataService from services.health_service import HealthService from services.job_service import JobService from services.location_intelligence_service import LocationIntelligenceService from services.object_intelligence_service import ObjectIntelligenceService from services.osint_service import OSINTService from services.correlation_engine_service import CorrelationEngineService from services.provider_service import ProviderService from services.recognition_service import RecognitionService from services.search_service import SearchService from storage.artifacts import ArtifactStore from storage.cache import Cache from storage.database import Database from storage.face_index import FaceIndex from storage.reference_store import ReferenceStore @dataclass class ServiceContainer: """Holds every wired service + infrastructure object.""" settings: Settings registry: ProviderRegistry cache: Cache database: Database artifacts: ArtifactStore reference_store: ReferenceStore metrics: MetricsCollector health_monitor: HealthMonitor orchestrator: Orchestrator confidence_engine: ConfidenceEngine conflict_detector: ConflictDetector validator: InputValidator preprocessor: ImagePreprocessor hasher: ImageHasher feature_extractor: FeatureExtractor detection_service: DetectionService recognition_service: RecognitionService search_service: SearchService analysis_service: AnalysisService job_service: JobService osint_service: OSINTService face_intelligence_service: FaceIntelligenceService forensic_metadata_service: ForensicMetadataService object_intelligence_service: ObjectIntelligenceService location_intelligence_service: LocationIntelligenceService correlation_engine_service: CorrelationEngineService provider_service: ProviderService cache_service: CacheService health_service: HealthService export_service: ExportService face_index: FaceIndex face_index_service: FaceIndexService def build_container(settings: Settings | None = None) -> ServiceContainer: """Construct the entire dependency graph. Called once at startup.""" settings = settings or Settings() # Infrastructure registry = ProviderRegistry(settings) registry.discover() cache = Cache( ttl_seconds=settings.cache_ttl_seconds, max_entries=settings.cache_max_entries, ) database = Database(path=settings.db_path) artifacts = ArtifactStore(root=UPLOADS_DIR) reference_store = ReferenceStore(root=GALLERY_DIR) metrics = MetricsCollector( failure_threshold=settings.circuit_breaker_failure_threshold, recovery_seconds=settings.circuit_breaker_recovery_seconds, ) health_monitor = HealthMonitor(metrics=metrics.health) orchestrator = Orchestrator( registry=registry, cache=cache, metrics=metrics, health=health_monitor, settings=settings, ) confidence_engine = ConfidenceEngine() conflict_detector = ConflictDetector() # Pipeline validator = InputValidator(max_bytes=settings.max_image_bytes) preprocessor = ImagePreprocessor(max_dim=1024) hasher = ImageHasher() # Use the first available detection provider as the default feature extractor from models.providers import ProviderCapability detectors = registry.list_by_capability(ProviderCapability.DETECTION) default_detector = detectors[0] if detectors else None feature_extractor = FeatureExtractor(detector=default_detector) # Services detection_service = DetectionService( registry=registry, orchestrator=orchestrator, cache=cache, metrics=metrics, validator=validator, preprocessor=preprocessor, hasher=hasher, feature_extractor=feature_extractor, confidence_engine=confidence_engine, conflict_detector=conflict_detector, ) recognition_service = RecognitionService( orchestrator=orchestrator, metrics=metrics, validator=validator, preprocessor=preprocessor, hasher=hasher, feature_extractor=feature_extractor, reference_store=reference_store, confidence_engine=confidence_engine, conflict_detector=conflict_detector, ) search_service = SearchService( orchestrator=orchestrator, metrics=metrics, validator=validator, preprocessor=preprocessor, hasher=hasher, feature_extractor=feature_extractor, confidence_engine=confidence_engine, conflict_detector=conflict_detector, ) analysis_service = AnalysisService( orchestrator=orchestrator, metrics=metrics, validator=validator, preprocessor=preprocessor, hasher=hasher, feature_extractor=feature_extractor, confidence_engine=confidence_engine, conflict_detector=conflict_detector, ) job_service = JobService( detection=detection_service, recognition=recognition_service, search=search_service, analysis=analysis_service, database=database, metrics=metrics, job_timeout_seconds=settings.job_timeout_seconds, ) osint_service = OSINTService( orchestrator=orchestrator, metrics=metrics, validator=validator, preprocessor=preprocessor, hasher=hasher, feature_extractor=feature_extractor, ) face_intelligence_service = FaceIntelligenceService( validator=validator, preprocessor=preprocessor, hasher=hasher, feature_extractor=feature_extractor, ) forensic_metadata_service = ForensicMetadataService( validator=validator, preprocessor=preprocessor, hasher=hasher, ) object_intelligence_service = ObjectIntelligenceService( orchestrator=orchestrator, validator=validator, preprocessor=preprocessor, hasher=hasher, feature_extractor=feature_extractor, ) location_intelligence_service = LocationIntelligenceService( validator=validator, preprocessor=preprocessor, hasher=hasher, ) correlation_engine_service = CorrelationEngineService( validator=validator, preprocessor=preprocessor, hasher=hasher, ) provider_service = ProviderService(registry=registry) cache_service = CacheService(cache=cache) health_service = HealthService( registry=registry, health_monitor=health_monitor, metrics=metrics, version=settings.app_version, ) export_service = ExportService(database=database) # Reverse face search index (sqlite-vec backed) face_index = FaceIndex(path=settings.face_index_path) face_index_service = FaceIndexService( settings=settings, validator=validator, preprocessor=preprocessor, hasher=hasher, feature_extractor=feature_extractor, face_index=face_index, ) return ServiceContainer( settings=settings, registry=registry, cache=cache, database=database, artifacts=artifacts, reference_store=reference_store, metrics=metrics, health_monitor=health_monitor, orchestrator=orchestrator, confidence_engine=confidence_engine, conflict_detector=conflict_detector, validator=validator, preprocessor=preprocessor, hasher=hasher, feature_extractor=feature_extractor, detection_service=detection_service, recognition_service=recognition_service, search_service=search_service, analysis_service=analysis_service, job_service=job_service, osint_service=osint_service, face_intelligence_service=face_intelligence_service, forensic_metadata_service=forensic_metadata_service, object_intelligence_service=object_intelligence_service, location_intelligence_service=location_intelligence_service, correlation_engine_service=correlation_engine_service, provider_service=provider_service, cache_service=cache_service, health_service=health_service, export_service=export_service, face_index=face_index, face_index_service=face_index_service, )