diff --git a/serverless/tensorflow/matterport/mask_rcnn/nuclio/function.yaml b/serverless/tensorflow/matterport/mask_rcnn/nuclio/function.yaml index 694b7ef4dab..9a763f3d48d 100644 --- a/serverless/tensorflow/matterport/mask_rcnn/nuclio/function.yaml +++ b/serverless/tensorflow/matterport/mask_rcnn/nuclio/function.yaml @@ -1,35 +1,132 @@ metadata: - name: tf-maskrcnn + name: tf.matterport.mask_rcnn namespace: cvat + annotations: + name: Mask RCNN via Tensorflow + type: detector + framework: tensorflow + spec: | + [ + { "id": 0, "name": "BG" }, + { "id": 1, "name": "person" }, + { "id": 2, "name": "bicycle" }, + { "id": 3, "name": "car" }, + { "id": 4, "name": "motorcycle" }, + { "id": 5, "name": "airplane" }, + { "id": 6, "name": "bus" }, + { "id": 7, "name": "train" }, + { "id": 8, "name": "truck" }, + { "id": 9, "name": "boat" }, + { "id": 10, "name": "traffic_light" }, + { "id": 11, "name": "fire_hydrant" }, + { "id": 12, "name": "stop_sign" }, + { "id": 13, "name": "parking_meter" }, + { "id": 14, "name": "bench" }, + { "id": 15, "name": "bird" }, + { "id": 16, "name": "cat" }, + { "id": 17, "name": "dog" }, + { "id": 18, "name": "horse" }, + { "id": 19, "name": "sheep" }, + { "id": 20, "name": "cow" }, + { "id": 21, "name": "elephant" }, + { "id": 22, "name": "bear" }, + { "id": 23, "name": "zebra" }, + { "id": 24, "name": "giraffe" }, + { "id": 25, "name": "backpack" }, + { "id": 26, "name": "umbrella" }, + { "id": 27, "name": "handbag" }, + { "id": 28, "name": "tie" }, + { "id": 29, "name": "suitcase" }, + { "id": 30, "name": "frisbee" }, + { "id": 31, "name": "skis" }, + { "id": 32, "name": "snowboard" }, + { "id": 33, "name": "sports_ball" }, + { "id": 34, "name": "kite" }, + { "id": 35, "name": "baseball_bat" }, + { "id": 36, "name": "baseball_glove" }, + { "id": 37, "name": "skateboard" }, + { "id": 38, "name": "surfboard" }, + { "id": 39, "name": "tennis_racket" }, + { "id": 40, "name": "bottle" }, + { "id": 41, "name": "wine_glass" }, + { "id": 42, "name": "cup" }, + { "id": 43, "name": "fork" }, + { "id": 44, "name": "knife" }, + { "id": 45, "name": "spoon" }, + { "id": 46, "name": "bowl" }, + { "id": 47, "name": "banana" }, + { "id": 48, "name": "apple" }, + { "id": 49, "name": "sandwich" }, + { "id": 50, "name": "orange" }, + { "id": 51, "name": "broccoli" }, + { "id": 52, "name": "carrot" }, + { "id": 53, "name": "hot_dog" }, + { "id": 54, "name": "pizza" }, + { "id": 55, "name": "donut" }, + { "id": 56, "name": "cake" }, + { "id": 57, "name": "chair" }, + { "id": 58, "name": "couch" }, + { "id": 59, "name": "potted_plant" }, + { "id": 60, "name": "bed" }, + { "id": 61, "name": "dining_table" }, + { "id": 62, "name": "toilet" }, + { "id": 63, "name": "tv" }, + { "id": 64, "name": "laptop" }, + { "id": 65, "name": "mouse" }, + { "id": 66, "name": "remote" }, + { "id": 67, "name": "keyboard" }, + { "id": 68, "name": "cell_phone" }, + { "id": 69, "name": "microwave" }, + { "id": 70, "name": "oven" }, + { "id": 71, "name": "toaster" }, + { "id": 72, "name": "sink" }, + { "id": 73, "name": "refrigerator" }, + { "id": 74, "name": "book" }, + { "id": 75, "name": "clock" }, + { "id": 76, "name": "vase" }, + { "id": 77, "name": "scissors" }, + { "id": 78, "name": "teddy_bear" }, + { "id": 79, "name": "hair_drier" }, + { "id": 80, "name": "toothbrush" } + ] spec: - description: TensorFlow MASK RCNN + description: | + An implementation of Mask RCNN on Python 3, Keras, and TensorFlow. + runtime: "python:3.6" handler: main:handler eventTimeout: 30s env: - - name: MASK_RCNN_PATH + - name: MASK_RCNN_DIR value: /opt/nuclio/Mask_RCNN - build: - image: cvat/tf-maskrcnn + image: cvat/tf.matterport.mask_rcnn baseImage: tensorflow/tensorflow:2.1.0-py3 - directives: postCopy: - kind: WORKDIR value: /opt/nuclio - kind: RUN - value: apt update && apt install --no-install-recommends -y git curl + value: apt update && apt install --no-install-recommends -y git curl libsm6 libxext6 libxrender-dev - kind: RUN value: git clone https://github.com/matterport/Mask_RCNN.git - kind: RUN value: curl -L https://github.com/matterport/Mask_RCNN/releases/download/v2.0/mask_rcnn_coco.h5 -o Mask_RCNN/mask_rcnn_coco.h5 - kind: RUN value: pip3 install -r Mask_RCNN/requirements.txt + - kind: RUN + value: pip3 install pycocotools tensorflow==1.13.1 keras==2.1.0 pillow pyyaml triggers: myHttpTrigger: maxWorkers: 2 kind: "http" workerAvailabilityTimeoutMilliseconds: 10000 + attributes: + maxRequestBodySize: 33554432 # 32MB + + platform: + restartPolicy: + name: always + maximumRetryCount: 3 diff --git a/serverless/tensorflow/matterport/mask_rcnn/nuclio/main.py b/serverless/tensorflow/matterport/mask_rcnn/nuclio/main.py index 44cb1f1b0a0..95816dd45fe 100644 --- a/serverless/tensorflow/matterport/mask_rcnn/nuclio/main.py +++ b/serverless/tensorflow/matterport/mask_rcnn/nuclio/main.py @@ -2,21 +2,31 @@ import base64 from PIL import Image import io +from model_loader import ModelLoader +import numpy as np +import yaml + def init_context(context): context.logger.info("Init context... 0%") - maskrcnn_handler = None - setattr(context.user_data, 'maskrcnn_handler', maskrcnn_handler) + + functionconfig = yaml.safe_load(open("/opt/nuclio/function.yaml")) + labels_spec = functionconfig['metadata']['annotations']['spec'] + labels = {item['id']: item['name'] for item in json.loads(labels_spec)} + + model_handler = ModelLoader(labels) + setattr(context.user_data, 'model_handler', model_handler) + context.logger.info("Init context...100%") def handler(context, event): - context.logger.info("call handler") + context.logger.info("Run tf.matterport.mask_rcnn model") data = event.body - buf = io.BytesIO(base64.b64decode(data["image"])) + buf = io.BytesIO(base64.b64decode(data["image"].encode('utf-8'))) + threshold = float(data.get("threshold", 0.2)) image = Image.open(buf) - objects = context.user_data.maskrcnn_handler.handle(image) - return context.Response(body=json.dumps(objects), - headers={}, - content_type='application/json', - status_code=200) + results = context.user_data.model_handler.infer(np.array(image), threshold) + + return context.Response(body=json.dumps(results), headers={}, + content_type='application/json', status_code=200) \ No newline at end of file diff --git a/serverless/tensorflow/matterport/mask_rcnn/nuclio/mask_rcnn.py b/serverless/tensorflow/matterport/mask_rcnn/nuclio/mask_rcnn.py deleted file mode 100644 index b510cc623a7..00000000000 --- a/serverless/tensorflow/matterport/mask_rcnn/nuclio/mask_rcnn.py +++ /dev/null @@ -1,104 +0,0 @@ - -# Copyright (C) 2018-2019 Intel Corporation -# -# SPDX-License-Identifier: MIT - -import os -import numpy as np -import sys -from skimage.measure import find_contours, approximate_polygon - -class MASKRCNN: - def get_labels_by_name(self): - return { "BG": 0, "person": 1, "bicycle": 2, "car": 3, - "motorcycle": 4, "airplane": 5, "bus": 6, "train": 7, "truck": 8, - "boat": 9, "traffic_light": 10, "fire_hydrant": 11, "stop_sign": 12, - "parking_meter": 13, "bench": 14, "bird": 15, "cat": 16, "dog": 17, - "horse": 18, "sheep": 19, "cow": 20, "elephant": 21, "bear": 22, - "zebra": 23, "giraffe": 24, "backpack": 25, "umbrella": 26, - "handbag": 27, "tie": 28, "suitcase": 29, "frisbee": 30, "skis": 31, - "snowboard": 32, "sports_ball": 33, "kite": 34, "baseball_bat": 35, - "baseball_glove": 36, "skateboard": 37, "surfboard": 38, - "tennis_racket": 39, "bottle": 40, "wine_glass": 41, "cup": 42, - "fork": 43, "knife": 44, "spoon": 45, "bowl": 46, "banana": 47, - "apple": 48, "sandwich": 49, "orange": 50, "broccoli": 51, - "carrot": 52, "hot_dog": 53, "pizza": 54, "donut": 55, "cake": 56, - "chair": 57, "couch": 58, "potted_plant": 59, "bed": 60, - "dining_table": 61, "toilet": 62, "tv": 63, "laptop": 64, "mouse": 65, - "remote": 66, "keyboard": 67, "cell_phone": 68, "microwave": 69, - "oven": 70, "toaster": 71, "sink": 72, "refrigerator": 73, "book": 74, - "clock": 75, "vase": 76, "scissors": 77, "teddy_bear": 78, - "hair_drier": 79, "toothbrush": 80 } - - def get_labels_by_id(self): - return {v:k for k,v in self.get_labels_by_id().items()} - - @staticmethod - def _convert_to_segmentation(mask): - contours = find_contours(mask, 0.5) - # only one contour exist in our case - contour = contours[0] - contour = np.flip(contour, axis=1) - # Approximate the contour and reduce the number of points - contour = approximate_polygon(contour, tolerance=2.5) - segmentation = contour.ravel().tolist() - return segmentation - - def __init__(self): - # Root directory of the project - ROOT_DIR = os.environ.get('MASK_RCNN_PATH', '/opt/nuclio/MASKRCNN') - # Import Mask RCNN - sys.path.append(ROOT_DIR) # To find local version of the library - import mrcnn.model as modellib - - # Import COCO config - sys.path.append(os.path.join(ROOT_DIR, "samples/coco/")) # To find local version - import coco - - # Directory to save logs and trained model - MODEL_DIR = os.path.join(ROOT_DIR, "logs") - - # Local path to trained weights file - COCO_MODEL_PATH = os.path.join(ROOT_DIR, "mask_rcnn_coco.h5") - if COCO_MODEL_PATH is None: - raise OSError('Model path env not found in the system.') - - ## CONFIGURATION - - class InferenceConfig(coco.CocoConfig): - # Set batch size to 1 since we'll be running inference on - # one image at a time. Batch size = GPU_COUNT * IMAGES_PER_GPU - GPU_COUNT = 1 - IMAGES_PER_GPU = 1 - - # Print config details - config = InferenceConfig() - config.display() - - ## CREATE MODEL AND LOAD TRAINED WEIGHTS - - # Create model object in inference mode. - self.model = modellib.MaskRCNN(mode="inference", model_dir=MODEL_DIR, config=config) - # Load weights trained on MS-COCO - self.model.load_weights(COCO_MODEL_PATH, by_name=True) - - def run(self, image, threshold=0.5): - ## RUN OBJECT DETECTION - results = {} - - # for multiple image detection, "batch size" must be equal to number of images - r = self.model.detect([image], verbose=1) - - r = r[0] - - # "r['rois'][index]" gives bounding box around the object - for index, class_id in enumerate(r['class_ids']): - if r['scores'][index] >= threshold: - mask = r['masks'][:,:,index].astype(np.uint8) - segmentation = _convert_to_segmentation(mask) - if class_id not in results: - results[class_id] = [] - results[class_id].append(segmentation) - - return results - diff --git a/serverless/tensorflow/matterport/mask_rcnn/nuclio/model_loader.py b/serverless/tensorflow/matterport/mask_rcnn/nuclio/model_loader.py new file mode 100644 index 00000000000..482e5d55883 --- /dev/null +++ b/serverless/tensorflow/matterport/mask_rcnn/nuclio/model_loader.py @@ -0,0 +1,80 @@ +# Copyright (C) 2018-2020 Intel Corporation +# +# SPDX-License-Identifier: MIT + +import os +import numpy as np +import sys +from skimage.measure import find_contours, approximate_polygon + +# workarround for tf.placeholder() is not compatible with eager execution +# https://github.com/tensorflow/tensorflow/issues/18165 +import tensorflow as tf +tf.compat.v1.disable_eager_execution() +#import tensorflow.compat.v1 as tf +# tf.disable_v2_behavior() + +# The directory should contain a clone of +# https://github.com/matterport/Mask_RCNN repository and +# downloaded mask_rcnn_coco.h5 model. +MASK_RCNN_DIR = os.environ.get('MASK_RCNN_DIR') +if MASK_RCNN_DIR: + sys.path.append(MASK_RCNN_DIR) # To find local version of the library + sys.path.append(os.path.join(MASK_RCNN_DIR, 'samples/coco')) + +from mrcnn import model as modellib, utils +import coco + +class ModelLoader: + def __init__(self, labels): + COCO_MODEL_PATH = os.path.join(MASK_RCNN_DIR, "mask_rcnn_coco.h5") + if COCO_MODEL_PATH is None: + raise OSError('Model path env not found in the system.') + + class InferenceConfig(coco.CocoConfig): + # Set batch size to 1 since we'll be running inference on + # one image at a time. Batch size = GPU_COUNT * IMAGES_PER_GPU + GPU_COUNT = 1 + IMAGES_PER_GPU = 1 + + # Print config details + self.config = InferenceConfig() + self.config.display() + + self.model = modellib.MaskRCNN(mode="inference", + config=self.config, model_dir=MASK_RCNN_DIR) + self.model.load_weights(COCO_MODEL_PATH, by_name=True) + self.labels = labels + + def infer(self, image, threshold): + output = self.model.detect([image], verbose=1)[0] + + results = [] + MASK_THRESHOLD = 0.5 + for i, box in enumerate(output["rois"]): + score = output["scores"][i] + class_id = output["class_ids"][i] + mask = output["masks"][:,:,i] + if score >= threshold: + mask = mask.astype(np.uint8) + contours = find_contours(mask, MASK_THRESHOLD) + # only one contour exist in our case + contour = contours[0] + contour = np.flip(contour, axis=1) + # Approximate the contour and reduce the number of points + contour = approximate_polygon(contour, tolerance=2.5) + polygon = contour.ravel().tolist() + if len(contour) < 3: + continue + label = self.labels[class_id] + + results.append({ + "confidence": str(score), + "label": label, + "points": polygon, + "type": "polygon", + }) + + return results + + diff --git a/serverless/tensorflow/matterport/mask_rcnn/views.py b/serverless/tensorflow/matterport/mask_rcnn/views.py deleted file mode 100644 index 4b15b094f29..00000000000 --- a/serverless/tensorflow/matterport/mask_rcnn/views.py +++ /dev/null @@ -1,310 +0,0 @@ - -# Copyright (C) 2018-2020 Intel Corporation -# -# SPDX-License-Identifier: MIT - - -from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest -from rest_framework.decorators import api_view -from rules.contrib.views import permission_required, objectgetter -from cvat.apps.authentication.decorators import login_required -from cvat.apps.dataset_manager.task import put_task_data -from cvat.apps.engine.models import Task as TaskModel -from cvat.apps.engine.serializers import LabeledDataSerializer -from cvat.apps.engine.frame_provider import FrameProvider - -import django_rq -import os -import rq - -import numpy as np - -from cvat.apps.engine.log import slogger - -import sys -import skimage.io -from skimage.measure import find_contours, approximate_polygon - -def run_tensorflow_auto_segmentation(frame_provider, labels_mapping, treshold): - def _convert_to_int(boolean_mask): - return boolean_mask.astype(np.uint8) - - def _convert_to_segmentation(mask): - contours = find_contours(mask, 0.5) - # only one contour exist in our case - contour = contours[0] - contour = np.flip(contour, axis=1) - # Approximate the contour and reduce the number of points - contour = approximate_polygon(contour, tolerance=2.5) - segmentation = contour.ravel().tolist() - return segmentation - - ## INITIALIZATION - - # workarround for tf.placeholder() is not compatible with eager execution - # https://github.com/tensorflow/tensorflow/issues/18165 - import tensorflow as tf - tf.compat.v1.disable_eager_execution() - - # Root directory of the project - ROOT_DIR = os.environ.get('AUTO_SEGMENTATION_PATH') - # Import Mask RCNN - sys.path.append(ROOT_DIR) # To find local version of the library - import mrcnn.model as modellib - - # Import COCO config - sys.path.append(os.path.join(ROOT_DIR, "samples/coco/")) # To find local version - import coco - - # Directory to save logs and trained model - MODEL_DIR = os.path.join(ROOT_DIR, "logs") - - # Local path to trained weights file - COCO_MODEL_PATH = os.path.join(ROOT_DIR, "mask_rcnn_coco.h5") - if COCO_MODEL_PATH is None: - raise OSError('Model path env not found in the system.') - job = rq.get_current_job() - - ## CONFIGURATION - - class InferenceConfig(coco.CocoConfig): - # Set batch size to 1 since we'll be running inference on - # one image at a time. Batch size = GPU_COUNT * IMAGES_PER_GPU - GPU_COUNT = 1 - IMAGES_PER_GPU = 1 - - # Print config details - config = InferenceConfig() - config.display() - - ## CREATE MODEL AND LOAD TRAINED WEIGHTS - - # Create model object in inference mode. - model = modellib.MaskRCNN(mode="inference", model_dir=MODEL_DIR, config=config) - # Load weights trained on MS-COCO - model.load_weights(COCO_MODEL_PATH, by_name=True) - - ## RUN OBJECT DETECTION - result = {} - frames = frame_provider.get_frames(frame_provider.Quality.ORIGINAL) - for image_num, (image_bytes, _) in enumerate(frames): - job.refresh() - if 'cancel' in job.meta: - del job.meta['cancel'] - job.save() - return None - job.meta['progress'] = image_num * 100 / len(frame_provider) - job.save_meta() - - image = skimage.io.imread(image_bytes) - - # for multiple image detection, "batch size" must be equal to number of images - r = model.detect([image], verbose=1) - - r = r[0] - # "r['rois'][index]" gives bounding box around the object - for index, c_id in enumerate(r['class_ids']): - if c_id in labels_mapping.keys(): - if r['scores'][index] >= treshold: - mask = _convert_to_int(r['masks'][:,:,index]) - segmentation = _convert_to_segmentation(mask) - label = labels_mapping[c_id] - if label not in result: - result[label] = [] - result[label].append( - [image_num, segmentation]) - - return result - -def convert_to_cvat_format(data): - result = { - "tracks": [], - "shapes": [], - "tags": [], - "version": 0, - } - - for label in data: - segments = data[label] - for segment in segments: - result['shapes'].append({ - "type": "polygon", - "label_id": label, - "frame": segment[0], - "points": segment[1], - "z_order": 0, - "group": None, - "occluded": False, - "attributes": [], - }) - - return result - -def create_thread(tid, labels_mapping, user): - try: - # If detected object accuracy bigger than threshold it will returend - TRESHOLD = 0.5 - # Init rq job - job = rq.get_current_job() - job.meta['progress'] = 0 - job.save_meta() - # Get job indexes and segment length - db_task = TaskModel.objects.get(pk=tid) - # Get image list - frame_provider = FrameProvider(db_task.data) - - # Run auto segmentation by tf - result = None - slogger.glob.info("auto segmentation with tensorflow framework for task {}".format(tid)) - result = run_tensorflow_auto_segmentation(frame_provider, labels_mapping, TRESHOLD) - - if result is None: - slogger.glob.info('auto segmentation for task {} canceled by user'.format(tid)) - return - - # Modify data format and save - result = convert_to_cvat_format(result) - serializer = LabeledDataSerializer(data = result) - if serializer.is_valid(raise_exception=True): - put_task_data(tid, result) - slogger.glob.info('auto segmentation for task {} done'.format(tid)) - except Exception as ex: - try: - slogger.task[tid].exception('exception was occured during auto segmentation of the task', exc_info=True) - except Exception: - slogger.glob.exception('exception was occured during auto segmentation of the task {}'.format(tid), exc_info=True) - raise ex - -@api_view(['POST']) -@login_required -def get_meta_info(request): - try: - queue = django_rq.get_queue('low') - tids = request.data - result = {} - for tid in tids: - job = queue.fetch_job('auto_segmentation.create/{}'.format(tid)) - if job is not None: - result[tid] = { - "active": job.is_queued or job.is_started, - "success": not job.is_failed - } - - return JsonResponse(result) - except Exception as ex: - slogger.glob.exception('exception was occured during tf meta request', exc_info=True) - return HttpResponseBadRequest(str(ex)) - - -@login_required -@permission_required(perm=['engine.task.change'], - fn=objectgetter(TaskModel, 'tid'), raise_exception=True) -def create(request, tid): - slogger.glob.info('auto segmentation create request for task {}'.format(tid)) - try: - db_task = TaskModel.objects.get(pk=tid) - queue = django_rq.get_queue('low') - job = queue.fetch_job('auto_segmentation.create/{}'.format(tid)) - if job is not None and (job.is_started or job.is_queued): - raise Exception("The process is already running") - - db_labels = db_task.label_set.prefetch_related('attributespec_set').all() - db_labels = {db_label.id:db_label.name for db_label in db_labels} - - # COCO Labels - auto_segmentation_labels = { "BG": 0, - "person": 1, "bicycle": 2, "car": 3, "motorcycle": 4, "airplane": 5, - "bus": 6, "train": 7, "truck": 8, "boat": 9, "traffic_light": 10, - "fire_hydrant": 11, "stop_sign": 12, "parking_meter": 13, "bench": 14, - "bird": 15, "cat": 16, "dog": 17, "horse": 18, "sheep": 19, "cow": 20, - "elephant": 21, "bear": 22, "zebra": 23, "giraffe": 24, "backpack": 25, - "umbrella": 26, "handbag": 27, "tie": 28, "suitcase": 29, "frisbee": 30, - "skis": 31, "snowboard": 32, "sports_ball": 33, "kite": 34, "baseball_bat": 35, - "baseball_glove": 36, "skateboard": 37, "surfboard": 38, "tennis_racket": 39, - "bottle": 40, "wine_glass": 41, "cup": 42, "fork": 43, "knife": 44, "spoon": 45, - "bowl": 46, "banana": 47, "apple": 48, "sandwich": 49, "orange": 50, "broccoli": 51, - "carrot": 52, "hot_dog": 53, "pizza": 54, "donut": 55, "cake": 56, "chair": 57, - "couch": 58, "potted_plant": 59, "bed": 60, "dining_table": 61, "toilet": 62, - "tv": 63, "laptop": 64, "mouse": 65, "remote": 66, "keyboard": 67, "cell_phone": 68, - "microwave": 69, "oven": 70, "toaster": 71, "sink": 72, "refrigerator": 73, - "book": 74, "clock": 75, "vase": 76, "scissors": 77, "teddy_bear": 78, "hair_drier": 79, - "toothbrush": 80 - } - - labels_mapping = {} - for key, labels in db_labels.items(): - if labels in auto_segmentation_labels.keys(): - labels_mapping[auto_segmentation_labels[labels]] = key - - if not len(labels_mapping.values()): - raise Exception('No labels found for auto segmentation') - - # Run auto segmentation job - queue.enqueue_call(func=create_thread, - args=(tid, labels_mapping, request.user), - job_id='auto_segmentation.create/{}'.format(tid), - timeout=604800) # 7 days - - slogger.task[tid].info('tensorflow segmentation job enqueued with labels {}'.format(labels_mapping)) - - except Exception as ex: - try: - slogger.task[tid].exception("exception was occured during tensorflow segmentation request", exc_info=True) - except Exception: - pass - return HttpResponseBadRequest(str(ex)) - - return HttpResponse() - -@login_required -@permission_required(perm=['engine.task.access'], - fn=objectgetter(TaskModel, 'tid'), raise_exception=True) -def check(request, tid): - try: - queue = django_rq.get_queue('low') - job = queue.fetch_job('auto_segmentation.create/{}'.format(tid)) - if job is not None and 'cancel' in job.meta: - return JsonResponse({'status': 'finished'}) - data = {} - if job is None: - data['status'] = 'unknown' - elif job.is_queued: - data['status'] = 'queued' - elif job.is_started: - data['status'] = 'started' - data['progress'] = job.meta['progress'] - elif job.is_finished: - data['status'] = 'finished' - job.delete() - else: - data['status'] = 'failed' - data['stderr'] = job.exc_info - job.delete() - - except Exception: - data['status'] = 'unknown' - - return JsonResponse(data) - - -@login_required -@permission_required(perm=['engine.task.change'], - fn=objectgetter(TaskModel, 'tid'), raise_exception=True) -def cancel(request, tid): - try: - queue = django_rq.get_queue('low') - job = queue.fetch_job('auto_segmentation.create/{}'.format(tid)) - if job is None or job.is_finished or job.is_failed: - raise Exception('Task is not being segmented currently') - elif 'cancel' not in job.meta: - job.meta['cancel'] = True - job.save() - - except Exception as ex: - try: - slogger.task[tid].exception("cannot cancel tensorflow segmentation for task #{}".format(tid), exc_info=True) - except Exception: - pass - return HttpResponseBadRequest(str(ex)) - - return HttpResponse()