Merge branch 'develop' of https://github.com/opencv/cvat into upstream/develop
commit
3236546907
File diff suppressed because one or more lines are too long
@ -1,38 +0,0 @@
|
||||
## [Keras+Tensorflow Mask R-CNN Segmentation](https://github.com/matterport/Mask_RCNN)
|
||||
|
||||
### What is it?
|
||||
- This application allows you automatically to segment many various objects on images.
|
||||
- It's based on Feature Pyramid Network (FPN) and a ResNet101 backbone.
|
||||
|
||||
- It uses a pre-trained model on MS COCO dataset
|
||||
- It supports next classes (use them in "labels" row):
|
||||
```python
|
||||
'BG', 'person', 'bicycle', 'car', 'motorcycle', 'airplane',
|
||||
'bus', 'train', 'truck', 'boat', 'traffic light',
|
||||
'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird',
|
||||
'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear',
|
||||
'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie',
|
||||
'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
|
||||
'kite', 'baseball bat', 'baseball glove', 'skateboard',
|
||||
'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup',
|
||||
'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
|
||||
'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
|
||||
'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed',
|
||||
'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote',
|
||||
'keyboard', 'cell phone', 'microwave', 'oven', 'toaster',
|
||||
'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors',
|
||||
'teddy bear', 'hair drier', 'toothbrush'.
|
||||
```
|
||||
- Component adds "Run Auto Segmentation" button into dashboard.
|
||||
|
||||
### Build docker image
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/auto_segmentation/docker-compose.auto_segmentation.yml build
|
||||
```
|
||||
|
||||
### Run docker container
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/auto_segmentation/docker-compose.auto_segmentation.yml up -d
|
||||
```
|
||||
@ -1,13 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
version: "2.3"
|
||||
|
||||
services:
|
||||
cvat:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
AUTO_SEGMENTATION: "yes"
|
||||
@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
MASK_RCNN_URL=https://github.com/matterport/Mask_RCNN
|
||||
|
||||
cd ${HOME} && \
|
||||
git clone ${MASK_RCNN_URL}.git && \
|
||||
curl -L ${MASK_RCNN_URL}/releases/download/v2.0/mask_rcnn_coco.h5 -o Mask_RCNN/mask_rcnn_coco.h5
|
||||
|
||||
# TODO remove useless files
|
||||
# tensorflow and Keras are installed globally
|
||||
@ -1,41 +0,0 @@
|
||||
## [NVIDIA CUDA Toolkit](https://developer.nvidia.com/cuda-toolkit)
|
||||
|
||||
### Requirements
|
||||
|
||||
* NVIDIA GPU with a compute capability [3.0 - 7.2]
|
||||
* Latest GPU driver
|
||||
|
||||
### Installation
|
||||
|
||||
#### Install the latest driver for your graphics card
|
||||
|
||||
```bash
|
||||
sudo add-apt-repository ppa:graphics-drivers/ppa
|
||||
sudo apt-get update
|
||||
sudo apt-cache search nvidia-* # find latest nvidia driver
|
||||
sudo apt-get --no-install-recommends install nvidia-* # install the nvidia driver
|
||||
sudo apt-get --no-install-recommends install mesa-common-dev
|
||||
sudo apt-get --no-install-recommends install freeglut3-dev
|
||||
sudo apt-get --no-install-recommends install nvidia-modprobe
|
||||
```
|
||||
|
||||
#### Reboot your PC and verify installation by `nvidia-smi` command.
|
||||
|
||||
#### Install [Nvidia-Docker](https://github.com/NVIDIA/nvidia-docker)
|
||||
|
||||
Please be sure that installation was successful.
|
||||
```bash
|
||||
docker info | grep 'Runtimes' # output should contains 'nvidia'
|
||||
```
|
||||
|
||||
### Build docker image
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/cuda/docker-compose.cuda.yml build
|
||||
```
|
||||
|
||||
### Run docker container
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/cuda/docker-compose.cuda.yml up -d
|
||||
```
|
||||
@ -1,23 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
version: "2.3"
|
||||
|
||||
services:
|
||||
cvat:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
CUDA_SUPPORT: "yes"
|
||||
runtime: "nvidia"
|
||||
environment:
|
||||
NVIDIA_VISIBLE_DEVICES: all
|
||||
NVIDIA_DRIVER_CAPABILITIES: compute,utility
|
||||
# That environment variable is used by the Nvidia Container Runtime.
|
||||
# The Nvidia Container Runtime parses this as:
|
||||
# :space:: logical OR
|
||||
# ,: Logical AND
|
||||
# https://gitlab.com/nvidia/container-images/cuda/issues/31#note_149432780
|
||||
NVIDIA_REQUIRE_CUDA: "cuda>=10.0 brand=tesla,driver>=384,driver<385 brand=tesla,driver>=410,driver<411"
|
||||
@ -1,38 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
set -e
|
||||
|
||||
NVIDIA_GPGKEY_SUM=d1be581509378368edeec8c1eb2958702feedf3bc3d17011adbf24efacce4ab5 && \
|
||||
NVIDIA_GPGKEY_FPR=ae09fe4bbd223a84b2ccfce3f60f4b3d7fa2af80 && \
|
||||
apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub && \
|
||||
apt-key adv --export --no-emit-version -a $NVIDIA_GPGKEY_FPR | tail -n +5 > cudasign.pub && \
|
||||
echo "$NVIDIA_GPGKEY_SUM cudasign.pub" | sha256sum -c --strict - && rm cudasign.pub && \
|
||||
echo "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64 /" > /etc/apt/sources.list.d/cuda.list && \
|
||||
echo "deb http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1604/x86_64 /" > /etc/apt/sources.list.d/nvidia-ml.list
|
||||
|
||||
CUDA_VERSION=10.0.130
|
||||
NCCL_VERSION=2.5.6
|
||||
CUDNN_VERSION=7.6.5.32
|
||||
CUDA_PKG_VERSION="10-0=$CUDA_VERSION-1"
|
||||
echo 'export PATH=/usr/local/nvidia/bin:/usr/local/cuda/bin:${PATH}' >> ${HOME}/.bashrc
|
||||
echo 'export LD_LIBRARY_PATH=/usr/local/nvidia/lib:/usr/local/nvidia/lib64:${LD_LIBRARY_PATH}' >> ${HOME}/.bashrc
|
||||
|
||||
apt-get update && apt-get install -y --no-install-recommends --allow-unauthenticated \
|
||||
cuda-cudart-$CUDA_PKG_VERSION \
|
||||
cuda-compat-10-0 \
|
||||
cuda-libraries-$CUDA_PKG_VERSION \
|
||||
cuda-nvtx-$CUDA_PKG_VERSION \
|
||||
libnccl2=$NCCL_VERSION-1+cuda10.0 \
|
||||
libcudnn7=$CUDNN_VERSION-1+cuda10.0 && \
|
||||
ln -s cuda-10.0 /usr/local/cuda && \
|
||||
apt-mark hold libnccl2 libcudnn7 && \
|
||||
rm -rf /var/lib/apt/lists/* \
|
||||
/etc/apt/sources.list.d/nvidia-ml.list /etc/apt/sources.list.d/cuda.list
|
||||
|
||||
python3 -m pip uninstall -y tensorflow
|
||||
python3 -m pip install --no-cache-dir tensorflow-gpu==1.15.2
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
## [Intel OpenVINO toolkit](https://software.intel.com/en-us/openvino-toolkit)
|
||||
|
||||
### Requirements
|
||||
|
||||
* Intel Core with 6th generation and higher or Intel Xeon CPUs.
|
||||
|
||||
### Preparation
|
||||
|
||||
- Download the latest [OpenVINO toolkit](https://software.intel.com/en-us/openvino-toolkit) .tgz installer
|
||||
(offline or online) for Ubuntu platforms. Note that OpenVINO does not maintain forward compatability between
|
||||
Intermediate Representations (IRs), so the version of OpenVINO in CVAT and the version used to translate the
|
||||
models needs to be the same.
|
||||
- Put downloaded file into ```cvat/components/openvino```.
|
||||
- Accept EULA in the `cvat/components/openvino/eula.cfg` file.
|
||||
|
||||
### Build docker image
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/openvino/docker-compose.openvino.yml build
|
||||
```
|
||||
|
||||
### Run docker container
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/openvino/docker-compose.openvino.yml up -d
|
||||
```
|
||||
|
||||
You should be able to login and see the web interface for CVAT now, complete with the new "Model Manager" button.
|
||||
|
||||
### OpenVINO Models
|
||||
|
||||
Clone the [Open Model Zoo](https://github.com/opencv/open_model_zoo). `$ git clone https://github.com/opencv/open_model_zoo.git`
|
||||
|
||||
Install the appropriate libraries. Currently that command would be `$ pip install -r open_model_zoo/tools/downloader/requirements.in`
|
||||
|
||||
Download the models using `downloader.py` file in `open_model_zoo/tools/downloader/`.
|
||||
The `--name` command can be used to specify specific models.
|
||||
The `--print_all` command can print all the available models.
|
||||
Specific models that are already integrated into Cvat can be found [here](https://github.com/opencv/cvat/tree/develop/utils/open_model_zoo).
|
||||
|
||||
From the web user interface in CVAT, upload the models using the model manager.
|
||||
You'll need to include the xml and bin file from the model downloader.
|
||||
You'll need to include the python and JSON files from scratch or by using the ones in the CVAT libary.
|
||||
See [here](https://github.com/opencv/cvat/tree/develop/cvat/apps/auto_annotation) for instructions for creating custom
|
||||
python and JSON files.
|
||||
@ -1,13 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
version: "2.3"
|
||||
|
||||
services:
|
||||
cvat:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
OPENVINO_TOOLKIT: "yes"
|
||||
@ -1,3 +0,0 @@
|
||||
# Accept actual EULA from openvino installation archive. Valid values are: {accept, decline}
|
||||
ACCEPT_EULA=accept
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
set -e
|
||||
|
||||
if [[ `lscpu | grep -o "GenuineIntel"` != "GenuineIntel" ]]; then
|
||||
echo "OpenVINO supports only Intel CPUs"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ `lscpu | grep -o "sse4" | head -1` != "sse4" ]] && [[ `lscpu | grep -o "avx2" | head -1` != "avx2" ]]; then
|
||||
echo "OpenVINO expects your CPU to support SSE4 or AVX2 instructions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
cd /tmp/components/openvino
|
||||
|
||||
tar -xzf `ls | grep "openvino_toolkit"`
|
||||
cd `ls -d */ | grep "openvino_toolkit"`
|
||||
|
||||
apt-get update && apt-get --no-install-recommends install -y sudo cpio && \
|
||||
if [ -f "install_cv_sdk_dependencies.sh" ]; then ./install_cv_sdk_dependencies.sh; \
|
||||
else ./install_openvino_dependencies.sh; fi && SUDO_FORCE_REMOVE=yes apt-get remove -y sudo
|
||||
|
||||
|
||||
cat ../eula.cfg >> silent.cfg
|
||||
./install.sh -s silent.cfg
|
||||
|
||||
cd /tmp/components && rm openvino -r
|
||||
|
||||
if [ -f "/opt/intel/computer_vision_sdk/bin/setupvars.sh" ]; then
|
||||
echo "source /opt/intel/computer_vision_sdk/bin/setupvars.sh" >> ${HOME}/.bashrc;
|
||||
echo -e '\nexport IE_PLUGINS_PATH=${IE_PLUGINS_PATH}' >> /opt/intel/computer_vision_sdk/bin/setupvars.sh;
|
||||
else
|
||||
echo "source /opt/intel/openvino/bin/setupvars.sh" >> ${HOME}/.bashrc;
|
||||
echo -e '\nexport IE_PLUGINS_PATH=${IE_PLUGINS_PATH}' >> /opt/intel/openvino/bin/setupvars.sh;
|
||||
fi
|
||||
@ -1,41 +0,0 @@
|
||||
## [Tensorflow Object Detector](https://github.com/tensorflow/models/tree/master/research/object_detection)
|
||||
|
||||
### What is it?
|
||||
* This application allows you automatically to annotate many various objects on images.
|
||||
* It uses [Faster RCNN Inception Resnet v2 Atrous Coco Model](http://download.tensorflow.org/models/object_detection/faster_rcnn_inception_resnet_v2_atrous_coco_2018_01_28.tar.gz) from [tensorflow detection model zoo](https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md)
|
||||
* It can work on CPU (with Tensorflow or OpenVINO) or GPU (with Tensorflow GPU).
|
||||
* It supports next classes (just specify them in "labels" row):
|
||||
```
|
||||
'surfboard', 'car', 'skateboard', 'boat', 'clock',
|
||||
'cat', 'cow', 'knife', 'apple', 'cup', 'tv',
|
||||
'baseball_bat', 'book', 'suitcase', 'tennis_racket',
|
||||
'stop_sign', 'couch', 'cell_phone', 'keyboard',
|
||||
'cake', 'tie', 'frisbee', 'truck', 'fire_hydrant',
|
||||
'snowboard', 'bed', 'vase', 'teddy_bear',
|
||||
'toaster', 'wine_glass', 'traffic_light',
|
||||
'broccoli', 'backpack', 'carrot', 'potted_plant',
|
||||
'donut', 'umbrella', 'parking_meter', 'bottle',
|
||||
'sandwich', 'motorcycle', 'bear', 'banana',
|
||||
'person', 'scissors', 'elephant', 'dining_table',
|
||||
'toothbrush', 'toilet', 'skis', 'bowl', 'sheep',
|
||||
'refrigerator', 'oven', 'microwave', 'train',
|
||||
'orange', 'mouse', 'laptop', 'bench', 'bicycle',
|
||||
'fork', 'kite', 'zebra', 'baseball_glove', 'bus',
|
||||
'spoon', 'horse', 'handbag', 'pizza', 'sports_ball',
|
||||
'airplane', 'hair_drier', 'hot_dog', 'remote',
|
||||
'sink', 'dog', 'bird', 'giraffe', 'chair'.
|
||||
```
|
||||
* Component adds "Run TF Annotation" button into dashboard.
|
||||
|
||||
|
||||
### Build docker image
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/tf_annotation/docker-compose.tf_annotation.yml build
|
||||
```
|
||||
|
||||
### Run docker container
|
||||
```bash
|
||||
# From project root directory
|
||||
docker-compose -f docker-compose.yml -f components/tf_annotation/docker-compose.tf_annotation.yml up -d
|
||||
```
|
||||
@ -1,13 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
version: "2.3"
|
||||
|
||||
services:
|
||||
cvat:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
TF_ANNOTATION: "yes"
|
||||
@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
set -e
|
||||
|
||||
cd ${HOME} && \
|
||||
curl http://download.tensorflow.org/models/object_detection/faster_rcnn_inception_resnet_v2_atrous_coco_2018_01_28.tar.gz -o model.tar.gz && \
|
||||
tar -xzf model.tar.gz && rm model.tar.gz && \
|
||||
mv faster_rcnn_inception_resnet_v2_atrous_coco_2018_01_28 ${HOME}/rcnn && cd ${HOME} && \
|
||||
mv rcnn/frozen_inference_graph.pb rcnn/inference_graph.pb
|
||||
|
||||
# tensorflow is installed globally
|
||||
@ -1,6 +1,5 @@
|
||||
docs
|
||||
node_modules
|
||||
reports
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
dist
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* global
|
||||
require:false
|
||||
*/
|
||||
|
||||
const serverProxy = require('./server-proxy');
|
||||
const { ArgumentError } = require('./exceptions');
|
||||
const { Task } = require('./session');
|
||||
const MLModel = require('./ml-model');
|
||||
const { RQStatus } = require('./enums');
|
||||
|
||||
class LambdaManager {
|
||||
constructor() {
|
||||
this.listening = {};
|
||||
this.cachedList = null;
|
||||
}
|
||||
|
||||
async list() {
|
||||
if (Array.isArray(this.cachedList)) {
|
||||
return [...this.cachedList];
|
||||
}
|
||||
|
||||
const result = await serverProxy.lambda.list();
|
||||
const models = [];
|
||||
|
||||
for (const model of result) {
|
||||
models.push(new MLModel({
|
||||
id: model.id,
|
||||
name: model.name,
|
||||
description: model.description,
|
||||
framework: model.framework,
|
||||
labels: [...model.labels],
|
||||
type: model.kind,
|
||||
}));
|
||||
}
|
||||
|
||||
this.cachedList = models;
|
||||
return models;
|
||||
}
|
||||
|
||||
async run(task, model, args) {
|
||||
if (!(task instanceof Task)) {
|
||||
throw new ArgumentError(
|
||||
`Argument task is expected to be an instance of Task class, but got ${typeof (task)}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!(model instanceof MLModel)) {
|
||||
throw new ArgumentError(
|
||||
`Argument model is expected to be an instance of MLModel class, but got ${typeof (model)}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (args && typeof (args) !== 'object') {
|
||||
throw new ArgumentError(
|
||||
`Argument args is expected to be an object, but got ${typeof (model)}`,
|
||||
);
|
||||
}
|
||||
|
||||
const body = args;
|
||||
body.task = task.id;
|
||||
body.function = model.id;
|
||||
|
||||
const result = await serverProxy.lambda.run(body);
|
||||
return result.id;
|
||||
}
|
||||
|
||||
async call(task, model, args) {
|
||||
const body = args;
|
||||
body.task = task.id;
|
||||
const result = await serverProxy.lambda.call(model.id, body);
|
||||
return result;
|
||||
}
|
||||
|
||||
async requests() {
|
||||
const result = await serverProxy.lambda.requests();
|
||||
return result.filter((request) => ['queued', 'started'].includes(request.status));
|
||||
}
|
||||
|
||||
async cancel(requestID) {
|
||||
if (typeof (requestID) !== 'string') {
|
||||
throw new ArgumentError(`Request id argument is required to be a string. But got ${requestID}`);
|
||||
}
|
||||
|
||||
if (this.listening[requestID]) {
|
||||
clearTimeout(this.listening[requestID].timeout);
|
||||
delete this.listening[requestID];
|
||||
}
|
||||
await serverProxy.lambda.cancel(requestID);
|
||||
}
|
||||
|
||||
async listen(requestID, onUpdate) {
|
||||
const timeoutCallback = async () => {
|
||||
try {
|
||||
this.listening[requestID].timeout = null;
|
||||
const response = await serverProxy.lambda.status(requestID);
|
||||
|
||||
if (response.status === RQStatus.QUEUED || response.status === RQStatus.STARTED) {
|
||||
onUpdate(response.status, response.progress || 0);
|
||||
this.listening[requestID].timeout = setTimeout(timeoutCallback, 2000);
|
||||
} else {
|
||||
if (response.status === RQStatus.FINISHED) {
|
||||
onUpdate(response.status, response.progress || 100);
|
||||
} else {
|
||||
onUpdate(response.status, response.progress || 0, response.exc_info || '');
|
||||
}
|
||||
|
||||
delete this.listening[requestID];
|
||||
}
|
||||
} catch (error) {
|
||||
onUpdate(RQStatus.UNKNOWN, 0, `Could not get a status of the request ${requestID}. ${error.toString()}`);
|
||||
}
|
||||
};
|
||||
|
||||
this.listening[requestID] = {
|
||||
onUpdate,
|
||||
timeout: setTimeout(timeoutCallback, 2000),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new LambdaManager();
|
||||
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2020 Intel Corporation
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class representing a machine learning model
|
||||
* @memberof module:API.cvat.classes
|
||||
*/
|
||||
class MLModel {
|
||||
constructor(data) {
|
||||
this._id = data.id;
|
||||
this._name = data.name;
|
||||
this._labels = data.labels;
|
||||
this._framework = data.framework;
|
||||
this._description = data.description;
|
||||
this._type = data.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
* @readonly
|
||||
*/
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
* @readonly
|
||||
*/
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string[]}
|
||||
* @readonly
|
||||
*/
|
||||
get labels() {
|
||||
if (Array.isArray(this._labels)) {
|
||||
return [...this._labels];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
* @readonly
|
||||
*/
|
||||
get framework() {
|
||||
return this._framework;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
* @readonly
|
||||
*/
|
||||
get description() {
|
||||
return this._description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {module:API.cvat.enums.ModelType}
|
||||
* @readonly
|
||||
*/
|
||||
get type() {
|
||||
return this._type;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MLModel;
|
||||
@ -1,227 +0,0 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import ReactDOM from 'react-dom';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Row, Col } from 'antd/lib/grid';
|
||||
import Modal from 'antd/lib/modal';
|
||||
import Menu from 'antd/lib/menu';
|
||||
import Text from 'antd/lib/typography/Text';
|
||||
import InputNumber from 'antd/lib/input-number';
|
||||
import Tooltip from 'antd/lib/tooltip';
|
||||
|
||||
import { clamp } from 'utils/math';
|
||||
import { run, cancel } from 'utils/reid-utils';
|
||||
import { connect } from 'react-redux';
|
||||
import { CombinedState } from 'reducers/interfaces';
|
||||
import { fetchAnnotationsAsync } from 'actions/annotation-actions';
|
||||
|
||||
interface InputModalProps {
|
||||
visible: boolean;
|
||||
onCancel(): void;
|
||||
onSubmit(threshold: number, distance: number): void;
|
||||
}
|
||||
|
||||
function InputModal(props: InputModalProps): JSX.Element {
|
||||
const { visible, onCancel, onSubmit } = props;
|
||||
const [threshold, setThreshold] = useState(0.5);
|
||||
const [distance, setDistance] = useState(50);
|
||||
|
||||
const [thresholdMin, thresholdMax] = [0.05, 0.95];
|
||||
const [distanceMin, distanceMax] = [1, 1000];
|
||||
return (
|
||||
<Modal
|
||||
closable={false}
|
||||
width={300}
|
||||
visible={visible}
|
||||
onCancel={onCancel}
|
||||
onOk={() => onSubmit(threshold, distance)}
|
||||
okText='Merge'
|
||||
>
|
||||
<Row type='flex'>
|
||||
<Col span={10}>
|
||||
<Tooltip title='Similarity of objects on neighbour frames is calculated using AI model'>
|
||||
<Text>Similarity threshold: </Text>
|
||||
</Tooltip>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<InputNumber
|
||||
style={{ width: '100%' }}
|
||||
min={thresholdMin}
|
||||
max={thresholdMax}
|
||||
step={0.05}
|
||||
value={threshold}
|
||||
onChange={(value: number | undefined) => {
|
||||
if (typeof (value) === 'number') {
|
||||
setThreshold(clamp(value, thresholdMin, thresholdMax));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row type='flex'>
|
||||
<Col span={10}>
|
||||
<Tooltip title='The value defines max distance to merge (between centers of two objects on neighbour frames)'>
|
||||
<Text>Max pixel distance: </Text>
|
||||
</Tooltip>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<InputNumber
|
||||
style={{ width: '100%' }}
|
||||
min={distanceMin}
|
||||
max={distanceMax}
|
||||
step={5}
|
||||
value={distance}
|
||||
onChange={(value: number | undefined) => {
|
||||
if (typeof (value) === 'number') {
|
||||
setDistance(clamp(value, distanceMin, distanceMax));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
interface InProgressDialogProps {
|
||||
visible: boolean;
|
||||
progress: number;
|
||||
onCancel(): void;
|
||||
}
|
||||
|
||||
function InProgressDialog(props: InProgressDialogProps): JSX.Element {
|
||||
const { visible, onCancel, progress } = props;
|
||||
return (
|
||||
<Modal
|
||||
closable={false}
|
||||
width={300}
|
||||
visible={visible}
|
||||
okText='Cancel'
|
||||
okButtonProps={{
|
||||
type: 'danger',
|
||||
}}
|
||||
onOk={onCancel}
|
||||
cancelButtonProps={{
|
||||
style: {
|
||||
display: 'none',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Text>{`Merging is in progress ${progress}%`}</Text>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const reidContainer = window.document.createElement('div');
|
||||
reidContainer.setAttribute('id', 'cvat-reid-wrapper');
|
||||
window.document.body.appendChild(reidContainer);
|
||||
|
||||
|
||||
interface StateToProps {
|
||||
jobInstance: any | null;
|
||||
}
|
||||
|
||||
interface DispatchToProps {
|
||||
updateAnnotations(): void;
|
||||
}
|
||||
|
||||
function mapStateToProps(state: CombinedState): StateToProps {
|
||||
const {
|
||||
annotation: {
|
||||
job: {
|
||||
instance: jobInstance,
|
||||
},
|
||||
},
|
||||
} = state;
|
||||
|
||||
return {
|
||||
jobInstance,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch: any): DispatchToProps {
|
||||
return {
|
||||
updateAnnotations(): void {
|
||||
dispatch(fetchAnnotationsAsync());
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function ReIDPlugin(props: StateToProps & DispatchToProps): JSX.Element {
|
||||
const { jobInstance, updateAnnotations, ...rest } = props;
|
||||
const [showInputDialog, setShowInputDialog] = useState(false);
|
||||
const [showInProgressDialog, setShowInProgressDialog] = useState(false);
|
||||
const [progress, setProgress] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
ReactDOM.render((
|
||||
<>
|
||||
<InProgressDialog
|
||||
visible={showInProgressDialog}
|
||||
progress={progress}
|
||||
onCancel={() => {
|
||||
cancel(jobInstance.id);
|
||||
}}
|
||||
/>
|
||||
<InputModal
|
||||
visible={showInputDialog}
|
||||
onCancel={() => setShowInputDialog(false)}
|
||||
onSubmit={async (threshold: number, distance: number) => {
|
||||
setProgress(0);
|
||||
setShowInputDialog(false);
|
||||
setShowInProgressDialog(true);
|
||||
|
||||
const onUpdatePercentage = (percent: number): void => {
|
||||
setProgress(percent);
|
||||
};
|
||||
|
||||
try {
|
||||
const annotations = await jobInstance.annotations.export();
|
||||
const merged = await run({
|
||||
threshold,
|
||||
distance,
|
||||
onUpdatePercentage,
|
||||
jobID: jobInstance.id,
|
||||
annotations,
|
||||
});
|
||||
await jobInstance.annotations.clear();
|
||||
updateAnnotations(); // one more call to do not confuse canvas
|
||||
await jobInstance.annotations.import(merged);
|
||||
updateAnnotations();
|
||||
} catch (error) {
|
||||
Modal.error({
|
||||
title: 'Could not merge annotations',
|
||||
content: error.toString(),
|
||||
});
|
||||
} finally {
|
||||
setShowInProgressDialog(false);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
), reidContainer);
|
||||
});
|
||||
|
||||
return (
|
||||
<Menu.Item
|
||||
{...rest}
|
||||
key='run_reid'
|
||||
title='Run algorithm that merges separated bounding boxes automatically'
|
||||
onClick={() => {
|
||||
if (jobInstance) {
|
||||
setShowInputDialog(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Run ReID merge
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(ReIDPlugin);
|
||||
@ -0,0 +1,166 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import React from 'react';
|
||||
import Form, { FormComponentProps } from 'antd/lib/form/Form';
|
||||
import Button from 'antd/lib/button';
|
||||
import Icon from 'antd/lib/icon';
|
||||
import Input from 'antd/lib/input';
|
||||
|
||||
import patterns from 'utils/validation-patterns';
|
||||
|
||||
export interface ChangePasswordData {
|
||||
oldPassword: string;
|
||||
newPassword1: string;
|
||||
newPassword2: string;
|
||||
}
|
||||
|
||||
type ChangePasswordFormProps = {
|
||||
fetching: boolean;
|
||||
onSubmit(loginData: ChangePasswordData): void;
|
||||
} & FormComponentProps;
|
||||
|
||||
class ChangePasswordFormComponent extends React.PureComponent<ChangePasswordFormProps> {
|
||||
private validateConfirmation = (_: any, value: string, callback: Function): void => {
|
||||
const { form } = this.props;
|
||||
if (value && value !== form.getFieldValue('newPassword1')) {
|
||||
callback('Two passwords that you enter is inconsistent!');
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
private validatePassword = (_: any, value: string, callback: Function): void => {
|
||||
const { form } = this.props;
|
||||
if (!patterns.validatePasswordLength.pattern.test(value)) {
|
||||
callback(patterns.validatePasswordLength.message);
|
||||
}
|
||||
|
||||
if (!patterns.passwordContainsNumericCharacters.pattern.test(value)) {
|
||||
callback(patterns.passwordContainsNumericCharacters.message);
|
||||
}
|
||||
|
||||
if (!patterns.passwordContainsUpperCaseCharacter.pattern.test(value)) {
|
||||
callback(patterns.passwordContainsUpperCaseCharacter.message);
|
||||
}
|
||||
|
||||
if (!patterns.passwordContainsLowerCaseCharacter.pattern.test(value)) {
|
||||
callback(patterns.passwordContainsLowerCaseCharacter.message);
|
||||
}
|
||||
|
||||
if (value) {
|
||||
form.validateFields(['newPassword2'], { force: true });
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
private handleSubmit = (e: React.FormEvent): void => {
|
||||
e.preventDefault();
|
||||
const {
|
||||
form,
|
||||
onSubmit,
|
||||
} = this.props;
|
||||
|
||||
form.validateFields((error, values): void => {
|
||||
if (!error) {
|
||||
const validatedFields = {
|
||||
...values,
|
||||
confirmations: [],
|
||||
};
|
||||
|
||||
onSubmit(validatedFields);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
private renderOldPasswordField(): JSX.Element {
|
||||
const { form } = this.props;
|
||||
|
||||
return (
|
||||
<Form.Item hasFeedback>
|
||||
{form.getFieldDecorator('oldPassword', {
|
||||
rules: [{
|
||||
required: true,
|
||||
message: 'Please input your current password!',
|
||||
}],
|
||||
})(<Input.Password
|
||||
autoComplete='new-password'
|
||||
prefix={<Icon type='lock' style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
|
||||
placeholder='Current password'
|
||||
/>)}
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
|
||||
private renderNewPasswordField(): JSX.Element {
|
||||
const { form } = this.props;
|
||||
|
||||
return (
|
||||
<Form.Item hasFeedback>
|
||||
{form.getFieldDecorator('newPassword1', {
|
||||
rules: [{
|
||||
required: true,
|
||||
message: 'Please input new password!',
|
||||
}, {
|
||||
validator: this.validatePassword,
|
||||
}],
|
||||
})(<Input.Password
|
||||
autoComplete='new-password'
|
||||
prefix={<Icon type='lock' style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
|
||||
placeholder='New password'
|
||||
/>)}
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
|
||||
private renderNewPasswordConfirmationField(): JSX.Element {
|
||||
const { form } = this.props;
|
||||
|
||||
return (
|
||||
<Form.Item hasFeedback>
|
||||
{form.getFieldDecorator('newPassword2', {
|
||||
rules: [{
|
||||
required: true,
|
||||
message: 'Please confirm your new password!',
|
||||
}, {
|
||||
validator: this.validateConfirmation,
|
||||
}],
|
||||
})(<Input.Password
|
||||
autoComplete='new-password'
|
||||
prefix={<Icon type='lock' style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
|
||||
placeholder='Confirm new password'
|
||||
/>)}
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
const { fetching } = this.props;
|
||||
|
||||
return (
|
||||
<Form
|
||||
onSubmit={this.handleSubmit}
|
||||
className='change-password-form'
|
||||
>
|
||||
{this.renderOldPasswordField()}
|
||||
{this.renderNewPasswordField()}
|
||||
{this.renderNewPasswordConfirmationField()}
|
||||
|
||||
<Form.Item>
|
||||
<Button
|
||||
type='primary'
|
||||
htmlType='submit'
|
||||
className='change-password-form-button'
|
||||
loading={fetching}
|
||||
disabled={fetching}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Form.create<ChangePasswordFormProps>()(ChangePasswordFormComponent);
|
||||
@ -0,0 +1,84 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import Modal from 'antd/lib/modal';
|
||||
import Title from 'antd/lib/typography/Title';
|
||||
|
||||
import { changePasswordAsync } from 'actions/auth-actions';
|
||||
import { CombinedState } from 'reducers/interfaces';
|
||||
import ChangePasswordForm, { ChangePasswordData } from './change-password-form';
|
||||
|
||||
|
||||
interface StateToProps {
|
||||
fetching: boolean;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
interface DispatchToProps {
|
||||
onChangePassword(
|
||||
oldPassword: string,
|
||||
newPassword1: string,
|
||||
newPassword2: string): void;
|
||||
}
|
||||
|
||||
interface ChangePasswordPageComponentProps {
|
||||
fetching: boolean;
|
||||
visible: boolean;
|
||||
onChangePassword: (oldPassword: string, newPassword1: string, newPassword2: string) => void;
|
||||
onClose(): void;
|
||||
}
|
||||
|
||||
function mapStateToProps(state: CombinedState): StateToProps {
|
||||
return {
|
||||
fetching: state.auth.fetching,
|
||||
visible: state.auth.showChangePasswordDialog,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch: any): DispatchToProps {
|
||||
return ({
|
||||
onChangePassword(oldPassword: string, newPassword1: string, newPassword2: string): void {
|
||||
dispatch(changePasswordAsync(oldPassword, newPassword1, newPassword2));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function ChangePasswordComponent(props: ChangePasswordPageComponentProps): JSX.Element {
|
||||
const {
|
||||
fetching,
|
||||
onChangePassword,
|
||||
visible,
|
||||
onClose,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={<Title level={3}>Change password</Title>}
|
||||
okType='primary'
|
||||
okText='Submit'
|
||||
footer={null}
|
||||
visible={visible}
|
||||
destroyOnClose
|
||||
onCancel={onClose}
|
||||
>
|
||||
<ChangePasswordForm
|
||||
onSubmit={(changePasswordData: ChangePasswordData): void => {
|
||||
onChangePassword(
|
||||
changePasswordData.oldPassword,
|
||||
changePasswordData.newPassword1,
|
||||
changePasswordData.newPassword2,
|
||||
);
|
||||
}}
|
||||
fetching={fetching}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(ChangePasswordComponent);
|
||||
@ -1,160 +0,0 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import React from 'react';
|
||||
import { Row, Col } from 'antd/lib/grid';
|
||||
import Icon from 'antd/lib/icon';
|
||||
import Alert from 'antd/lib/alert';
|
||||
import Button from 'antd/lib/button';
|
||||
import Tooltip from 'antd/lib/tooltip';
|
||||
import message from 'antd/lib/message';
|
||||
import notification from 'antd/lib/notification';
|
||||
import Text from 'antd/lib/typography/Text';
|
||||
|
||||
import consts from 'consts';
|
||||
import ConnectedFileManager, {
|
||||
FileManagerContainer,
|
||||
} from 'containers/file-manager/file-manager';
|
||||
import { ModelFiles } from 'reducers/interfaces';
|
||||
|
||||
import CreateModelForm, {
|
||||
CreateModelForm as WrappedCreateModelForm,
|
||||
} from './create-model-form';
|
||||
|
||||
interface Props {
|
||||
createModel(name: string, files: ModelFiles, global: boolean): void;
|
||||
isAdmin: boolean;
|
||||
modelCreatingStatus: string;
|
||||
}
|
||||
|
||||
export default class CreateModelContent extends React.PureComponent<Props> {
|
||||
private modelForm: WrappedCreateModelForm;
|
||||
private fileManagerContainer: FileManagerContainer;
|
||||
|
||||
public constructor(props: Props) {
|
||||
super(props);
|
||||
this.modelForm = null as any as WrappedCreateModelForm;
|
||||
this.fileManagerContainer = null as any as FileManagerContainer;
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Props): void {
|
||||
const { modelCreatingStatus } = this.props;
|
||||
|
||||
if (prevProps.modelCreatingStatus !== 'CREATED'
|
||||
&& modelCreatingStatus === 'CREATED') {
|
||||
message.success('The model has been uploaded');
|
||||
this.modelForm.resetFields();
|
||||
this.fileManagerContainer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private handleSubmitClick = (): void => {
|
||||
const { createModel } = this.props;
|
||||
this.modelForm.submit()
|
||||
.then((data) => {
|
||||
const {
|
||||
local,
|
||||
share,
|
||||
} = this.fileManagerContainer.getFiles();
|
||||
|
||||
const files = local.length ? local : share;
|
||||
const grouppedFiles: ModelFiles = {
|
||||
xml: '',
|
||||
bin: '',
|
||||
py: '',
|
||||
json: '',
|
||||
};
|
||||
|
||||
(files as any).reduce((acc: ModelFiles, value: File | string): ModelFiles => {
|
||||
const name = typeof value === 'string' ? value : value.name;
|
||||
const [extension] = name.split('.').reverse();
|
||||
if (extension in acc) {
|
||||
acc[extension] = value;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, grouppedFiles);
|
||||
|
||||
if (Object.keys(grouppedFiles)
|
||||
.map((key: string) => grouppedFiles[key])
|
||||
.filter((val) => !!val).length !== 4) {
|
||||
notification.error({
|
||||
message: 'Could not upload a model',
|
||||
description: 'Please, specify correct files',
|
||||
});
|
||||
} else {
|
||||
createModel(data.name, grouppedFiles, data.global);
|
||||
}
|
||||
}).catch(() => {
|
||||
notification.error({
|
||||
message: 'Could not upload a model',
|
||||
description: 'Please, check input fields',
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
public render(): JSX.Element {
|
||||
const {
|
||||
modelCreatingStatus,
|
||||
} = this.props;
|
||||
const loading = !!modelCreatingStatus
|
||||
&& modelCreatingStatus !== 'CREATED';
|
||||
const status = modelCreatingStatus
|
||||
&& modelCreatingStatus !== 'CREATED' ? modelCreatingStatus : '';
|
||||
|
||||
const { AUTO_ANNOTATION_GUIDE_URL } = consts;
|
||||
return (
|
||||
<Row type='flex' justify='start' align='middle' className='cvat-create-model-content'>
|
||||
<Col span={24}>
|
||||
<Tooltip title='Click to open guide'>
|
||||
<Icon
|
||||
onClick={(): void => {
|
||||
// false positive
|
||||
// eslint-disable-next-line
|
||||
window.open(AUTO_ANNOTATION_GUIDE_URL, '_blank');
|
||||
}}
|
||||
type='question-circle'
|
||||
/>
|
||||
</Tooltip>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<CreateModelForm
|
||||
wrappedComponentRef={
|
||||
(ref: WrappedCreateModelForm): void => {
|
||||
this.modelForm = ref;
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Text type='danger'>* </Text>
|
||||
<Text className='cvat-text-color'>Select files:</Text>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<ConnectedFileManager
|
||||
ref={
|
||||
(container: FileManagerContainer): void => {
|
||||
this.fileManagerContainer = container;
|
||||
}
|
||||
}
|
||||
withRemote={false}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={18}>
|
||||
{status && <Alert message={`${status}`} />}
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Button
|
||||
type='primary'
|
||||
disabled={loading}
|
||||
loading={loading}
|
||||
onClick={this.handleSubmitClick}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import React from 'react';
|
||||
import { Row, Col } from 'antd/lib/grid';
|
||||
import Form, { FormComponentProps } from 'antd/lib/form/Form';
|
||||
import Input from 'antd/lib/input';
|
||||
import Tooltip from 'antd/lib/tooltip';
|
||||
import Checkbox from 'antd/lib/checkbox';
|
||||
import Text from 'antd/lib/typography/Text';
|
||||
|
||||
type Props = FormComponentProps;
|
||||
|
||||
export class CreateModelForm extends React.PureComponent<Props> {
|
||||
public submit(): Promise<{name: string; global: boolean}> {
|
||||
const { form } = this.props;
|
||||
return new Promise((resolve, reject) => {
|
||||
form.validateFields((errors, values): void => {
|
||||
if (!errors) {
|
||||
resolve({
|
||||
name: values.name,
|
||||
global: values.global,
|
||||
});
|
||||
} else {
|
||||
reject(errors);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public resetFields(): void {
|
||||
const { form } = this.props;
|
||||
form.resetFields();
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
const { form } = this.props;
|
||||
const { getFieldDecorator } = form;
|
||||
|
||||
return (
|
||||
<Form onSubmit={(e: React.FormEvent): void => e.preventDefault()}>
|
||||
<Row>
|
||||
<Col span={24}>
|
||||
<Text type='danger'>* </Text>
|
||||
<Text className='cvat-text-color'>Name:</Text>
|
||||
</Col>
|
||||
<Col span={14}>
|
||||
<Form.Item hasFeedback>
|
||||
{ getFieldDecorator('name', {
|
||||
rules: [{
|
||||
required: true,
|
||||
message: 'Please, specify a model name',
|
||||
}],
|
||||
})(<Input placeholder='Model name' />)}
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8} offset={2}>
|
||||
<Form.Item>
|
||||
<Tooltip title='Will this model be availabe for everyone?'>
|
||||
{ getFieldDecorator('global', {
|
||||
initialValue: false,
|
||||
valuePropName: 'checked',
|
||||
})(
|
||||
<Checkbox>
|
||||
<Text className='cvat-text-color'>
|
||||
Load globally
|
||||
</Text>
|
||||
</Checkbox>,
|
||||
)}
|
||||
</Tooltip>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Form.create()(CreateModelForm);
|
||||
@ -1,38 +0,0 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import './styles.scss';
|
||||
import React from 'react';
|
||||
import { Row, Col } from 'antd/lib/grid';
|
||||
import Text from 'antd/lib/typography/Text';
|
||||
|
||||
import { ModelFiles } from 'reducers/interfaces';
|
||||
import CreateModelContent from './create-model-content';
|
||||
|
||||
interface Props {
|
||||
createModel(name: string, files: ModelFiles, global: boolean): void;
|
||||
isAdmin: boolean;
|
||||
modelCreatingStatus: string;
|
||||
}
|
||||
|
||||
export default function CreateModelPageComponent(props: Props): JSX.Element {
|
||||
const {
|
||||
isAdmin,
|
||||
modelCreatingStatus,
|
||||
createModel,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Row type='flex' justify='center' align='top' className='cvat-create-model-form-wrapper'>
|
||||
<Col md={20} lg={16} xl={14} xxl={9}>
|
||||
<Text className='cvat-title'>Upload a new model</Text>
|
||||
<CreateModelContent
|
||||
isAdmin={isAdmin}
|
||||
modelCreatingStatus={modelCreatingStatus}
|
||||
createModel={createModel}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
@import '../../base.scss';
|
||||
|
||||
.cvat-create-model-form-wrapper {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
overflow-y: auto;
|
||||
height: 90%;
|
||||
|
||||
> div > span {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.cvat-create-model-content {
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border: 1px solid $border-color-1;
|
||||
border-radius: 3px;
|
||||
padding: 20px;
|
||||
background: $background-color-1;
|
||||
text-align: initial;
|
||||
|
||||
> div:nth-child(1) > i {
|
||||
float: right;
|
||||
font-size: 20px;
|
||||
color: $danger-icon-color;
|
||||
}
|
||||
|
||||
> div:nth-child(4) {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
> div:nth-child(6) > button {
|
||||
margin-top: 10px;
|
||||
float: right;
|
||||
width: 120px;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue