feat: qualify complete RELLIS ground dataset
This commit is contained in:
@@ -429,6 +429,9 @@ app.include_router(
|
||||
dataset_rellis_preview_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "dataset-gateway" / "rellis-preview.json"
|
||||
),
|
||||
dataset_rellis_admission_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "dataset-gateway" / "rellis-admission.json"
|
||||
),
|
||||
dataset_ground_preview_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "dataset-gateway" / "ground-comparison.json"
|
||||
),
|
||||
|
||||
@@ -64,6 +64,7 @@ def build_lidar_router(
|
||||
dataset_admission_provider: DatasetArtifactProvider = configured_dataset_admission_manifest,
|
||||
dataset_preview_provider: DatasetArtifactProvider = configured_dataset_preview,
|
||||
dataset_rellis_preview_provider: DatasetArtifactProvider = lambda: None,
|
||||
dataset_rellis_admission_provider: DatasetArtifactProvider = lambda: None,
|
||||
dataset_ground_preview_provider: DatasetArtifactProvider = configured_dataset_ground_preview,
|
||||
) -> APIRouter:
|
||||
router = APIRouter(prefix="/api/v1/lidar", tags=["lidar"])
|
||||
@@ -73,6 +74,7 @@ def build_lidar_router(
|
||||
return dataset_gateway_catalog(
|
||||
admission_manifest_path=dataset_admission_provider(),
|
||||
rellis_preview_path=dataset_rellis_preview_provider(),
|
||||
rellis_admission_path=dataset_rellis_admission_provider(),
|
||||
)
|
||||
|
||||
@router.get("/dataset-gateway/preview")
|
||||
|
||||
@@ -41,17 +41,21 @@ DETAIL_SCHEMA: Final = "missioncore.polygon-run-detail/v1"
|
||||
GROUND_QUALIFICATION_SCHEMA: Final = "missioncore.polygon-ground-qualification/v1"
|
||||
GROUND_FAILURE_PREVIEW_SCHEMA: Final = "missioncore.polygon-ground-failure-preview/v1"
|
||||
GROUND_REPORT_ARTIFACT_KIND: Final = "goose-ground-qualification-report"
|
||||
RELLIS_REPORT_ARTIFACT_KIND: Final = "rellis-ground-qualification-report"
|
||||
GROUND_FAILURE_ARTIFACT_KIND: Final = "goose-ground-qualification-failure-preview"
|
||||
GROUND_REPORT_SCHEMA: Final = "missioncore.goose-ground-qualification-report/v1"
|
||||
RELLIS_REPORT_SCHEMA: Final = "missioncore.rellis-ground-qualification-report/v1"
|
||||
GROUND_FAILURE_SCHEMA: Final = "missioncore.goose-ground-qualification-failure-preview/v1"
|
||||
GROUND_REVIEW_SCHEMA: Final = "missioncore.polygon-ground-review/v2"
|
||||
GROUND_REVIEW_FRAME_SCHEMA: Final = "missioncore.polygon-ground-review-frame/v1"
|
||||
GOOSE_REVIEW_PACK_SCHEMA: Final = "missioncore.goose-ground-review-pack/v1"
|
||||
GOOSE_REVIEW_FRAME_SCHEMA: Final = "missioncore.goose-ground-review-frame/v1"
|
||||
RELLIS_REVIEW_PACK_SCHEMA: Final = "missioncore.rellis-ground-review-pack/v1"
|
||||
RELLIS_REVIEW_FRAME_SCHEMA: Final = "missioncore.rellis-ground-review-frame/v1"
|
||||
MAX_QUALIFICATION_ARTIFACT_BYTES: Final = 32 * 1024**2
|
||||
MAX_REVIEW_MANIFEST_BYTES: Final = 8 * 1024**2
|
||||
MAX_REVIEW_FRAME_BYTES: Final = 2 * 1024**2
|
||||
MAX_REVIEW_FRAMES: Final = 2_000
|
||||
MAX_REVIEW_FRAMES: Final = 3_000
|
||||
MAX_REVIEW_POINTS: Final = 20_000
|
||||
COMMIT_PATTERN: Final = re.compile(r"^[a-f0-9]{40}$")
|
||||
GOOSE_FRAME_ID_PATTERN: Final = re.compile(
|
||||
@@ -201,8 +205,8 @@ def build_polygon_router(
|
||||
report = _read_registered_json(
|
||||
store,
|
||||
run,
|
||||
artifact_kind=GROUND_REPORT_ARTIFACT_KIND,
|
||||
expected_schema=GROUND_REPORT_SCHEMA,
|
||||
artifact_kind=(GROUND_REPORT_ARTIFACT_KIND, RELLIS_REPORT_ARTIFACT_KIND),
|
||||
expected_schema=(GROUND_REPORT_SCHEMA, RELLIS_REPORT_SCHEMA),
|
||||
)
|
||||
required = (
|
||||
"identity_sha256",
|
||||
@@ -305,7 +309,7 @@ def build_polygon_router(
|
||||
"ground_iou_delta",
|
||||
)
|
||||
},
|
||||
**_goose_frame_identity(frame["frame_id"]),
|
||||
**_dataset_frame_identity(frame),
|
||||
}
|
||||
for frame in manifest["frames"]
|
||||
],
|
||||
@@ -348,7 +352,11 @@ def build_polygon_router(
|
||||
) from exc
|
||||
point_count = int(frame["point_count"])
|
||||
if (
|
||||
schema != GOOSE_REVIEW_FRAME_SCHEMA
|
||||
schema
|
||||
not in {
|
||||
GOOSE_REVIEW_FRAME_SCHEMA,
|
||||
RELLIS_REVIEW_FRAME_SCHEMA,
|
||||
}
|
||||
or stored_frame_id != frame_id
|
||||
or source_point_count != frame["source_point_count"]
|
||||
or xyz_cm.dtype != np.dtype("<i2")
|
||||
@@ -562,11 +570,17 @@ def _read_registered_json(
|
||||
store: QualificationRunStore,
|
||||
run: QualificationRun,
|
||||
*,
|
||||
artifact_kind: str,
|
||||
expected_schema: str,
|
||||
artifact_kind: str | tuple[str, ...],
|
||||
expected_schema: str | tuple[str, ...],
|
||||
frame_id: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
candidates = [artifact for artifact in run.artifacts if artifact.kind == artifact_kind]
|
||||
artifact_kinds = (artifact_kind,) if isinstance(artifact_kind, str) else artifact_kind
|
||||
expected_schemas = (
|
||||
(expected_schema,) if isinstance(expected_schema, str) else expected_schema
|
||||
)
|
||||
candidates = [
|
||||
artifact for artifact in run.artifacts if artifact.kind in artifact_kinds
|
||||
]
|
||||
if frame_id is not None:
|
||||
candidates = [
|
||||
artifact for artifact in candidates if Path(artifact.relative_path).stem == frame_id
|
||||
@@ -611,7 +625,7 @@ def _read_registered_json(
|
||||
status_code=500,
|
||||
detail="Квалификационный артефакт не является допустимым JSON.",
|
||||
) from exc
|
||||
if not isinstance(value, dict) or value.get("schema_version") != expected_schema:
|
||||
if not isinstance(value, dict) or value.get("schema_version") not in expected_schemas:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Квалификационный артефакт имеет неизвестную схему.",
|
||||
@@ -676,7 +690,8 @@ def _read_ground_review_manifest(
|
||||
safety = manifest.get("safety") if isinstance(manifest, dict) else None
|
||||
if (
|
||||
not isinstance(manifest, dict)
|
||||
or manifest.get("schema_version") != GOOSE_REVIEW_PACK_SCHEMA
|
||||
or manifest.get("schema_version")
|
||||
not in {GOOSE_REVIEW_PACK_SCHEMA, RELLIS_REVIEW_PACK_SCHEMA}
|
||||
or manifest.get("source_run_id") != run_id
|
||||
or not isinstance(manifest.get("identity_sha256"), str)
|
||||
or not re.fullmatch(r"[a-f0-9]{64}", manifest["identity_sha256"])
|
||||
@@ -725,7 +740,27 @@ def _read_ground_review_manifest(
|
||||
return pack_root, manifest
|
||||
|
||||
|
||||
def _goose_frame_identity(frame_id: str) -> dict[str, str | int]:
|
||||
def _dataset_frame_identity(frame: dict[str, Any]) -> dict[str, str | int | None]:
|
||||
frame_id = frame["frame_id"]
|
||||
explicit_sequence = frame.get("dataset_sequence_id")
|
||||
explicit_number = frame.get("dataset_frame_number")
|
||||
if explicit_sequence is not None or explicit_number is not None:
|
||||
if (
|
||||
not isinstance(explicit_sequence, str)
|
||||
or re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_-]{0,95}", explicit_sequence)
|
||||
is None
|
||||
or not isinstance(explicit_number, int)
|
||||
or explicit_number < 0
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Идентичность dataset-кадра нарушает контракт.",
|
||||
)
|
||||
return {
|
||||
"dataset_sequence_id": explicit_sequence,
|
||||
"dataset_frame_number": explicit_number,
|
||||
"sensor_timestamp_ns": None,
|
||||
}
|
||||
match = GOOSE_FRAME_ID_PATTERN.fullmatch(frame_id)
|
||||
if match is None:
|
||||
raise HTTPException(
|
||||
|
||||
Reference in New Issue
Block a user