import logging import asyncio import uvicorn import sys from contextlib import asynccontextmanager from fastapi import FastAPI # --- API & Streaming --- from f01_flight_api import router as flight_router from f01_flight_api import get_lifecycle_manager, get_flight_database from f15_sse_event_streamer import SSEEventStreamer # --- Base Managers & Helpers --- from h04_faiss_index_manager import FaissIndexManager from f04_satellite_data_manager import SatelliteDataManager, CacheConfig from f03_flight_database import FlightDatabase # --- Vision & Metric Components --- from f09_local_geospatial_anchoring import LocalGeospatialAnchoring from f06_image_rotation_manager import ImageRotationManager from f08_global_place_recognition import GlobalPlaceRecognition from f07_sequential_visual_odometry import SequentialVisualOdometry from f05_image_input_pipeline import ImageInputPipeline from f14_result_manager import ResultManager from f16_model_manager import ModelManager from f17_configuration_manager import ConfigurationManager from f13_coordinate_transformer import CoordinateTransformer from h01_camera_model import CameraModel # --- Optimization & Graph Components --- from f10_factor_graph_optimizer import FactorGraphOptimizer from f12_route_chunk_manager import RouteChunkManager # --- Orchestration --- from f11_failure_recovery_coordinator import FailureRecoveryCoordinator from f02_2_flight_processing_engine import FlightProcessingEngine from f02_1_flight_lifecycle_manager import FlightLifecycleManager logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", handlers=[ logging.FileHandler("server_debug.log", mode='w'), logging.StreamHandler(sys.stdout) ] ) logger = logging.getLogger("AURA_Main") # Global reference for API access (can be accessed inside FastAPI route handlers) lifecycle_manager = None db_manager = None @asynccontextmanager async def lifespan(app: FastAPI): """FastAPI Lifespan Context Manager. Instantiates pipeline components.""" global lifecycle_manager, db_manager logger.info("Initializing AURA Pipeline Components...") # 1. Instantiate Base Managers faiss_manager = FaissIndexManager() sat_manager = SatelliteDataManager(CacheConfig()) db_manager = FlightDatabase() sse_streamer = SSEEventStreamer() # 2. Instantiate Vision/Metric Components config_manager = ConfigurationManager(f03_database=db_manager) model_manager = ModelManager() metric_refinement = LocalGeospatialAnchoring(model_manager=model_manager) rotation_manager = ImageRotationManager() global_place_rec = GlobalPlaceRecognition(model_manager, faiss_manager, sat_manager) # 3. Instantiate Odometry and Input vo_frontend = SequentialVisualOdometry(model_manager) image_pipeline = ImageInputPipeline() # 4. Instantiate Optimization and Chunking factor_graph = FactorGraphOptimizer() chunk_manager = RouteChunkManager(f03=db_manager, f05=image_pipeline, f08=global_place_rec, f10=factor_graph) result_manager = ResultManager(f03_database=db_manager, f15_streamer=sse_streamer) camera_model = CameraModel() coord_transformer = CoordinateTransformer(f10_optimizer=factor_graph, f17_config=config_manager, camera_model=camera_model) # 5. Instantiate Failure Recovery Coordinator recovery_deps = { "satellite_data_manager": sat_manager, "image_rotation_manager": rotation_manager, "global_place_recognition": global_place_rec, "metric_refinement": metric_refinement, "factor_graph_optimizer": factor_graph, "route_chunk_manager": chunk_manager } failure_coordinator = FailureRecoveryCoordinator(recovery_deps) # 7. Instantiate Lifecycle Manager and bind overrides lifecycle_manager = FlightLifecycleManager( db_adapter=db_manager, orchestrator=None, config_manager=config_manager, model_manager=model_manager, satellite_manager=sat_manager, place_recognition=global_place_rec, coordinate_transformer=coord_transformer, sse_streamer=sse_streamer ) # 8. Bind Engine Factory Override to connect Real Engine def real_engine_factory(flight_id: str) -> FlightProcessingEngine: return FlightProcessingEngine( f04=sat_manager, f05=image_pipeline, f06=rotation_manager, f07=vo_frontend, f08=global_place_rec, f09=metric_refinement, f10=factor_graph, f11=failure_coordinator, f12=chunk_manager, f13=coord_transformer, f14=result_manager, f15=sse_streamer, f17=config_manager ) def _get_or_create_engine_override(flight_id: str): if flight_id not in lifecycle_manager.active_engines: lifecycle_manager.active_engines[flight_id] = real_engine_factory(flight_id) return lifecycle_manager.active_engines[flight_id] lifecycle_manager._get_or_create_engine = _get_or_create_engine_override lifecycle_manager._delegate_queue_batch = image_pipeline.queue_batch lifecycle_manager.initialize_system() app.dependency_overrides[get_lifecycle_manager] = lambda: lifecycle_manager app.dependency_overrides[get_flight_database] = lambda: db_manager logger.info("AURA Pipeline successfully initialized and bound to API.") yield logger.info("Shutting down AURA Pipeline...") if lifecycle_manager: for engine in lifecycle_manager.active_engines.values(): if hasattr(engine, "stop_processing"): engine.stop_processing() app = FastAPI(title="AURA GPS-Denied Navigation API", lifespan=lifespan) app.include_router(flight_router) if __name__ == "__main__": logger.info("Starting AURA REST API & SSE Service...") uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=False)