feat: add passive K1 local surface replay
This commit is contained in:
@@ -9,11 +9,14 @@ from typing import Annotated, Any, Final
|
||||
from fastapi import APIRouter, HTTPException, Query, Response
|
||||
|
||||
from k1link.compute import (
|
||||
E10LidarFieldSource,
|
||||
K1LocalSurfaceV1,
|
||||
LidarFieldReviewV1,
|
||||
LidarGroundBenchmarkV1,
|
||||
LidarGroundError,
|
||||
LidarReplayError,
|
||||
LidarReplayPackV2,
|
||||
k1_local_surface_catalog_item,
|
||||
lidar_field_review_catalog_item,
|
||||
lidar_ground_benchmark_catalog_item,
|
||||
lidar_ground_frame_detail,
|
||||
@@ -34,9 +37,12 @@ from k1link.datasets import (
|
||||
LIDAR_CATALOG_SCHEMA: Final = "missioncore.lidar-replay-pack-catalog/v1"
|
||||
LIDAR_GROUND_CATALOG_SCHEMA: Final = "missioncore.lidar-ground-benchmark-catalog/v1"
|
||||
LIDAR_FIELD_REVIEW_CATALOG_SCHEMA: Final = "missioncore.lidar-field-review-catalog/v1"
|
||||
K1_LOCAL_SURFACE_CATALOG_SCHEMA: Final = "missioncore.k1-local-surface-catalog/v1"
|
||||
_PACK_ID = re.compile(r"^lidar-replay-pack-[a-f0-9]{64}$")
|
||||
_BENCHMARK_ID = re.compile(r"^ground-benchmark-[a-f0-9]{64}$")
|
||||
_FIELD_REVIEW_ID = re.compile(r"^lidar-field-review-[a-f0-9]{64}$")
|
||||
_LOCAL_SURFACE_ID = re.compile(r"^k1-local-surface-[a-f0-9]{64}$")
|
||||
_E10_PACK_ID = re.compile(r"^e10-lidar-pack-[a-f0-9]{64}$")
|
||||
RootProvider = Callable[[], Path | None]
|
||||
DatasetArtifactProvider = Callable[[], Path | None]
|
||||
|
||||
@@ -56,11 +62,23 @@ def configured_lidar_field_review_root() -> Path | None:
|
||||
return Path(value).expanduser().absolute() if value else None
|
||||
|
||||
|
||||
def configured_k1_local_surface_root() -> Path | None:
|
||||
value = os.environ.get("MISSIONCORE_K1_LOCAL_SURFACE_ROOT", "").strip()
|
||||
return Path(value).expanduser().absolute() if value else None
|
||||
|
||||
|
||||
def configured_e10_lidar_source_root() -> Path | None:
|
||||
value = os.environ.get("MISSIONCORE_E10_LIDAR_SOURCE_ROOT", "").strip()
|
||||
return Path(value).expanduser().absolute() if value else None
|
||||
|
||||
|
||||
def build_lidar_router(
|
||||
*,
|
||||
root_provider: RootProvider = configured_lidar_replay_root,
|
||||
ground_root_provider: RootProvider = configured_lidar_ground_root,
|
||||
field_review_root_provider: RootProvider = configured_lidar_field_review_root,
|
||||
local_surface_root_provider: RootProvider = configured_k1_local_surface_root,
|
||||
e10_source_root_provider: RootProvider = configured_e10_lidar_source_root,
|
||||
dataset_admission_provider: DatasetArtifactProvider = configured_dataset_admission_manifest,
|
||||
dataset_preview_provider: DatasetArtifactProvider = configured_dataset_preview,
|
||||
dataset_rellis_preview_provider: DatasetArtifactProvider = lambda: None,
|
||||
@@ -483,4 +501,111 @@ def build_lidar_router(
|
||||
headers={"Cache-Control": "private, max-age=31536000, immutable"},
|
||||
)
|
||||
|
||||
@router.get("/local-surfaces")
|
||||
def list_k1_local_surfaces(
|
||||
limit: int = Query(default=10, ge=1, le=50),
|
||||
) -> dict[str, Any]:
|
||||
root = local_surface_root_provider()
|
||||
if root is None or not root.is_dir():
|
||||
return {
|
||||
"schema_version": K1_LOCAL_SURFACE_CATALOG_SCHEMA,
|
||||
"configured": root is not None,
|
||||
"items": [],
|
||||
"valid_total": 0,
|
||||
"invalid_total": 0,
|
||||
"access": "read-only",
|
||||
}
|
||||
items: list[dict[str, object]] = []
|
||||
invalid_total = 0
|
||||
candidates = sorted(
|
||||
(
|
||||
candidate
|
||||
for candidate in root.iterdir()
|
||||
if candidate.is_dir()
|
||||
and _LOCAL_SURFACE_ID.fullmatch(candidate.name) is not None
|
||||
),
|
||||
key=lambda candidate: candidate.stat().st_mtime_ns,
|
||||
reverse=True,
|
||||
)
|
||||
for candidate in candidates:
|
||||
try:
|
||||
model = K1LocalSurfaceV1(candidate)
|
||||
try:
|
||||
items.append(k1_local_surface_catalog_item(model))
|
||||
finally:
|
||||
model.close()
|
||||
except (LidarGroundError, OSError):
|
||||
invalid_total += 1
|
||||
return {
|
||||
"schema_version": K1_LOCAL_SURFACE_CATALOG_SCHEMA,
|
||||
"configured": True,
|
||||
"items": items[:limit],
|
||||
"valid_total": len(items),
|
||||
"invalid_total": invalid_total,
|
||||
"access": "read-only",
|
||||
}
|
||||
|
||||
@router.get("/local-surfaces/{model_id}/frames/{frame_index}")
|
||||
def get_k1_local_surface_frame(
|
||||
model_id: str,
|
||||
frame_index: int,
|
||||
) -> dict[str, object]:
|
||||
if _LOCAL_SURFACE_ID.fullmatch(model_id) is None or frame_index < 0:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="K1 local-surface frame не найден",
|
||||
)
|
||||
model_root = local_surface_root_provider()
|
||||
source_root = e10_source_root_provider()
|
||||
if model_root is None or not model_root.is_dir():
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="K1 local-surface storage не настроен",
|
||||
)
|
||||
if source_root is None or not source_root.is_dir():
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="E10 LiDAR source storage не настроен",
|
||||
)
|
||||
model_path = model_root / model_id
|
||||
if not model_path.is_dir():
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="K1 local-surface model не найден",
|
||||
)
|
||||
try:
|
||||
model = K1LocalSurfaceV1(model_path)
|
||||
try:
|
||||
source_pack_id = model.identity.get("source_pack_id")
|
||||
if (
|
||||
not isinstance(source_pack_id, str)
|
||||
or _E10_PACK_ID.fullmatch(source_pack_id) is None
|
||||
):
|
||||
raise LidarGroundError("K1 local-surface source id is invalid")
|
||||
source_path = source_root / source_pack_id
|
||||
if not source_path.is_dir():
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="Связанный E10 LiDAR source не найден",
|
||||
)
|
||||
source = E10LidarFieldSource(source_path)
|
||||
try:
|
||||
return model.frame_detail(source, frame_index)
|
||||
finally:
|
||||
source.close()
|
||||
finally:
|
||||
model.close()
|
||||
except IndexError as exc:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="K1 local-surface frame не найден",
|
||||
) from exc
|
||||
except HTTPException:
|
||||
raise
|
||||
except (LidarGroundError, OSError) as exc:
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail="K1 local-surface evidence не прошло проверку целостности",
|
||||
) from exc
|
||||
|
||||
return router
|
||||
|
||||
Reference in New Issue
Block a user