Skip to content

Commit

Permalink
test
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolaiPetukhov committed Sep 21, 2023
1 parent ea5864c commit 26cd090
Show file tree
Hide file tree
Showing 57 changed files with 2,807 additions and 1,923 deletions.
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ git+https://github.com/supervisely/supervisely.git@NikolaiPetukhov
jsonschema
networkx
scikit-image>=0.17.1, <1.0.0
cacheout
cacheout
markdown
json2html
12 changes: 12 additions & 0 deletions src/globals.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import queue
from dotenv import load_dotenv

import supervisely as sly
Expand Down Expand Up @@ -29,3 +30,14 @@

layers_count = 0
layers = {}


update_queue = queue.Queue()


def updater(update: str):
global update_queue
update_queue.put(update)


context_menu_position = None
5 changes: 4 additions & 1 deletion src/main.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import shutil
import os
import threading
from supervisely import Application

from src.ui.ui import layout
from src.ui.ui import layout, update_loop
import src.globals as g

shutil.rmtree(g.STATIC_DIR, ignore_errors=True)
os.mkdir(g.STATIC_DIR)
app = Application(layout=layout, static_dir=g.STATIC_DIR)

update_loop.start()
13 changes: 4 additions & 9 deletions src/ui/dtl/Action.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,15 @@
from typing import Optional

from supervisely.app.widgets import NodesFlow, Container, Text
import src.globals as g


class Action:
name = None
title = None
docs_url = None
description = None
md_description = ""
width = 340
# when setting options from settings json, values from _settings_mapping will be mapped to options.
# If there is no option mapped directly to setting, set this option mapping to None and set the option value
# in set_settings_from_json function. If option name is different from setting name - set mapping in
# _settings_mapping below. If option name is the same as setting name - no need to set mapping.
_settings_mapping = {}

@classmethod
def create_new_layer(cls, layer_id: Optional[str] = None):
Expand All @@ -33,8 +28,8 @@ def create_outputs(cls):
def create_info_widget(cls):
return Container(
widgets=[
Text(f"<h3>{cls.title}</h3>", color="white"),
Text(f'<a href="{cls.docs_url}" target="_blank" style="color: white;">Docs</a>'),
Text(f"<p>{cls.description}</p>", color="white"),
Text(f"<h3>{cls.title}</h3>"),
Text(f'<a href="{cls.docs_url}" target="_blank">Docs</a>'),
Text(f"<p>{cls.description}</p>"),
]
)
229 changes: 122 additions & 107 deletions src/ui/dtl/Layer.py
Original file line number Diff line number Diff line change
@@ -1,70 +1,71 @@
import copy
from supervisely import Annotation
from supervisely.app.widgets import LabeledImage, NodesFlow
from supervisely.imaging.image import write as write_image
from src.ui.dtl.Action import Action


from typing import Optional
import json
import markdown
import json2html
import random
import numpy as np

from supervisely import Annotation
from supervisely.app.widgets import LabeledImage, NodesFlow, Text, Card
from supervisely.imaging.image import write as write_image

import random
from typing import List, Optional
from src.ui.dtl.Action import Action


class Layer:
def __init__(
self,
action: Action,
options: List[NodesFlow.Node.Option],
get_settings: callable,
create_options: callable,
get_src: Optional[callable] = None,
meta_changed_cb: Optional[callable] = None,
get_settings: Optional[callable] = None,
get_dst: Optional[callable] = None,
set_settings_from_json: callable = None,
meta_changed_cb: Optional[callable] = None,
id: Optional[str] = None,
):
self.action = action
self._id = id
if self._id is None:
self._id = action.name + "_" + "".join(random.choice("0123456789") for _ in range(8))
self.id = id
if self.id is None:
self.id = action.name + "_" + "".join(random.choice("0123456789") for _ in range(8))

self._options = options
self._create_options = create_options
self._get_settings = get_settings
self._get_src = get_src
self._meta_changed_cb = meta_changed_cb
self._get_dst = get_dst
self._set_settings_from_json = set_settings_from_json
self._meta_changed_cb = meta_changed_cb

self._src = []
self._settings = {}
self._dst = []

self.output_meta = None

self._preview_img_url = f"static/{self._id}.jpg"
self._ann = None

self._add_info_option()
self._add_preview_option()

def _add_info_option(self):
self._options = [
# info option
self._info_option = NodesFlow.Node.Option(
name="Info",
option_component=NodesFlow.ButtonOptionComponent(
sidebar_component=NodesFlow.HtmlOptionComponent(
markdown.markdown(self.action.md_description)
)
),
)
# settings preview option
self._settings_preview_widget = Text("", color="white")
self._settings_preview_options = [
NodesFlow.Node.Option(
name="Info",
option_component=NodesFlow.ButtonOptionComponent(
sidebar_component=NodesFlow.WidgetOptionComponent(
self.action.create_info_widget()
)
),
name="settings_text",
option_component=NodesFlow.TextOptionComponent("Settings"),
),
*self._options,
# NodesFlow.Node.Option(
# name="settings_preview",
# option_component=NodesFlow.WidgetOptionComponent(self._settings_preview_widget),
# ),
]

def _add_preview_option(self):
self._preview_widget = LabeledImage(enable_zoom=True)
self._options = [
*self._options,
# preview option
self._preview_img_url = f"static/{self.id}.jpg"
self._ann = None
self._preview_widget = LabeledImage(enable_zoom=True, view_height=250)
self._preview_options = [
NodesFlow.Node.Option(
name="preview_text", option_component=NodesFlow.TextOptionComponent("Preview")
),
Expand All @@ -74,6 +75,16 @@ def _add_preview_option(self):
),
]

def get_src(self) -> list:
return self._src

def get_dst(self) -> list:
return self._dst

def get_settings(self) -> dict:
return self._settings

# JSON
def to_json(self) -> dict:
return {
"action": self.action.name,
Expand All @@ -82,60 +93,76 @@ def to_json(self) -> dict:
"settings": self._settings,
}

def get_destination_name(self, dst_index: int):
outputs = self.action.create_outputs()
return outputs[dst_index].name

def set_settings_from_json(self, json_data: dict, node_state: dict):
node_state = copy.deepcopy(node_state)
settings = json_data["settings"]
for settings_key, value in settings.items():
node_state_key = self.action._settings_mapping.get(settings_key, settings_key)
if node_state_key is not None:
node_state[node_state_key] = value
if self._set_settings_from_json is not None:
node_state = self._set_settings_from_json(json_data, node_state)
return node_state

def from_json(self, json_data: dict = {}) -> None:
"""Init src, dst and settings from json data"""
src = json_data.get("src", [])
if isinstance(src, str):
src = [src]
self._src = src
dst = json_data.get("dst", [])
if isinstance(dst, str):
dst = [dst]
self._dst = dst
self._settings = json_data.get("settings", {})

# NodesFlow.Node
def create_node(self) -> NodesFlow.Node:
"""creates node from src, dst and settings"""
self._inputs = self.action.create_inputs()
self._outputs = self.action.create_outputs()
options = self._create_options(src=self._src, dst=self._dst, settings=self._settings)
return NodesFlow.Node(
id=self._id,
id=self.id,
name=self.action.title,
width=self.action.width,
options=self._options,
options=[
self._info_option,
*options["src"],
*options["dst"],
# *self._settings_preview_options,
*options["settings"],
*self._preview_options,
],
inputs=self._inputs,
outputs=self._outputs,
inputs_up=True,
)

def update_src(self, node_options: dict):
if self._get_src is not None:
self._src = self._get_src(options_json=node_options)
else:
self._src = []

def update_dst(self, node_options: dict):
if self._get_dst is not None:
self._dst = self._get_dst(options_json=node_options)
else:
self._dst = self._create_destinations()

def update_settings(self, node_options: dict):
if self._get_settings is not None:
self._settings = self._get_settings(options_json=node_options)
else:
self._settings = {}

def parse_options(self, node_options: dict):
self.update_src(node_options)
self.update_dst(node_options)
self.update_settings(node_options)
"""Read node options and init src, dst and settings"""
self._update_src(node_options)
self._update_dst(node_options)
self._update_settings(node_options)

def add_source(self, from_node_id, from_node_interface):
src_name = self._connection_name(from_node_id, from_node_interface)
self._src.append(src_name)

def update_settings_preview(self):
self._settings_preview_widget.text = json2html.json2html.convert(
json=json.dumps(self._settings)
)

def clear_preview(self):
self._preview_widget.clean_up()

def update_preview(self, img: np.ndarray, ann: Annotation):
write_image(self._preview_img_url, img)
self._ann = ann
self._preview_widget.set(title=None, image_url=self._preview_img_url, ann=self._ann)

def get_ann(self):
return self._ann

def update_project_meta(self, project_meta):
if self._meta_changed_cb is not None:
self._meta_changed_cb(project_meta)

# Utils
def get_destination_name(self, dst_index: int):
outputs = self.action.create_outputs()
return outputs[dst_index].name

def _connection_name(self, name: str, interface: str):
interface_str = "_".join(
[
Expand All @@ -149,36 +176,24 @@ def _connection_name(self, name: str, interface: str):
return "$" + name + (f"__{interface_str}" if interface_str else "")

def _create_destinations(self):
return [self._connection_name(self._id, output.name) for output in self._outputs]

def clear_sources(self):
self._src = []

def clear_destinations(self):
self._dst = []

def clear_settings(self):
self._settings = {}

def clear(self):
self.clear_sources()
self.clear_destinations()
self.clear_settings()
return [self._connection_name(self.id, output.name) for output in self._outputs]

def get_src(self):
return self._src

def get_dst(self):
return self._dst

def set_preview(self, img: np.ndarray, ann: Annotation):
write_image(self._preview_img_url, img)
self._ann = ann
self._preview_widget.set(title=None, image_url=self._preview_img_url, ann=self._ann)
def _update_src(self, node_options: dict):
if self._get_src is not None:
self._src = self._get_src(options_json=node_options)
else:
self._src = []

def get_ann(self):
return self._ann
def _update_dst(self, node_options: dict):
"""Read node options and init dst"""
if self._get_dst is not None:
self._dst = self._get_dst(options_json=node_options)
else:
self._dst = self._create_destinations()

def meta_changed_cb(self, project_meta):
if self._meta_changed_cb is not None:
self._meta_changed_cb(project_meta)
def _update_settings(self, node_options: dict):
"""Read node options and init settings"""
if self._get_settings is not None:
self._settings = self._get_settings(options_json=node_options)
else:
self._settings = {}
Loading

0 comments on commit 26cd090

Please sign in to comment.