Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate quality UI changes #7441

Merged
merged 31 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
77f06b5
draft fix of job list
klakhov Feb 5, 2024
5337022
fixed number representation & conflicts display
klakhov Feb 5, 2024
f115555
A bunch more fixes to job-list
klakhov Feb 5, 2024
e690143
added missing newlines
klakhov Feb 6, 2024
b4dc0ed
removed analytics state
klakhov Feb 6, 2024
33a36ab
moved more refactoring
klakhov Feb 6, 2024
992bfb3
migrated styles
klakhov Feb 6, 2024
18b08cc
applied quality settings refactoring
klakhov Feb 6, 2024
9a051b4
analytics page refactoring
klakhov Feb 6, 2024
e84d0fb
fix getting report
klakhov Feb 6, 2024
24012c3
updated changelog
klakhov Feb 6, 2024
f1f4902
updated versions
klakhov Feb 6, 2024
e0c51c9
Merge branch 'develop' into kl/quality-bugfixes
klakhov Feb 6, 2024
a43cdf9
fixed test
klakhov Feb 6, 2024
ce1e731
Merge branch 'kl/quality-bugfixes' of https://github.com/cvat-ai/cvat…
klakhov Feb 6, 2024
8844536
Merge branch 'develop' into kl/quality-bugfixes
klakhov Feb 9, 2024
41b491d
Merge branch 'develop' into kl/quality-bugfixes
klakhov Feb 12, 2024
a338e5e
fixed changelog
klakhov Feb 12, 2024
d734b19
added analytics filter types to server-proxy
klakhov Feb 12, 2024
ceb7ede
added types for analytics module in cvat-core index
klakhov Feb 12, 2024
a00d478
removed excessive parameter in fieldsToSnakeCase
klakhov Feb 12, 2024
7e48601
fixed count on quality reports
klakhov Feb 12, 2024
2404ff8
fixed index types
klakhov Feb 12, 2024
2490b6d
added camelized filter versions
klakhov Feb 12, 2024
8f037ca
force `ID` in camelization
klakhov Feb 12, 2024
7ef3014
Id to ID across analytics
klakhov Feb 12, 2024
1766675
Merge branch 'develop' into kl/quality-bugfixes
klakhov Feb 14, 2024
db34cb4
fixed license header
klakhov Feb 14, 2024
c470313
fixed analytics tabs hash
klakhov Feb 14, 2024
5cc875e
rewritten quality component with state/reducer
klakhov Feb 14, 2024
8f608e2
applied comments
klakhov Feb 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 = {}) {
klakhov marked this conversation as resolved.
Show resolved Hide resolved
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
Loading