Spaces:
Running
Running
| from threading import Lock | |
| from fastapi import FastAPI, HTTPException, Query | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.staticfiles import StaticFiles | |
| from .config import get_settings | |
| from .schemas import ObjectSearchRequest, TrailRequest | |
| from .services import AfterimageService | |
| settings = get_settings() | |
| _service_lock = Lock() | |
| _service_instance: AfterimageService | None = None | |
| app = FastAPI(title="Afterimage API", version="0.1.0") | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=settings.cors_origin_list, | |
| allow_credentials=False, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| app.mount("/assets", StaticFiles(directory=settings.resolved_asset_root), name="assets") | |
| def service() -> AfterimageService: | |
| global _service_instance | |
| if _service_instance is None: | |
| with _service_lock: | |
| if _service_instance is None: | |
| _service_instance = AfterimageService(settings) | |
| return _service_instance | |
| def bad_request(exc: Exception) -> HTTPException: | |
| return HTTPException(status_code=400, detail=str(exc)) | |
| def health(): | |
| try: | |
| return service().health() | |
| except Exception as exc: | |
| raise HTTPException(status_code=503, detail=str(exc)) from exc | |
| def scenarios(): | |
| try: | |
| return service().scenarios() | |
| except Exception as exc: | |
| raise HTTPException(status_code=503, detail=str(exc)) from exc | |
| def memories( | |
| scenario: str = Query(default="vault", max_length=60), | |
| zone: str | None = Query(default=None), | |
| region_id: str | None = Query(default=None), | |
| is_baseline: bool | None = Query(default=None), | |
| ): | |
| try: | |
| return service().memories(scenario=scenario, zone=zone, region_id=region_id, is_baseline=is_baseline) | |
| except ValueError as exc: | |
| raise bad_request(exc) from exc | |
| def anomaly_scan(scenario: str = Query(default="vault", max_length=60)): | |
| try: | |
| return service().scan_anomalies(scenario=scenario) | |
| except (FileNotFoundError, ValueError) as exc: | |
| raise bad_request(exc) from exc | |
| def object_search(request: ObjectSearchRequest): | |
| try: | |
| return service().object_search( | |
| scenario=request.scenario, | |
| asset_id=request.asset_id or request.crop_id, | |
| image_ref=request.image_ref, | |
| filters=request.filters, | |
| limit=request.limit, | |
| ) | |
| except (FileNotFoundError, ValueError) as exc: | |
| raise bad_request(exc) from exc | |
| def trail(request: TrailRequest): | |
| try: | |
| return service().trail( | |
| scenario=request.scenario, | |
| asset_id=request.asset_id or request.crop_id, | |
| image_ref=request.image_ref, | |
| score_cutoff=request.score_cutoff, | |
| ) | |
| except (FileNotFoundError, ValueError) as exc: | |
| raise bad_request(exc) from exc | |
| def outliers(scenario: str = Query(default="vault", max_length=60)): | |
| try: | |
| return service().outliers(scenario=scenario) | |
| except ValueError as exc: | |
| raise bad_request(exc) from exc | |
| def matrix(scenario: str = Query(default="vault", max_length=60), sample: int = Query(default=24, ge=1, le=100)): | |
| try: | |
| return service().matrix(scenario=scenario, sample=sample) | |
| except ValueError as exc: | |
| raise bad_request(exc) from exc | |
| def text_search(q: str = Query(..., max_length=120), scenario: str | None = Query(default=None, max_length=60)): | |
| try: | |
| return service().text_search(query=q, scenario=scenario) | |
| except (FileNotFoundError, ValueError) as exc: | |
| raise bad_request(exc) from exc | |