feat: qualify complete RELLIS ground dataset
This commit is contained in:
@@ -12,7 +12,8 @@ export type DatasetSourceAdmissionStatus =
|
||||
| "verifying"
|
||||
| "verified"
|
||||
| "frame-ready"
|
||||
| "smoke-ready";
|
||||
| "smoke-ready"
|
||||
| "dataset-ready";
|
||||
|
||||
export interface DatasetSource {
|
||||
sourceId: string;
|
||||
@@ -308,6 +309,7 @@ export function parseDatasetGatewayCatalog(
|
||||
&& admissionStatus !== "verified"
|
||||
&& admissionStatus !== "frame-ready"
|
||||
&& admissionStatus !== "smoke-ready"
|
||||
&& admissionStatus !== "dataset-ready"
|
||||
) {
|
||||
throw new DatasetGatewayContractError("source admission status неизвестен");
|
||||
}
|
||||
|
||||
@@ -42,7 +42,10 @@ export interface GroundQualification {
|
||||
checks: QualificationCheck[];
|
||||
worstFrames: QualificationWorstFrame[];
|
||||
decision: {
|
||||
status: "shadow-candidate" | "qualification-rejected";
|
||||
status:
|
||||
| "shadow-candidate"
|
||||
| "cross-dataset-qualified"
|
||||
| "qualification-rejected";
|
||||
passed: boolean;
|
||||
promotedToNavigationOrSafety: false;
|
||||
reason: string;
|
||||
@@ -75,7 +78,7 @@ export interface GroundReviewFrameSummary {
|
||||
frameId: string;
|
||||
datasetSequenceId: string;
|
||||
datasetFrameNumber: number;
|
||||
sensorTimestampNs: string;
|
||||
sensorTimestampNs: string | null;
|
||||
sourcePointCount: number;
|
||||
pointCount: number;
|
||||
current: GroundReviewFrameMetrics;
|
||||
@@ -264,7 +267,11 @@ export function decodeGroundQualification(payload: unknown): GroundQualification
|
||||
);
|
||||
const decision = record(source.decision, "decision");
|
||||
const status = text(decision.status, "decision.status", 64);
|
||||
if (status !== "shadow-candidate" && status !== "qualification-rejected") {
|
||||
if (
|
||||
status !== "shadow-candidate"
|
||||
&& status !== "cross-dataset-qualified"
|
||||
&& status !== "qualification-rejected"
|
||||
) {
|
||||
throw new GroundQualificationContractError("Решение квалификации неизвестно.");
|
||||
}
|
||||
if (decision.promoted_to_navigation_or_safety !== false) {
|
||||
@@ -384,7 +391,11 @@ export function decodeGroundReview(payload: unknown): GroundReview {
|
||||
throw new GroundQualificationContractError("Неизвестная схема покадрового просмотра.");
|
||||
}
|
||||
const frameCount = integer(source.frame_count, "frame_count", 1);
|
||||
const frames = array(source.frames, "frames", 2_000).map(
|
||||
const sourceId = text(source.source_id, "source_id");
|
||||
if (sourceId !== "goose-3d/v2025-08-22" && sourceId !== "rellis-3d/v1.1") {
|
||||
throw new GroundQualificationContractError("Источник review неизвестен.");
|
||||
}
|
||||
const frames = array(source.frames, "frames", 3_000).map(
|
||||
(value, index): GroundReviewFrameSummary => {
|
||||
const frame = record(value, `frames[${index}]`);
|
||||
const sequence = integer(frame.sequence, `frames[${index}].sequence`);
|
||||
@@ -392,7 +403,6 @@ export function decodeGroundReview(payload: unknown): GroundReview {
|
||||
throw new GroundQualificationContractError("Кадры просмотра идут не по порядку.");
|
||||
}
|
||||
const frameId = id(frame.frame_id, `frames[${index}].frame_id`);
|
||||
const frameIdentity = parseGooseFrameId(frameId);
|
||||
const datasetSequenceId = id(
|
||||
frame.dataset_sequence_id,
|
||||
`frames[${index}].dataset_sequence_id`,
|
||||
@@ -401,18 +411,30 @@ export function decodeGroundReview(payload: unknown): GroundReview {
|
||||
frame.dataset_frame_number,
|
||||
`frames[${index}].dataset_frame_number`,
|
||||
);
|
||||
const sensorTimestampNs = text(
|
||||
frame.sensor_timestamp_ns,
|
||||
`frames[${index}].sensor_timestamp_ns`,
|
||||
20,
|
||||
);
|
||||
if (
|
||||
datasetSequenceId !== frameIdentity.datasetSequenceId
|
||||
|| datasetFrameNumber !== frameIdentity.datasetFrameNumber
|
||||
|| sensorTimestampNs !== frameIdentity.sensorTimestampNs
|
||||
let sensorTimestampNs: string | null = null;
|
||||
if (sourceId === "goose-3d/v2025-08-22") {
|
||||
const frameIdentity = parseGooseFrameId(frameId);
|
||||
sensorTimestampNs = text(
|
||||
frame.sensor_timestamp_ns,
|
||||
`frames[${index}].sensor_timestamp_ns`,
|
||||
20,
|
||||
);
|
||||
if (
|
||||
datasetSequenceId !== frameIdentity.datasetSequenceId
|
||||
|| datasetFrameNumber !== frameIdentity.datasetFrameNumber
|
||||
|| sensorTimestampNs !== frameIdentity.sensorTimestampNs
|
||||
) {
|
||||
throw new GroundQualificationContractError(
|
||||
`frames[${index}] противоречит идентичности GOOSE-кадра.`,
|
||||
);
|
||||
}
|
||||
} else if (
|
||||
frame.sensor_timestamp_ns !== null
|
||||
|| !/^rellis-0000[0-4]-[0-9]{6}$/.test(frameId)
|
||||
|| frameId !== `rellis-${datasetSequenceId}-${String(datasetFrameNumber).padStart(6, "0")}`
|
||||
) {
|
||||
throw new GroundQualificationContractError(
|
||||
`frames[${index}] противоречит идентичности GOOSE-кадра.`,
|
||||
`frames[${index}] противоречит идентичности RELLIS-кадра.`,
|
||||
);
|
||||
}
|
||||
return {
|
||||
@@ -457,7 +479,7 @@ export function decodeGroundReview(payload: unknown): GroundReview {
|
||||
return {
|
||||
runId: id(source.run_id, "run_id"),
|
||||
identitySha256,
|
||||
sourceId: text(source.source_id, "source_id"),
|
||||
sourceId,
|
||||
frameCount,
|
||||
previewPoints: integer(source.preview_points, "preview_points", 1),
|
||||
frames,
|
||||
|
||||
Reference in New Issue
Block a user