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

New models UI #5635

Merged
merged 37 commits into from
Jan 30, 2023
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ecf84c4
added base functionality
klakhov Nov 21, 2022
5f5e60e
added functions to lambda manager
klakhov Nov 25, 2022
7e7160d
added loading to create model page
klakhov Nov 25, 2022
9f91c7a
Merge branch 'develop' into kl/roboflow-ui
klakhov Jan 20, 2023
4472fb1
refactored model creation
klakhov Jan 20, 2023
3cdfbeb
added model deletion
klakhov Jan 22, 2023
2796119
fixed working with cvat-provided models
klakhov Jan 24, 2023
960b83d
added errors, improved model creation
klakhov Jan 24, 2023
fe20654
added classifiers
klakhov Jan 24, 2023
d86c27f
reworked model form
klakhov Jan 24, 2023
1fdbcfc
added card layout, added icons
klakhov Jan 25, 2023
bf0ca7c
fixed clipping styles
klakhov Jan 27, 2023
8fc7726
added onclick on empty preview
klakhov Jan 27, 2023
0586698
fixed large preview
klakhov Jan 27, 2023
4675538
Merge branch 'develop' into kl/roboflow-ui
klakhov Jan 27, 2023
e1d8232
Merge branch 'kl/roboflow-ui' of github.com:opencv/cvat into kl/robof…
klakhov Jan 27, 2023
38c8fa1
added model provider enum
klakhov Jan 27, 2023
ea1ef2b
Fixed preview error
klakhov Jan 27, 2023
c075cf9
revert eslint precommit
klakhov Jan 27, 2023
997d164
fix models empty list
klakhov Jan 27, 2023
ef64b9f
fixed updating of models
klakhov Jan 27, 2023
0aa51df
removed usage of .functions from cvat-ui
klakhov Jan 27, 2023
a697a36
fixed key and route issue
klakhov Jan 27, 2023
ea1f997
added error handling if functions are not present
klakhov Jan 27, 2023
efd8871
get rid of big/small icons
klakhov Jan 27, 2023
9fb1915
revert rotate icon
klakhov Jan 27, 2023
bc56d45
added server icons
klakhov Jan 27, 2023
7b04383
updated headers, package versions, changelog
klakhov Jan 27, 2023
52eed99
Applied comments
klakhov Jan 30, 2023
7b3478a
fixed delete method
klakhov Jan 30, 2023
14869b7
added filter function for queries
klakhov Jan 30, 2023
dd3471f
fixed convert mask to poly if model returns poly
klakhov Jan 30, 2023
14d0bb1
added models sorting by created date
klakhov Jan 30, 2023
c2c9e63
removed menu from built-in models
klakhov Jan 30, 2023
fa082fa
removed console log, extended error message length
klakhov Jan 30, 2023
147cad7
add handling for requests
klakhov Jan 30, 2023
fb90bc4
Merge branch 'develop' into kl/roboflow-ui
klakhov Jan 30, 2023
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Windows Installation Instructions adjusted to work around <https://github.com/nuclio/nuclio/issues/1821>
- The contour detection function for semantic segmentation (<https://github.com/opencv/cvat/pull/4665>)
- Delete newline character when generating a webhook signature (<https://github.com/opencv/cvat/pull/5622>)
- DL models UI (<https://github.com/opencv/cvat/pull/5635>)

### Deprecated
- TDB
Expand Down
2 changes: 1 addition & 1 deletion cvat-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-core",
"version": "8.0.0",
"version": "8.1.0",
"description": "Part of Computer Vision Tool which presents an interface for client-side integration",
"main": "src/api.ts",
"scripts": {
Expand Down
3 changes: 2 additions & 1 deletion 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 CVAT.ai Corporation
// Copyright (C) 2022-2023 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

Expand Down Expand Up @@ -37,6 +37,7 @@ export default function implementAPI(cvat) {
cvat.lambda.cancel.implementation = lambdaManager.cancel.bind(lambdaManager);
cvat.lambda.listen.implementation = lambdaManager.listen.bind(lambdaManager);
cvat.lambda.requests.implementation = lambdaManager.requests.bind(lambdaManager);
cvat.lambda.providers.implementation = lambdaManager.providers.bind(lambdaManager);

cvat.server.about.implementation = async () => {
const result = await serverProxy.server.about();
Expand Down
12 changes: 8 additions & 4 deletions cvat-core/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,18 +190,22 @@ function build() {
const result = await PluginRegistry.apiWrapper(cvat.lambda.call, task, model, args);
return result;
},
async cancel(requestID) {
const result = await PluginRegistry.apiWrapper(cvat.lambda.cancel, requestID);
async cancel(requestID, functionID) {
const result = await PluginRegistry.apiWrapper(cvat.lambda.cancel, requestID, functionID);
return result;
},
async listen(requestID, onChange) {
const result = await PluginRegistry.apiWrapper(cvat.lambda.listen, requestID, onChange);
async listen(requestID, functionID, onChange) {
const result = await PluginRegistry.apiWrapper(cvat.lambda.listen, requestID, functionID, onChange);
return result;
},
async requests() {
const result = await PluginRegistry.apiWrapper(cvat.lambda.requests);
return result;
},
async providers() {
const result = await PluginRegistry.apiWrapper(cvat.lambda.providers);
return result;
},
},
logger: loggerStorage,
config: {
Expand Down
8 changes: 7 additions & 1 deletion cvat-core/src/enums.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2019-2022 Intel Corporation
// Copyright (C) 2022 CVAT.ai Corporation
// Copyright (C) 2022-2023 CVAT.ai Corporation
//
// SPDX-License-Identifier = MIT

Expand Down Expand Up @@ -136,6 +136,12 @@ export enum ModelType {
DETECTOR = 'detector',
INTERACTOR = 'interactor',
TRACKER = 'tracker',
CLASSIFIER = 'classifier',
REID = 'reid',
}

export enum ModelProviders {
CVAT = 'cvat',
}

export const colors = [
Expand Down
91 changes: 76 additions & 15 deletions cvat-core/src/lambda-manager.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
// Copyright (C) 2019-2022 Intel Corporation
// Copyright (C) 2022 CVAT.ai Corporation
// Copyright (C) 2022-2023 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

import serverProxy from './server-proxy';
import { ArgumentError } from './exceptions';
import MLModel from './ml-model';
import { RQStatus } from './enums';
import { ModelProviders, RQStatus } from './enums';

export interface ModelProvider {
name: string;
icon: string;
attributes: Record<string, string>;
}

class LambdaManager {
private listening: any;
Expand All @@ -18,18 +24,26 @@ class LambdaManager {
}

async list(): Promise<MLModel[]> {
if (Array.isArray(this.cachedList)) {
return [...this.cachedList];
}

const result = await serverProxy.lambda.list();
let lambdaFunctions = [];
let functions = [];
try {
// lambda.list returns error if list is empty, but we should work with models anyway
lambdaFunctions = await serverProxy.lambda.list();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. why we have error in case with empty list? Do you mean 404?
  2. it ignores all the errors, not sure it is correct
  3. better to handle on server-proxy because it looks like server-specific thing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we have 503(service unavailable) error if nuclio is not running. I think we should be able to use functions without it.
And 404 for functions if there is no such thing on server. I've moved handling to serverProxy

// eslint-disable-next-line no-empty
} catch (error) {}

try {
functions = await serverProxy.functions.list();
// eslint-disable-next-line no-empty
} catch (error) {}

const result = [...lambdaFunctions, ...functions];
const models = [];

for (const model of result) {
models.push(
new MLModel({
...model,
type: model.kind,
}),
);
}
Expand Down Expand Up @@ -59,7 +73,12 @@ class LambdaManager {
function: model.id,
};

const result = await serverProxy.lambda.run(body);
let result;
if (model.provider === ModelProviders.CVAT) {
result = await serverProxy.lambda.run(body);
} else {
result = await serverProxy.functions.run(body);
}
return result.id;
}

Expand All @@ -73,32 +92,59 @@ class LambdaManager {
task: taskID,
};

const result = await serverProxy.lambda.call(model.id, body);
let result;
if (model.provider === ModelProviders.CVAT) {
result = await serverProxy.lambda.call(model.id, body);
} else {
result = await serverProxy.functions.call(model.id, body);
}
return result;
}

async requests() {
const result = await serverProxy.lambda.requests();
const lambdaRequests = await serverProxy.lambda.requests();
const functionsRequests = await serverProxy.functions.requests();
const result = [...lambdaRequests, ...functionsRequests];
return result.filter((request) => ['queued', 'started'].includes(request.status));
}

async cancel(requestID): Promise<void> {
async cancel(requestID, functionID): Promise<void> {
if (typeof requestID !== 'string') {
throw new ArgumentError(`Request id argument is required to be a string. But got ${requestID}`);
}
const model = this.cachedList.find((_model) => _model.id === functionID);
if (!model) {
throw new ArgumentError('Incorrect Function Id provided');
}

if (this.listening[requestID]) {
clearTimeout(this.listening[requestID].timeout);
delete this.listening[requestID];
}
await serverProxy.lambda.cancel(requestID);

const { provider } = model;
if (provider === ModelProviders.CVAT) {
await serverProxy.lambda.cancel(requestID);
} else {
await serverProxy.functions.cancel(requestID);
}
}

async listen(requestID, onUpdate): Promise<void> {
async listen(requestID, functionID, onUpdate): Promise<void> {
const model = this.cachedList.find((_model) => _model.id === functionID);
if (!model) {
throw new ArgumentError('Incorrect Function Id provided');
}
const { provider } = model;
const timeoutCallback = async (): Promise<void> => {
try {
this.listening[requestID].timeout = null;
const response = await serverProxy.lambda.status(requestID);
let response = null;
if (provider === ModelProviders.CVAT) {
response = await serverProxy.lambda.status(requestID);
} else {
response = await serverProxy.functions.status(requestID);
}
klakhov marked this conversation as resolved.
Show resolved Hide resolved

if (response.status === RQStatus.QUEUED || response.status === RQStatus.STARTED) {
onUpdate(response.status, response.progress || 0);
Expand All @@ -123,9 +169,24 @@ class LambdaManager {

this.listening[requestID] = {
onUpdate,
functionID,
timeout: setTimeout(timeoutCallback, 2000),
};
}

async providers(): Promise<ModelProvider[]> {
const providersData: Record<string, Record<string, string>> = await serverProxy.functions.providers();
const providers = Object.entries(providersData).map(([provider, attributes]) => {
const { icon } = attributes;
delete attributes.icon;
return {
name: provider,
icon,
attributes,
};
});
return providers;
}
}

export default new LambdaManager();
Loading