From 105669886f1ceee59f7163e103d36770ff8bd3a5 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Fri, 7 Jun 2024 15:40:26 +0200 Subject: [PATCH 01/17] Add workflow output --- annotation-tool/src/main.py | 15 ++++++++++----- dev_requirements.txt | 3 --- requirements.txt | 3 +++ 3 files changed, 13 insertions(+), 8 deletions(-) delete mode 100644 dev_requirements.txt create mode 100644 requirements.txt diff --git a/annotation-tool/src/main.py b/annotation-tool/src/main.py index c6be956..bcdf93a 100644 --- a/annotation-tool/src/main.py +++ b/annotation-tool/src/main.py @@ -1,22 +1,25 @@ import os -import yaml import pathlib import sys from collections import defaultdict + import supervisely as sly -from supervisely.imaging.color import random_rgb, generate_rgb +import yaml +from supervisely.imaging.color import generate_rgb, random_rgb root_source_path = str(pathlib.Path(sys.argv[0]).parents[2]) sly.logger.info(f"Root source directory: {root_source_path}") sys.path.append(root_source_path) +import io + +import ruamel.yaml +from dotenv import load_dotenv from init_ui import init_ui + from shared_utils.connect import get_model_info from shared_utils.inference import postprocess from shared_utils.ui2 import set_error -from dotenv import load_dotenv -import ruamel.yaml -import io if sly.is_development(): load_dotenv(os.path.expanduser("~/supervisely.env")) @@ -440,6 +443,7 @@ def inference(api: sly.Api, task_id, context, state, app_logger): {"field": "state.processing", "payload": False}, ] api.task.set_fields(task_id, fields) + api.app.add_output_project(project_id) @my_app.callback("undo") @@ -457,6 +461,7 @@ def undo(api: sly.Api, task_id, context, state, app_logger): {"field": "state.processing", "payload": False}, ] api.task.set_fields(task_id, fields) + # ? do we need to add output project here, cuz undo will be for the same project def main(): diff --git a/dev_requirements.txt b/dev_requirements.txt deleted file mode 100644 index c51d2cd..0000000 --- a/dev_requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -supervisely==6.73.60 -matplotlib>=3.3.2, <4.0.0 -imgaug>=0.4.0, <1.0.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e1146b6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +git+https://github.com/supervisely/supervisely.git@app-workflow +matplotlib>=3.3.2, <4.0.0 +imgaug>=0.4.0, <1.0.0 \ No newline at end of file From 76959a255f69d159416f56206f6e9a8e4382e238 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Fri, 21 Jun 2024 20:52:11 +0200 Subject: [PATCH 02/17] Add output task workflow --- annotation-tool/src/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/annotation-tool/src/main.py b/annotation-tool/src/main.py index 5927baa..a5e3933 100644 --- a/annotation-tool/src/main.py +++ b/annotation-tool/src/main.py @@ -451,6 +451,7 @@ def inference(api: sly.Api, task_id, context, state, app_logger): ] api.task.set_fields(task_id, fields) api.app.add_output_project(project_id) + api.app.add_output_task(task_id) @my_app.callback("undo") From f0e2bbc17b77a6341bcca82ab4cd616478f490aa Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Fri, 21 Jun 2024 21:13:39 +0200 Subject: [PATCH 03/17] Update main.py to use session ID for output task workflow --- annotation-tool/src/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/annotation-tool/src/main.py b/annotation-tool/src/main.py index a5e3933..623c045 100644 --- a/annotation-tool/src/main.py +++ b/annotation-tool/src/main.py @@ -451,7 +451,7 @@ def inference(api: sly.Api, task_id, context, state, app_logger): ] api.task.set_fields(task_id, fields) api.app.add_output_project(project_id) - api.app.add_output_task(task_id) + api.app.add_output_task(int(state["sessionId"])) @my_app.callback("undo") From 1432738d5b7430b2d44fe9f5da267ef9d45093a2 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Tue, 25 Jun 2024 13:29:29 +0200 Subject: [PATCH 04/17] Add workflow input and output for project and task --- annotation-tool/src/main.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/annotation-tool/src/main.py b/annotation-tool/src/main.py index 623c045..d0b6116 100644 --- a/annotation-tool/src/main.py +++ b/annotation-tool/src/main.py @@ -128,6 +128,11 @@ def inference(api: sly.Api, task_id, context, state, app_logger): project_meta = sly.ProjectMeta.from_json(api.project.get_meta(project_id)) + # -------------------------------------- Add Workflow Input -------------------------------------- # + api.app.add_input_project(project_id) + api.app.add_input_task(int(state["sessionId"])) + # ----------------------------------------------- - ---------------------------------------------- # + if image_id not in ann_cache: # keep only current image for simplicity ann_cache.clear() @@ -450,8 +455,9 @@ def inference(api: sly.Api, task_id, context, state, app_logger): {"field": "state.processing", "payload": False}, ] api.task.set_fields(task_id, fields) + # -------------------------------------- Add Workflow Output ------------------------------------- # api.app.add_output_project(project_id) - api.app.add_output_task(int(state["sessionId"])) + # ----------------------------------------------- - ---------------------------------------------- # @my_app.callback("undo") From 5fa110d9b3a7a619a8db812598426b806a7dbbac Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Thu, 27 Jun 2024 00:16:28 +0200 Subject: [PATCH 05/17] Add Workflow class for input and output handling --- annotation-tool/src/main.py | 7 ++++--- annotation-tool/src/workflow.py | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 annotation-tool/src/workflow.py diff --git a/annotation-tool/src/main.py b/annotation-tool/src/main.py index d0b6116..14de6fe 100644 --- a/annotation-tool/src/main.py +++ b/annotation-tool/src/main.py @@ -6,6 +6,7 @@ import supervisely as sly import yaml from supervisely.imaging.color import generate_rgb, random_rgb +from workflow import Workflow root_source_path = str(pathlib.Path(sys.argv[0]).parents[2]) sly.logger.info(f"Root source directory: {root_source_path}") @@ -129,8 +130,7 @@ def inference(api: sly.Api, task_id, context, state, app_logger): project_meta = sly.ProjectMeta.from_json(api.project.get_meta(project_id)) # -------------------------------------- Add Workflow Input -------------------------------------- # - api.app.add_input_project(project_id) - api.app.add_input_task(int(state["sessionId"])) + Workflow.add_input(api, project_id, state) # ----------------------------------------------- - ---------------------------------------------- # if image_id not in ann_cache: @@ -455,8 +455,9 @@ def inference(api: sly.Api, task_id, context, state, app_logger): {"field": "state.processing", "payload": False}, ] api.task.set_fields(task_id, fields) + # -------------------------------------- Add Workflow Output ------------------------------------- # - api.app.add_output_project(project_id) + Workflow.add_output(api, project_id) # ----------------------------------------------- - ---------------------------------------------- # diff --git a/annotation-tool/src/workflow.py b/annotation-tool/src/workflow.py new file mode 100644 index 0000000..0cee36d --- /dev/null +++ b/annotation-tool/src/workflow.py @@ -0,0 +1,36 @@ +import supervisely as sly + + +def check_compatibility(func): + def wrapper(self, *args, **kwargs): + if self.is_compatible is None: + self.is_compatible = self.check_instance_ver_compatibility() + if not self.is_compatible: + return + return func(self, *args, **kwargs) + + return wrapper + + +class Workflow: + def __init__(self): + self.is_compatible = None + self._min_instance_version = "6.9.22" + + @check_compatibility + def add_input(self, api: sly.Api, project_id: int, state: dict): + if api.project.get_info_by_id(project_id).version: # to prevent cycled workflow + api.app.add_input_project(project_id) + api.app.add_input_task(int(state["sessionId"])) + + @check_compatibility + def add_output(self, api: sly.Api, project_id: int): + api.app.add_output_project(project_id) + + def check_instance_ver_compatibility(self, api: sly.Api): + if api.instance_version < self._min_instance_version: + sly.logger.info( + f"Supervisely instance version does not support workflow and versioning features. To use them, please update your instance minimum to version {self._min_instance_version}." + ) + return False + return True From 404aa7f5a16a8c141be55b2c4276722069af36f8 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Thu, 27 Jun 2024 01:02:11 +0200 Subject: [PATCH 06/17] Refactor Workflow class to use API instance and improve compatibility check --- annotation-tool/src/main.py | 5 +++-- annotation-tool/src/workflow.py | 23 +++++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/annotation-tool/src/main.py b/annotation-tool/src/main.py index 14de6fe..bf61c67 100644 --- a/annotation-tool/src/main.py +++ b/annotation-tool/src/main.py @@ -130,7 +130,8 @@ def inference(api: sly.Api, task_id, context, state, app_logger): project_meta = sly.ProjectMeta.from_json(api.project.get_meta(project_id)) # -------------------------------------- Add Workflow Input -------------------------------------- # - Workflow.add_input(api, project_id, state) + nn_workflow = Workflow(api) + nn_workflow.add_input(project_id, state) # ----------------------------------------------- - ---------------------------------------------- # if image_id not in ann_cache: @@ -457,7 +458,7 @@ def inference(api: sly.Api, task_id, context, state, app_logger): api.task.set_fields(task_id, fields) # -------------------------------------- Add Workflow Output ------------------------------------- # - Workflow.add_output(api, project_id) + nn_workflow.add_output(project_id) # ----------------------------------------------- - ---------------------------------------------- # diff --git a/annotation-tool/src/workflow.py b/annotation-tool/src/workflow.py index 0cee36d..bce8ef1 100644 --- a/annotation-tool/src/workflow.py +++ b/annotation-tool/src/workflow.py @@ -13,22 +13,25 @@ def wrapper(self, *args, **kwargs): class Workflow: - def __init__(self): + def __init__(self, api: sly.Api, min_instance_version: str = None): self.is_compatible = None - self._min_instance_version = "6.9.22" + self.api = api + self._min_instance_version = ( + "6.9.22" if min_instance_version is None else min_instance_version + ) @check_compatibility - def add_input(self, api: sly.Api, project_id: int, state: dict): - if api.project.get_info_by_id(project_id).version: # to prevent cycled workflow - api.app.add_input_project(project_id) - api.app.add_input_task(int(state["sessionId"])) + def add_input(self, project_id: int, state: dict): + if self.api.project.get_info_by_id(project_id).version: # to prevent cycled workflow + self.api.app.add_input_project(project_id) + self.api.app.add_input_task(int(state["sessionId"])) @check_compatibility - def add_output(self, api: sly.Api, project_id: int): - api.app.add_output_project(project_id) + def add_output(self, project_id: int): + self.api.app.add_output_project(project_id) - def check_instance_ver_compatibility(self, api: sly.Api): - if api.instance_version < self._min_instance_version: + def check_instance_ver_compatibility(self): + if self.api.instance_version < self._min_instance_version: sly.logger.info( f"Supervisely instance version does not support workflow and versioning features. To use them, please update your instance minimum to version {self._min_instance_version}." ) From bcb72609ab502677629f1c8b7ef362a079f0e1f1 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Mon, 8 Jul 2024 12:52:50 +0200 Subject: [PATCH 07/17] Refactor Workflow Update SDK verion to v6.73.123 --- annotation-tool/src/workflow.py | 8 ++++---- dev_requirements.txt | 3 +++ project-dataset/config.json | 7 ++----- requirements.txt | 3 --- 4 files changed, 9 insertions(+), 12 deletions(-) create mode 100644 dev_requirements.txt delete mode 100644 requirements.txt diff --git a/annotation-tool/src/workflow.py b/annotation-tool/src/workflow.py index bce8ef1..451f49a 100644 --- a/annotation-tool/src/workflow.py +++ b/annotation-tool/src/workflow.py @@ -17,18 +17,18 @@ def __init__(self, api: sly.Api, min_instance_version: str = None): self.is_compatible = None self.api = api self._min_instance_version = ( - "6.9.22" if min_instance_version is None else min_instance_version + "6.9.31" if min_instance_version is None else min_instance_version ) @check_compatibility def add_input(self, project_id: int, state: dict): if self.api.project.get_info_by_id(project_id).version: # to prevent cycled workflow - self.api.app.add_input_project(project_id) - self.api.app.add_input_task(int(state["sessionId"])) + self.api.app.workflow.add_input_project(project_id) + self.api.app.workflow.add_input_task(int(state["sessionId"])) @check_compatibility def add_output(self, project_id: int): - self.api.app.add_output_project(project_id) + self.api.app.workflow.add_output_project(project_id) def check_instance_ver_compatibility(self): if self.api.instance_version < self._min_instance_version: diff --git a/dev_requirements.txt b/dev_requirements.txt new file mode 100644 index 0000000..a20cb05 --- /dev/null +++ b/dev_requirements.txt @@ -0,0 +1,3 @@ +supervisely==6.73.123 +matplotlib>=3.3.2, <4.0.0 +imgaug>=0.4.0, <1.0.0 \ No newline at end of file diff --git a/project-dataset/config.json b/project-dataset/config.json index 771f131..85228a1 100644 --- a/project-dataset/config.json +++ b/project-dataset/config.json @@ -12,7 +12,7 @@ "labeling" ], "description": "NN Inference on images in project or dataset", - "docker_image": "supervisely/labeling:6.73.104", + "docker_image": "supervisely/labeling:6.73.123", "min_instance_version": "6.9.4", "entrypoint": "python -m uvicorn project-dataset.src.main:app --host 0.0.0.0 --port 8000", "task_location": "workspace_tasks", @@ -21,10 +21,7 @@ "icon": "https://i.imgur.com/KdCigmp.png", "icon_background": "#FFFFFF", "context_menu": { - "target": [ - "images_project", - "images_dataset" - ], + "target": ["images_project", "images_dataset"], "context_root": "Neural Networks" }, "poster": "https://user-images.githubusercontent.com/106374579/187227957-ea4fd452-35ef-4969-9e55-cd7a5a4873ee.png" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 22bb041..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -git+https://github.com/supervisely/supervisely.git@workflow+versions -matplotlib>=3.3.2, <4.0.0 -imgaug>=0.4.0, <1.0.0 \ No newline at end of file From f26d53a46f19f09a93bafe18c27e4edcf46fe1c9 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Tue, 9 Jul 2024 11:45:02 +0200 Subject: [PATCH 08/17] add Workflow --- annotation-tool/src/workflow.py | 2 +- project-dataset/src/globals.py | 5 +++ project-dataset/src/ui/input_data.py | 1 + project-dataset/src/ui/output_data.py | 28 ++++++++++++++-- project-dataset/src/workflow.py | 47 +++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 project-dataset/src/workflow.py diff --git a/annotation-tool/src/workflow.py b/annotation-tool/src/workflow.py index 451f49a..67246fe 100644 --- a/annotation-tool/src/workflow.py +++ b/annotation-tool/src/workflow.py @@ -33,7 +33,7 @@ def add_output(self, project_id: int): def check_instance_ver_compatibility(self): if self.api.instance_version < self._min_instance_version: sly.logger.info( - f"Supervisely instance version does not support workflow and versioning features. To use them, please update your instance minimum to version {self._min_instance_version}." + f"Supervisely instance version does not support workflow features. To use them, please update your instance minimum to version {self._min_instance_version}." ) return False return True diff --git a/project-dataset/src/globals.py b/project-dataset/src/globals.py index e15cb8a..0353503 100644 --- a/project-dataset/src/globals.py +++ b/project-dataset/src/globals.py @@ -2,6 +2,7 @@ import supervisely as sly from dotenv import load_dotenv +from src.workflow import Workflow ABSOLUTE_PATH = os.path.dirname(os.path.abspath(__file__)) PARENT_DIR = os.path.dirname(ABSOLUTE_PATH) @@ -22,6 +23,9 @@ ) api = sly.Api.from_env() + +workflow = Workflow(api) + if dataset_id: dataset_info = api.dataset.get_info_by_id(dataset_id) project_id = dataset_info.project_id @@ -29,6 +33,7 @@ # region ui-settings selected_project = None selected_datasets = None +all_datasets_selected = None # for workflow. Output: bool model_session_id = None model_meta = None inference_settings = None diff --git a/project-dataset/src/ui/input_data.py b/project-dataset/src/ui/input_data.py index 2052358..7ea296f 100644 --- a/project-dataset/src/ui/input_data.py +++ b/project-dataset/src/ui/input_data.py @@ -55,6 +55,7 @@ def datasets_selected() -> None: connect_nn.card.uncollapse() card.lock() change_button.show() + g.all_datasets_selected = select_dataset._all_datasets_checkbox.is_checked() @change_button.click diff --git a/project-dataset/src/ui/output_data.py b/project-dataset/src/ui/output_data.py index b00f3c5..2d256ed 100644 --- a/project-dataset/src/ui/output_data.py +++ b/project-dataset/src/ui/output_data.py @@ -2,6 +2,7 @@ import supervisely as sly import yaml +from src.globals import workflow from supervisely.app.widgets import Button, Card, Container, Input, Progress, ProjectThumbnail g = importlib.import_module("project-dataset.src.globals") @@ -35,6 +36,7 @@ def apply_model_ds(src_project, dst_project, inference_settings, res_project_met timer = {} dst_dataset_infos = [] + add_output = True # for workflow output try: # 1. Create destination datasets selected_datasets = g.selected_datasets @@ -143,8 +145,14 @@ def apply_model_ds(src_project, dst_project, inference_settings, res_project_met t = time.time() except Exception: g.api.dataset.remove_batch([ds.id for ds in dst_dataset_infos]) + add_output = False raise finally: + # -------------------------------------- Add Workflow Output ------------------------------------- # + if not g.all_datasets_selected and add_output: + for dataset_info in dst_dataset_infos: + workflow.add_output(dataset_id=dataset_info.id) + # ----------------------------------------------- - ---------------------------------------------- # sly.logger.debug("Timer:", extra={"timer": timer}) @@ -168,6 +176,12 @@ def apply_model(): ) g.api.project.update_meta(res_project.id, res_project_meta.to_json()) + # -------------------------------------- Add Workflow Input -------------------------------------- # + workflow.add_input(session_id=g.model_session_id) + if g.all_datasets_selected: + workflow.add_input(project_id=g.selected_project) + # ----------------------------------------------- - ---------------------------------------------- # + try: apply_model_ds(g.selected_project, res_project, inference_settings, res_project_meta) except Exception as e: @@ -179,6 +193,10 @@ def apply_model(): with inference_progress(message="Processing images...", total=len(g.input_images)) as pbar: for dataset_id in g.selected_datasets: dataset_info = g.api.dataset.get_info_by_id(dataset_id) + # -------------------------------------- Add Workflow Input -------------------------------------- # + if not g.all_datasets_selected: + workflow.add_input(dataset_id=dataset_id) + # ----------------------------------------------- - ---------------------------------------------- # res_dataset = g.api.dataset.create( res_project.id, dataset_info.name, dataset_info.description ) @@ -249,10 +267,16 @@ def apply_model(): ) continue pbar.update(len(batched_image_infos)) - + # -------------------------------------- Add Workflow Output ------------------------------------- # + if not g.all_datasets_selected: + workflow.add_output(dataset_id=res_dataset.id) + # ----------------------------------------------- - ---------------------------------------------- # output_project_thumbnail.set(g.api.project.get_info_by_id(res_project.id)) output_project_thumbnail.show() - + # -------------------------------------- Add Workflow Output ------------------------------------- # + if g.all_datasets_selected: + workflow.add_output(project_id=res_project.id) + # ----------------------------------------------- - ---------------------------------------------- # main = importlib.import_module("project-dataset.src.main") main.app.stop() diff --git a/project-dataset/src/workflow.py b/project-dataset/src/workflow.py new file mode 100644 index 0000000..3db073f --- /dev/null +++ b/project-dataset/src/workflow.py @@ -0,0 +1,47 @@ +import supervisely as sly + + +def check_compatibility(func): + def wrapper(self, *args, **kwargs): + if self.is_compatible is None: + self.is_compatible = self.check_instance_ver_compatibility() + if not self.is_compatible: + return + return func(self, *args, **kwargs) + + return wrapper + + +class Workflow: + def __init__(self, api: sly.Api, min_instance_version: str = None): + self.is_compatible = None + self.api = api + self._min_instance_version = ( + "6.9.31" if min_instance_version is None else min_instance_version + ) + + def check_instance_ver_compatibility(self): + if self.api.instance_version < self._min_instance_version: + sly.logger.info( + f"Supervisely instance version does not support workflow features. To use them, please update your instance minimum to version {self._min_instance_version}." + ) + return False + return True + + @check_compatibility + def add_input(self, project_id: int = None, session_id: int = None, dataset_id: int = None): + if session_id is not None: + self.api.app.workflow.add_input_task(int(session_id)) + if dataset_id is not None: + self.api.app.workflow.add_input_dataset(dataset_id) + if ( + project_id and self.api.project.get_info_by_id(project_id).version + ): # to prevent cycled workflow + self.api.app.workflow.add_input_project(project_id) + + @check_compatibility + def add_output(self, project_id: int = None, dataset_id: int = None): + if project_id is not None: + self.api.app.workflow.add_output_project(project_id) + if dataset_id is not None: + self.api.app.workflow.add_output_dataset(dataset_id) From 3a2175feacc91aa26b56dfc7e307418f59f9fe9e Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Tue, 9 Jul 2024 11:54:30 +0200 Subject: [PATCH 09/17] fix import --- project-dataset/src/globals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project-dataset/src/globals.py b/project-dataset/src/globals.py index 0353503..4610d78 100644 --- a/project-dataset/src/globals.py +++ b/project-dataset/src/globals.py @@ -2,7 +2,7 @@ import supervisely as sly from dotenv import load_dotenv -from src.workflow import Workflow +from workflow import Workflow ABSOLUTE_PATH = os.path.dirname(os.path.abspath(__file__)) PARENT_DIR = os.path.dirname(ABSOLUTE_PATH) From e55c30de41f153ee5c84de4ef272ab2f9a55a596 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Tue, 9 Jul 2024 11:58:20 +0200 Subject: [PATCH 10/17] fix import --- project-dataset/src/globals.py | 5 ++++- project-dataset/src/ui/output_data.py | 13 ++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/project-dataset/src/globals.py b/project-dataset/src/globals.py index 4610d78..d8e7391 100644 --- a/project-dataset/src/globals.py +++ b/project-dataset/src/globals.py @@ -1,9 +1,12 @@ +import importlib import os import supervisely as sly from dotenv import load_dotenv from workflow import Workflow +w = importlib.import_module("project-dataset.src.workflow") + ABSOLUTE_PATH = os.path.dirname(os.path.abspath(__file__)) PARENT_DIR = os.path.dirname(ABSOLUTE_PATH) STATIC_DIR = os.path.join(PARENT_DIR, "temp") @@ -24,7 +27,7 @@ api = sly.Api.from_env() -workflow = Workflow(api) +workflow = w.Workflow(api) if dataset_id: dataset_info = api.dataset.get_info_by_id(dataset_id) diff --git a/project-dataset/src/ui/output_data.py b/project-dataset/src/ui/output_data.py index 2d256ed..3d30387 100644 --- a/project-dataset/src/ui/output_data.py +++ b/project-dataset/src/ui/output_data.py @@ -2,7 +2,6 @@ import supervisely as sly import yaml -from src.globals import workflow from supervisely.app.widgets import Button, Card, Container, Input, Progress, ProjectThumbnail g = importlib.import_module("project-dataset.src.globals") @@ -151,7 +150,7 @@ def apply_model_ds(src_project, dst_project, inference_settings, res_project_met # -------------------------------------- Add Workflow Output ------------------------------------- # if not g.all_datasets_selected and add_output: for dataset_info in dst_dataset_infos: - workflow.add_output(dataset_id=dataset_info.id) + g.workflow.add_output(dataset_id=dataset_info.id) # ----------------------------------------------- - ---------------------------------------------- # sly.logger.debug("Timer:", extra={"timer": timer}) @@ -177,9 +176,9 @@ def apply_model(): g.api.project.update_meta(res_project.id, res_project_meta.to_json()) # -------------------------------------- Add Workflow Input -------------------------------------- # - workflow.add_input(session_id=g.model_session_id) + g.workflow.add_input(session_id=g.model_session_id) if g.all_datasets_selected: - workflow.add_input(project_id=g.selected_project) + g.workflow.add_input(project_id=g.selected_project) # ----------------------------------------------- - ---------------------------------------------- # try: @@ -195,7 +194,7 @@ def apply_model(): dataset_info = g.api.dataset.get_info_by_id(dataset_id) # -------------------------------------- Add Workflow Input -------------------------------------- # if not g.all_datasets_selected: - workflow.add_input(dataset_id=dataset_id) + g.workflow.add_input(dataset_id=dataset_id) # ----------------------------------------------- - ---------------------------------------------- # res_dataset = g.api.dataset.create( res_project.id, dataset_info.name, dataset_info.description @@ -269,13 +268,13 @@ def apply_model(): pbar.update(len(batched_image_infos)) # -------------------------------------- Add Workflow Output ------------------------------------- # if not g.all_datasets_selected: - workflow.add_output(dataset_id=res_dataset.id) + g.workflow.add_output(dataset_id=res_dataset.id) # ----------------------------------------------- - ---------------------------------------------- # output_project_thumbnail.set(g.api.project.get_info_by_id(res_project.id)) output_project_thumbnail.show() # -------------------------------------- Add Workflow Output ------------------------------------- # if g.all_datasets_selected: - workflow.add_output(project_id=res_project.id) + g.workflow.add_output(project_id=res_project.id) # ----------------------------------------------- - ---------------------------------------------- # main = importlib.import_module("project-dataset.src.main") From f87cb0b3193b742c065c7e740b1723d735e4f858 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Tue, 9 Jul 2024 12:09:47 +0200 Subject: [PATCH 11/17] fix imports --- project-dataset/src/globals.py | 1 - 1 file changed, 1 deletion(-) diff --git a/project-dataset/src/globals.py b/project-dataset/src/globals.py index d8e7391..99bdb31 100644 --- a/project-dataset/src/globals.py +++ b/project-dataset/src/globals.py @@ -3,7 +3,6 @@ import supervisely as sly from dotenv import load_dotenv -from workflow import Workflow w = importlib.import_module("project-dataset.src.workflow") From 33722ea954415b1413b6c50b29a010911c4029b5 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Tue, 9 Jul 2024 21:20:27 +0200 Subject: [PATCH 12/17] Refactor Workflow not to use datasets --- project-dataset/src/globals.py | 1 - project-dataset/src/ui/output_data.py | 20 ++++---------------- project-dataset/src/workflow.py | 14 ++++++-------- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/project-dataset/src/globals.py b/project-dataset/src/globals.py index 99bdb31..3fcb1fb 100644 --- a/project-dataset/src/globals.py +++ b/project-dataset/src/globals.py @@ -35,7 +35,6 @@ # region ui-settings selected_project = None selected_datasets = None -all_datasets_selected = None # for workflow. Output: bool model_session_id = None model_meta = None inference_settings = None diff --git a/project-dataset/src/ui/output_data.py b/project-dataset/src/ui/output_data.py index 3d30387..a012a2a 100644 --- a/project-dataset/src/ui/output_data.py +++ b/project-dataset/src/ui/output_data.py @@ -148,9 +148,8 @@ def apply_model_ds(src_project, dst_project, inference_settings, res_project_met raise finally: # -------------------------------------- Add Workflow Output ------------------------------------- # - if not g.all_datasets_selected and add_output: - for dataset_info in dst_dataset_infos: - g.workflow.add_output(dataset_id=dataset_info.id) + if add_output: + g.workflow.add_output(project_id=dst_project.id) # ----------------------------------------------- - ---------------------------------------------- # sly.logger.debug("Timer:", extra={"timer": timer}) @@ -176,9 +175,7 @@ def apply_model(): g.api.project.update_meta(res_project.id, res_project_meta.to_json()) # -------------------------------------- Add Workflow Input -------------------------------------- # - g.workflow.add_input(session_id=g.model_session_id) - if g.all_datasets_selected: - g.workflow.add_input(project_id=g.selected_project) + g.workflow.add_input(project_id=g.selected_project, session_id=g.model_session_id) # ----------------------------------------------- - ---------------------------------------------- # try: @@ -192,10 +189,6 @@ def apply_model(): with inference_progress(message="Processing images...", total=len(g.input_images)) as pbar: for dataset_id in g.selected_datasets: dataset_info = g.api.dataset.get_info_by_id(dataset_id) - # -------------------------------------- Add Workflow Input -------------------------------------- # - if not g.all_datasets_selected: - g.workflow.add_input(dataset_id=dataset_id) - # ----------------------------------------------- - ---------------------------------------------- # res_dataset = g.api.dataset.create( res_project.id, dataset_info.name, dataset_info.description ) @@ -266,15 +259,10 @@ def apply_model(): ) continue pbar.update(len(batched_image_infos)) - # -------------------------------------- Add Workflow Output ------------------------------------- # - if not g.all_datasets_selected: - g.workflow.add_output(dataset_id=res_dataset.id) - # ----------------------------------------------- - ---------------------------------------------- # output_project_thumbnail.set(g.api.project.get_info_by_id(res_project.id)) output_project_thumbnail.show() # -------------------------------------- Add Workflow Output ------------------------------------- # - if g.all_datasets_selected: - g.workflow.add_output(project_id=res_project.id) + g.workflow.add_output(project_id=res_project.id) # ----------------------------------------------- - ---------------------------------------------- # main = importlib.import_module("project-dataset.src.main") diff --git a/project-dataset/src/workflow.py b/project-dataset/src/workflow.py index 3db073f..4bd3cca 100644 --- a/project-dataset/src/workflow.py +++ b/project-dataset/src/workflow.py @@ -29,19 +29,17 @@ def check_instance_ver_compatibility(self): return True @check_compatibility - def add_input(self, project_id: int = None, session_id: int = None, dataset_id: int = None): + def add_input(self, project_id: int = None, session_id: int = None): if session_id is not None: + sly.logger.debug(f"Workflow Input: Session ID - {session_id}") self.api.app.workflow.add_input_task(int(session_id)) - if dataset_id is not None: - self.api.app.workflow.add_input_dataset(dataset_id) if ( project_id and self.api.project.get_info_by_id(project_id).version ): # to prevent cycled workflow + sly.logger.debug(f"Workflow Input: Project ID - {project_id}") self.api.app.workflow.add_input_project(project_id) @check_compatibility - def add_output(self, project_id: int = None, dataset_id: int = None): - if project_id is not None: - self.api.app.workflow.add_output_project(project_id) - if dataset_id is not None: - self.api.app.workflow.add_output_dataset(dataset_id) + def add_output(self, project_id: int): + sly.logger.debug(f"Workflow Output: Project ID - {project_id}") + self.api.app.workflow.add_output_project(project_id) From d918a09d1eb553722809d3bc0487a288ddd8d5e0 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Wed, 10 Jul 2024 00:15:17 +0200 Subject: [PATCH 13/17] Fix check instance version compatibility --- annotation-tool/src/workflow.py | 20 ++++++++++++-------- project-dataset/src/workflow.py | 8 ++++++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/annotation-tool/src/workflow.py b/annotation-tool/src/workflow.py index 67246fe..c3b61cb 100644 --- a/annotation-tool/src/workflow.py +++ b/annotation-tool/src/workflow.py @@ -20,6 +20,18 @@ def __init__(self, api: sly.Api, min_instance_version: str = None): "6.9.31" if min_instance_version is None else min_instance_version ) + def check_instance_ver_compatibility(self): + if not self.api.is_version_supported(self._min_instance_version): + sly.logger.info( + f"Supervisely instance version {self.api.instance_version} does not support workflow features." + ) + if not sly.is_community(): + sly.logger.info( + f"To use them, please update your instance to version {self._min_instance_version} or higher." + ) + return False + return True + @check_compatibility def add_input(self, project_id: int, state: dict): if self.api.project.get_info_by_id(project_id).version: # to prevent cycled workflow @@ -29,11 +41,3 @@ def add_input(self, project_id: int, state: dict): @check_compatibility def add_output(self, project_id: int): self.api.app.workflow.add_output_project(project_id) - - def check_instance_ver_compatibility(self): - if self.api.instance_version < self._min_instance_version: - sly.logger.info( - f"Supervisely instance version does not support workflow features. To use them, please update your instance minimum to version {self._min_instance_version}." - ) - return False - return True diff --git a/project-dataset/src/workflow.py b/project-dataset/src/workflow.py index 4bd3cca..08fbaf3 100644 --- a/project-dataset/src/workflow.py +++ b/project-dataset/src/workflow.py @@ -21,10 +21,14 @@ def __init__(self, api: sly.Api, min_instance_version: str = None): ) def check_instance_ver_compatibility(self): - if self.api.instance_version < self._min_instance_version: + if not self.api.is_version_supported(self._min_instance_version): sly.logger.info( - f"Supervisely instance version does not support workflow features. To use them, please update your instance minimum to version {self._min_instance_version}." + f"Supervisely instance version {self.api.instance_version} does not support workflow and versioning features." ) + if not sly.is_community(): + sly.logger.info( + f"To use them, please update your instance to version {self._min_instance_version} or higher." + ) return False return True From ca7f2f947ea554f951375d909f5ee098e17a8d2b Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Wed, 10 Jul 2024 01:28:17 +0200 Subject: [PATCH 14/17] Add debug logs for workflow --- annotation-tool/src/workflow.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/annotation-tool/src/workflow.py b/annotation-tool/src/workflow.py index c3b61cb..d144e6a 100644 --- a/annotation-tool/src/workflow.py +++ b/annotation-tool/src/workflow.py @@ -37,7 +37,9 @@ def add_input(self, project_id: int, state: dict): if self.api.project.get_info_by_id(project_id).version: # to prevent cycled workflow self.api.app.workflow.add_input_project(project_id) self.api.app.workflow.add_input_task(int(state["sessionId"])) + sly.logger.debug(f"Workflow Input: Project ID - {project_id}, Session ID - {int(state["sessionId"])}") @check_compatibility def add_output(self, project_id: int): self.api.app.workflow.add_output_project(project_id) + sly.logger.debug(f"Workflow Output: Project ID - {project_id}") From a089d662383f73ff7a5fce20807e1a226326e898 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Wed, 10 Jul 2024 12:11:24 +0200 Subject: [PATCH 15/17] Update log message --- project-dataset/src/workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project-dataset/src/workflow.py b/project-dataset/src/workflow.py index 08fbaf3..4a74682 100644 --- a/project-dataset/src/workflow.py +++ b/project-dataset/src/workflow.py @@ -23,7 +23,7 @@ def __init__(self, api: sly.Api, min_instance_version: str = None): def check_instance_ver_compatibility(self): if not self.api.is_version_supported(self._min_instance_version): sly.logger.info( - f"Supervisely instance version {self.api.instance_version} does not support workflow and versioning features." + f"Supervisely instance version {self.api.instance_version} does not support workflow features." ) if not sly.is_community(): sly.logger.info( From 98db39e749f4423c3539753d7ff8fae68c1889b5 Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Wed, 10 Jul 2024 14:16:58 +0200 Subject: [PATCH 16/17] Remove unnecessary code in Workflow --- project-dataset/src/ui/output_data.py | 6 ------ project-dataset/src/workflow.py | 4 +--- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/project-dataset/src/ui/output_data.py b/project-dataset/src/ui/output_data.py index a012a2a..3b52155 100644 --- a/project-dataset/src/ui/output_data.py +++ b/project-dataset/src/ui/output_data.py @@ -35,7 +35,6 @@ def apply_model_ds(src_project, dst_project, inference_settings, res_project_met timer = {} dst_dataset_infos = [] - add_output = True # for workflow output try: # 1. Create destination datasets selected_datasets = g.selected_datasets @@ -144,13 +143,8 @@ def apply_model_ds(src_project, dst_project, inference_settings, res_project_met t = time.time() except Exception: g.api.dataset.remove_batch([ds.id for ds in dst_dataset_infos]) - add_output = False raise finally: - # -------------------------------------- Add Workflow Output ------------------------------------- # - if add_output: - g.workflow.add_output(project_id=dst_project.id) - # ----------------------------------------------- - ---------------------------------------------- # sly.logger.debug("Timer:", extra={"timer": timer}) diff --git a/project-dataset/src/workflow.py b/project-dataset/src/workflow.py index 4a74682..9312a01 100644 --- a/project-dataset/src/workflow.py +++ b/project-dataset/src/workflow.py @@ -37,9 +37,7 @@ def add_input(self, project_id: int = None, session_id: int = None): if session_id is not None: sly.logger.debug(f"Workflow Input: Session ID - {session_id}") self.api.app.workflow.add_input_task(int(session_id)) - if ( - project_id and self.api.project.get_info_by_id(project_id).version - ): # to prevent cycled workflow + if project_id is not None: sly.logger.debug(f"Workflow Input: Project ID - {project_id}") self.api.app.workflow.add_input_project(project_id) From 403e78cd2da15322879d09a00f22d9762b9251db Mon Sep 17 00:00:00 2001 From: GoldenAnpu Date: Wed, 10 Jul 2024 14:31:28 +0200 Subject: [PATCH 17/17] Remove unnecessary var --- project-dataset/src/ui/input_data.py | 1 - 1 file changed, 1 deletion(-) diff --git a/project-dataset/src/ui/input_data.py b/project-dataset/src/ui/input_data.py index 7ea296f..2052358 100644 --- a/project-dataset/src/ui/input_data.py +++ b/project-dataset/src/ui/input_data.py @@ -55,7 +55,6 @@ def datasets_selected() -> None: connect_nn.card.uncollapse() card.lock() change_button.show() - g.all_datasets_selected = select_dataset._all_datasets_checkbox.is_checked() @change_button.click