Surface YOLO preflight in Detection Lab
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-07-06 10:52:26 +02:00
parent 58608383cd
commit 7aa9382c9e
14 changed files with 275 additions and 1 deletions
+6
View File
@@ -301,6 +301,12 @@ python scripts/yolo_preflight.py --model-path /absolute/path/to/local-model.pt -
The preflight checks configuration, dependency availability, local model file existence, tile manifest validity, tile count and referenced tile paths. JSON output also includes runtime diagnostics for the model directory, `YOLO_CONFIG_DIR`, installed `torch`/`ultralytics` versions and CUDA availability when dependency checks pass. It does not load a YOLO model, run inference or download weights.
The same read-only status is available through the API and Detection Lab UI:
```bash
curl http://localhost:1202/api/v1/detection/yolo/preflight
```
### Run backend
```bash
+11
View File
@@ -9,6 +9,7 @@ from app.db.session import get_db
from app.schemas import DetectionQaRequest, DetectionRunRequest
from app.services.detection_service import DetectionService
from app.services.model_registry_service import ModelRegistryService
from app.services.yolo_preflight_service import YoloPreflightService
from app.utils.response import envelope
router = APIRouter(prefix="/detection", tags=["detection"])
@@ -19,6 +20,16 @@ def list_detection_models() -> dict:
return envelope({"models": [model.model_dump() for model in ModelRegistryService.list_model_capabilities()]})
@router.get("/yolo/preflight", response_model=dict)
def get_yolo_preflight(tile_manifest_path: str | None = None, check_model_load: bool = False) -> dict:
return envelope(
YoloPreflightService.run(
tile_manifest_path=tile_manifest_path,
check_model_load=check_model_load,
)
)
@router.post("/run", response_model=dict)
def run_detection(payload: DetectionRunRequest, db: Session = Depends(get_db)) -> dict:
result = DetectionService.run_detection(
@@ -0,0 +1,25 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
def test_detection_lab_surfaces_yolo_runtime_preflight() -> None:
lab = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
encoding="utf-8"
)
hook = (ROOT / "frontend" / "src" / "hooks" / "useDetectionWorkflow.ts").read_text(encoding="utf-8")
api = (ROOT / "frontend" / "src" / "services" / "api" / "detection.ts").read_text(encoding="utf-8")
types = (ROOT / "frontend" / "src" / "types.ts").read_text(encoding="utf-8")
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
assert "YOLO runtime preflight" in lab
assert "torch_version" in lab
assert "ultralytics_version" in lab
assert "cuda_available" in lab
assert "onRefreshYoloPreflight" in lab
assert "loadYoloPreflight" in hook
assert "getYoloPreflight" in api
assert "/api/v1/detection/yolo/preflight" in api
assert "interface YoloPreflightResponse" in types
assert "yoloPreflight={yoloPreflight}" in app
@@ -5,7 +5,10 @@ import subprocess
import sys
from pathlib import Path
from fastapi.testclient import TestClient
from app.core.config import Settings
from app.main import app
from app.services.yolo_preflight_service import YoloPreflightService
@@ -213,3 +216,21 @@ def test_yolo_preflight_script_rejects_assumed_dependencies_for_model_load(tmp_p
assert result.returncode != 0
assert "--check-model-load cannot be combined with --assume-dependencies" in result.stderr
def test_yolo_preflight_api_returns_canonical_envelope(monkeypatch, tmp_path: Path) -> None:
monkeypatch.setenv("YOLO_ENABLED", "false")
monkeypatch.setenv("YOLO_MODEL_PATH", str(tmp_path / "missing.pt"))
monkeypatch.setenv("YOLO_CONFIG_DIR", str(tmp_path / "ultralytics"))
response = TestClient(app).get("/api/v1/detection/yolo/preflight")
assert response.status_code == 200
payload = response.json()
assert set(payload) == {"data"}
assert payload["data"]["status"] == "not_configured"
assert payload["data"]["checks"]["enabled"] is False
assert payload["data"]["runtime"]["model_directory"] == str(tmp_path)
assert payload["data"]["runtime"]["yolo_config_dir"] == str(tmp_path / "ultralytics")
assert payload["data"]["will_download_models"] is False
assert payload["data"]["will_run_inference"] is False