export interface Detection {
|
class_id: number;
|
class_name: string;
|
confidence: number;
|
bbox_xyxy: number[];
|
}
|
|
export interface DetectionImage {
|
file: string;
|
annotated_file: string;
|
width: number;
|
height: number;
|
detections: Detection[];
|
}
|
|
export interface DetectionRun {
|
detection_count: number;
|
processed_images: number;
|
elapsed_seconds: number;
|
device: string;
|
model: string;
|
confidence: number;
|
input_dir: string;
|
notes: string[];
|
}
|
|
export interface TrajectoryEvent {
|
event_id: string;
|
event_type: string;
|
track_ids: string[];
|
start_time: string;
|
end_time: string;
|
duration_seconds: number;
|
}
|
|
export interface TrajectoryRun {
|
case_count: number;
|
track_count: number;
|
event_count: number;
|
dropped_duplicate_observations: number;
|
elapsed_seconds: number;
|
device: string;
|
input: string;
|
thresholds_by_case: Record<string, Record<string, number>>;
|
}
|
|
export interface TrajectorySummary {
|
track_id: string;
|
entity_type: string;
|
point_count: string;
|
distance_m: string;
|
average_speed_mps: string;
|
behavior_labels: string;
|
}
|
|
export const artifactUrl = (path: string) => `/${path.replace(/\\/g, "/").split("/").map(encodeURIComponent).join("/")}`;
|
|
async function getJson<T>(path: string): Promise<T> {
|
const response = await fetch(artifactUrl(path), { cache: "no-store" });
|
if (!response.ok) throw new Error(`无法读取 ${path} (${response.status})`);
|
return response.json() as Promise<T>;
|
}
|
|
async function getText(path: string): Promise<string> {
|
const response = await fetch(artifactUrl(path), { cache: "no-store" });
|
if (!response.ok) throw new Error(`无法读取 ${path} (${response.status})`);
|
return response.text();
|
}
|
|
function parseCsv(text: string): TrajectorySummary[] {
|
const lines = text.trim().split(/\r?\n/);
|
const headers = lines.shift()?.replace(/^\uFEFF/, "").split(",") ?? [];
|
return lines.filter(Boolean).map((line) => {
|
const values = line.split(",");
|
return Object.fromEntries(headers.map((header, index) => [header, values[index] ?? ""])) as unknown as TrajectorySummary;
|
});
|
}
|
|
export async function loadDetectionArtifacts() {
|
const [run, payload] = await Promise.all([
|
getJson<DetectionRun>("shared/outputs/01-object-detection/run_metadata.json"),
|
getJson<{ images: DetectionImage[] }>("shared/outputs/01-object-detection/detections.json")
|
]);
|
return { run, images: payload.images };
|
}
|
|
export async function loadTrajectoryArtifacts() {
|
const [run, difficultEvents, difficultSummary, normalSummary] = await Promise.all([
|
getJson<TrajectoryRun>("shared/outputs/15-trajectory-analysis/run_metadata.json"),
|
getJson<{ events: TrajectoryEvent[] }>("shared/outputs/15-trajectory-analysis/difficult/events.json"),
|
getText("shared/outputs/15-trajectory-analysis/difficult/trajectory_summary.csv"),
|
getText("shared/outputs/15-trajectory-analysis/normal/trajectory_summary.csv")
|
]);
|
return {
|
run,
|
cases: {
|
difficult: { events: difficultEvents.events, summary: parseCsv(difficultSummary) },
|
normal: { events: [], summary: parseCsv(normalSummary) }
|
}
|
};
|
}
|