Skip to content

Commit

Permalink
Migrate quality UI changes (#7441)
Browse files Browse the repository at this point in the history
  • Loading branch information
klakhov committed Feb 15, 2024
1 parent e8384f8 commit 11cec4c
Show file tree
Hide file tree
Showing 34 changed files with 1,278 additions and 1,389 deletions.
4 changes: 4 additions & 0 deletions changelog.d/20240206_125854_klakhov_quality_bugfixes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
### Fixed

- On quality page for a task, only the first page with jobs has quality report metrics
(<https://github.com/opencv/cvat/pull/7441>)
36 changes: 3 additions & 33 deletions cvat-core/src/analytics-report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,11 @@
//
// SPDX-License-Identifier: MIT

import {
SerializedAnalyticsEntry, SerializedAnalyticsReport, SerializedDataEntry, SerializedTransformationEntry,
} from './server-response-types';
import { ArgumentError } from './exceptions';

export interface SerializedDataEntry {
date?: string;
value?: number | Record<string, number>
}

export interface SerializedTransformBinaryOp {
left: string;
operator: string;
right: string;
}

export interface SerializedTransformationEntry {
name: string;
binary?: SerializedTransformBinaryOp;
}

export interface SerializedAnalyticsEntry {
name?: string;
title?: string;
description?: string;
granularity?: string;
default_view?: string;
data_series?: Record<string, SerializedDataEntry[]>;
transformations?: SerializedTransformationEntry[];
}

export interface SerializedAnalyticsReport {
id?: number;
target?: string;
created_date?: string;
statistics?: SerializedAnalyticsEntry[];
}

export enum AnalyticsReportTarget {
JOB = 'job',
TASK = 'task',
Expand Down
85 changes: 39 additions & 46 deletions cvat-core/src/api-implementation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2019-2022 Intel Corporation
// Copyright (C) 2022-2023 CVAT.ai Corporation
// Copyright (C) 2022-2024 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

Expand All @@ -13,10 +13,12 @@ import {
isBoolean,
isInteger,
isString,
isPageSize,
checkFilter,
checkExclusiveFields,
checkObjectType,
filterFieldsToSnakeCase,
fieldsToSnakeCase,
} from './common';

import User from './user';
Expand Down Expand Up @@ -402,34 +404,36 @@ export default function implementAPI(cvat: CVATCore): CVATCore {
});

implementationMixin(cvat.analytics.quality.reports, async (filter) => {
let updatedParams: Record<string, string> = {};
if ('taskId' in filter) {
updatedParams = {
task_id: filter.taskId,
sort: '-created_date',
target: filter.target,
};
}
if ('jobId' in filter) {
updatedParams = {
job_id: filter.jobId,
sort: '-created_date',
target: filter.target,
};
}
const reportsData = await serverProxy.analytics.quality.reports(updatedParams);
checkFilter(filter, {
page: isInteger,
pageSize: isPageSize,
parentID: isInteger,
projectID: isInteger,
taskID: isInteger,
jobID: isInteger,
target: isString,
filter: isString,
search: isString,
sort: isString,
});

const params = fieldsToSnakeCase({ ...filter, sort: '-created_date' });

return reportsData.map((report) => new QualityReport({ ...report }));
const reportsData = await serverProxy.analytics.quality.reports(params);
const reports = Object.assign(
reportsData.map((report) => new QualityReport({ ...report })),
{ count: reportsData.count },
);
return reports;
});
implementationMixin(cvat.analytics.quality.conflicts, async (filter) => {
let updatedParams: Record<string, string> = {};
if ('reportId' in filter) {
updatedParams = {
report_id: filter.reportId,
};
}
checkFilter(filter, {
reportID: isInteger,
});

const params = fieldsToSnakeCase(filter);

const conflictsData = await serverProxy.analytics.quality.conflicts(updatedParams);
const conflictsData = await serverProxy.analytics.quality.conflicts(params);
const conflicts = conflictsData.map((conflict) => new QualityConflict({ ...conflict }));
const frames = Array.from(new Set(conflicts.map((conflict) => conflict.frame)))
.sort((a, b) => a - b);
Expand Down Expand Up @@ -498,8 +502,14 @@ export default function implementAPI(cvat: CVATCore): CVATCore {

return mergedConflicts;
});
implementationMixin(cvat.analytics.quality.settings.get, async (taskID: number) => {
const settings = await serverProxy.analytics.quality.settings.get(taskID);
implementationMixin(cvat.analytics.quality.settings.get, async (filter) => {
checkFilter(filter, {
taskID: isInteger,
});

const params = fieldsToSnakeCase(filter);

const settings = await serverProxy.analytics.quality.settings.get(params);
return new QualitySettings({ ...settings });
});
implementationMixin(cvat.analytics.performance.reports, async (filter) => {
Expand All @@ -513,25 +523,8 @@ export default function implementAPI(cvat: CVATCore): CVATCore {

checkExclusiveFields(filter, ['jobID', 'taskID', 'projectID'], ['startDate', 'endDate']);

const updatedParams: Record<string, string> = {};

if ('taskID' in filter) {
updatedParams.task_id = filter.taskID;
}
if ('jobID' in filter) {
updatedParams.job_id = filter.jobID;
}
if ('projectID' in filter) {
updatedParams.project_id = filter.projectID;
}
if ('startDate' in filter) {
updatedParams.start_date = filter.startDate;
}
if ('endDate' in filter) {
updatedParams.end_date = filter.endDate;
}

const reportData = await serverProxy.analytics.performance.reports(updatedParams);
const params = fieldsToSnakeCase(filter);
const reportData = await serverProxy.analytics.performance.reports(params);
return new AnalyticsReport(reportData);
});
implementationMixin(cvat.frames.getMeta, async (type, id) => {
Expand Down
8 changes: 4 additions & 4 deletions cvat-core/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,17 +350,17 @@ function build(): CVATCore {
},
},
quality: {
async reports(filter: any) {
async reports(filter = {}) {
const result = await PluginRegistry.apiWrapper(cvat.analytics.quality.reports, filter);
return result;
},
async conflicts(filter: any) {
async conflicts(filter = {}) {
const result = await PluginRegistry.apiWrapper(cvat.analytics.quality.conflicts, filter);
return result;
},
settings: {
async get(taskID: number) {
const result = await PluginRegistry.apiWrapper(cvat.analytics.quality.settings.get, taskID);
async get(filter = {}) {
const result = await PluginRegistry.apiWrapper(cvat.analytics.quality.settings.get, filter);
return result;
},
},
Expand Down
15 changes: 14 additions & 1 deletion cvat-core/src/common.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright (C) 2019-2022 Intel Corporation
// Copyright (C) 2022-2023s CVAT.ai Corporation
// Copyright (C) 2022-2024 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

import { snakeCase } from 'lodash';
import { ArgumentError } from './exceptions';

export function isBoolean(value): boolean {
Expand Down Expand Up @@ -145,3 +146,15 @@ export function filterFieldsToSnakeCase(filter: Record<string, string>, keysToSn
export function isResourceURL(url: string): boolean {
return /\/([0-9]+)$/.test(url);
}

export function isPageSize(value: number | 'all'): boolean {
return isInteger(value) || value === 'all';
}

export function fieldsToSnakeCase(params: Record<string, any>): Record<string, any> {
const result = {};
for (const [k, v] of Object.entries(params)) {
result[snakeCase(k)] = v;
}
return result;
}
17 changes: 13 additions & 4 deletions cvat-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
//
// SPDX-License-Identifier: MIT

import {
AnalyticsReportFilter, QualityConflictsFilter, QualityReportsFilter, QualitySettingsFilter,
} from './server-response-types';
import PluginRegistry from './plugins';
import serverProxy from './server-proxy';
import lambdaManager from './lambda-manager';
Expand All @@ -24,6 +27,10 @@ import { FrameData } from './frames';
import CloudStorage from './cloud-storage';
import Organization, { Invitation } from './organization';
import Webhook from './webhook';
import QualityReport from './quality-report';
import QualityConflict from './quality-conflict';
import QualitySettings from './quality-settings';
import AnalyticsReport from './analytics-report';
import AnnotationGuide from './guide';
import BaseSingleFrameAction, { listActions, registerAction, runActions } from './annotations-actions';
import {
Expand Down Expand Up @@ -126,12 +133,14 @@ export default interface CVATCore {
};
analytics: {
quality: {
reports: any;
conflicts: any;
settings: any;
reports: (filter: QualityReportsFilter) => Promise<PaginatedResource<QualityReport>>;
conflicts: (filter: QualityConflictsFilter) => Promise<QualityConflict[]>;
settings: {
get: (filter: QualitySettingsFilter) => Promise<QualitySettings>;
};
};
performance: {
reports: any;
reports: (filter: AnalyticsReportFilter) => Promise<AnalyticsReport>;
};
};
frames: {
Expand Down
20 changes: 1 addition & 19 deletions cvat-core/src/quality-conflict.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: MIT

import { SerializedAnnotationConflictData, SerializedQualityConflictData } from './server-response-types';
import { ObjectType } from './enums';

export enum QualityConflictType {
Expand All @@ -15,25 +16,6 @@ export enum ConflictSeverity {
WARNING = 'warning',
}

export interface SerializedQualityConflictData {
id?: number;
frame?: number;
type?: string;
annotation_ids?: SerializedAnnotationConflictData[];
data?: string;
severity?: string;
description?: string;
}

export interface SerializedAnnotationConflictData {
job_id?: number;
obj_id?: number;
type?: ObjectType;
shape_type?: string | null;
conflict_type?: string;
severity?: string;
}

export class AnnotationConflict {
#jobID: number;
#serverID: number;
Expand Down
54 changes: 13 additions & 41 deletions cvat-core/src/quality-report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,7 @@
//
// SPDX-License-Identifier: MIT

export interface SerializedQualityReportData {
id?: number;
parent_id?: number;
task_id?: number;
job_id?: number;
target: string;
created_date?: string;
gt_last_updated?: string;
summary?: {
frame_count: number,
frame_share: number,
conflict_count: number,
valid_count: number,
ds_count: number,
gt_count: number,
error_count: number,
warning_count: number,
conflicts_by_type: {
extra_annotation: number,
missing_annotation: number,
mismatching_label: number,
low_overlap: number,
mismatching_direction: number,
mismatching_attributes: number,
mismatching_groups: number,
covered_annotation: number,
}
};
}
import { SerializedQualityReportData } from './server-response-types';

export interface QualitySummary {
frameCount: number;
Expand Down Expand Up @@ -58,19 +30,19 @@ export interface QualitySummary {

export default class QualityReport {
#id: number;
#parentId: number;
#taskId: number;
#jobId: number;
#parentID: number;
#taskID: number;
#jobID: number;
#target: string;
#createdDate: string;
#gtLastUpdated: string;
#summary: Partial<SerializedQualityReportData['summary']>;

constructor(initialData: SerializedQualityReportData) {
this.#id = initialData.id;
this.#parentId = initialData.parent_id;
this.#taskId = initialData.task_id;
this.#jobId = initialData.job_id;
this.#parentID = initialData.parent_id;
this.#taskID = initialData.task_id;
this.#jobID = initialData.job_id;
this.#target = initialData.target;
this.#gtLastUpdated = initialData.gt_last_updated;
this.#createdDate = initialData.created_date;
Expand All @@ -81,16 +53,16 @@ export default class QualityReport {
return this.#id;
}

get parentId(): number {
return this.#parentId;
get parentID(): number {
return this.#parentID;
}

get taskId(): number {
return this.#taskId;
get taskID(): number {
return this.#taskID;
}

get jobId(): number {
return this.#jobId;
get jobID(): number {
return this.#jobID;
}

get target(): string {
Expand Down
Loading

0 comments on commit 11cec4c

Please sign in to comment.