supervisely 6.73.420__py3-none-any.whl → 6.73.421__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. supervisely/api/api.py +10 -5
  2. supervisely/api/app_api.py +71 -4
  3. supervisely/api/module_api.py +4 -0
  4. supervisely/api/nn/deploy_api.py +15 -9
  5. supervisely/api/nn/ecosystem_models_api.py +201 -0
  6. supervisely/api/nn/neural_network_api.py +12 -3
  7. supervisely/api/project_api.py +35 -6
  8. supervisely/api/task_api.py +5 -1
  9. supervisely/app/widgets/__init__.py +8 -1
  10. supervisely/app/widgets/agent_selector/template.html +1 -0
  11. supervisely/app/widgets/deploy_model/__init__.py +0 -0
  12. supervisely/app/widgets/deploy_model/deploy_model.py +729 -0
  13. supervisely/app/widgets/dropdown_checkbox_selector/__init__.py +0 -0
  14. supervisely/app/widgets/dropdown_checkbox_selector/dropdown_checkbox_selector.py +87 -0
  15. supervisely/app/widgets/dropdown_checkbox_selector/template.html +12 -0
  16. supervisely/app/widgets/ecosystem_model_selector/__init__.py +0 -0
  17. supervisely/app/widgets/ecosystem_model_selector/ecosystem_model_selector.py +190 -0
  18. supervisely/app/widgets/experiment_selector/experiment_selector.py +447 -264
  19. supervisely/app/widgets/fast_table/fast_table.py +402 -74
  20. supervisely/app/widgets/fast_table/script.js +364 -96
  21. supervisely/app/widgets/fast_table/style.css +24 -0
  22. supervisely/app/widgets/fast_table/template.html +43 -3
  23. supervisely/app/widgets/radio_table/radio_table.py +10 -2
  24. supervisely/app/widgets/select/select.py +6 -4
  25. supervisely/app/widgets/select_dataset_tree/select_dataset_tree.py +18 -0
  26. supervisely/app/widgets/tabs/tabs.py +22 -6
  27. supervisely/app/widgets/tabs/template.html +5 -1
  28. supervisely/nn/artifacts/__init__.py +1 -1
  29. supervisely/nn/artifacts/artifacts.py +10 -2
  30. supervisely/nn/artifacts/detectron2.py +1 -0
  31. supervisely/nn/artifacts/hrda.py +1 -0
  32. supervisely/nn/artifacts/mmclassification.py +20 -0
  33. supervisely/nn/artifacts/mmdetection.py +5 -3
  34. supervisely/nn/artifacts/mmsegmentation.py +1 -0
  35. supervisely/nn/artifacts/ritm.py +1 -0
  36. supervisely/nn/artifacts/rtdetr.py +1 -0
  37. supervisely/nn/artifacts/unet.py +1 -0
  38. supervisely/nn/artifacts/utils.py +3 -0
  39. supervisely/nn/artifacts/yolov5.py +2 -0
  40. supervisely/nn/artifacts/yolov8.py +1 -0
  41. supervisely/nn/benchmark/semantic_segmentation/metric_provider.py +18 -18
  42. supervisely/nn/experiments.py +9 -0
  43. supervisely/nn/inference/gui/serving_gui_template.py +39 -13
  44. supervisely/nn/inference/inference.py +160 -94
  45. supervisely/nn/inference/predict_app/__init__.py +0 -0
  46. supervisely/nn/inference/predict_app/gui/__init__.py +0 -0
  47. supervisely/nn/inference/predict_app/gui/classes_selector.py +91 -0
  48. supervisely/nn/inference/predict_app/gui/gui.py +710 -0
  49. supervisely/nn/inference/predict_app/gui/input_selector.py +165 -0
  50. supervisely/nn/inference/predict_app/gui/model_selector.py +79 -0
  51. supervisely/nn/inference/predict_app/gui/output_selector.py +139 -0
  52. supervisely/nn/inference/predict_app/gui/preview.py +93 -0
  53. supervisely/nn/inference/predict_app/gui/settings_selector.py +184 -0
  54. supervisely/nn/inference/predict_app/gui/tags_selector.py +110 -0
  55. supervisely/nn/inference/predict_app/gui/utils.py +282 -0
  56. supervisely/nn/inference/predict_app/predict_app.py +184 -0
  57. supervisely/nn/inference/uploader.py +9 -5
  58. supervisely/nn/model/prediction.py +2 -0
  59. supervisely/nn/model/prediction_session.py +20 -3
  60. supervisely/nn/training/gui/gui.py +131 -44
  61. supervisely/nn/training/gui/model_selector.py +8 -6
  62. supervisely/nn/training/gui/train_val_splits_selector.py +122 -70
  63. supervisely/nn/training/gui/training_artifacts.py +0 -5
  64. supervisely/nn/training/train_app.py +161 -44
  65. supervisely/template/experiment/experiment.html.jinja +74 -17
  66. supervisely/template/experiment/experiment_generator.py +258 -112
  67. supervisely/template/experiment/header.html.jinja +31 -13
  68. supervisely/template/experiment/sly-style.css +7 -2
  69. {supervisely-6.73.420.dist-info → supervisely-6.73.421.dist-info}/METADATA +3 -1
  70. {supervisely-6.73.420.dist-info → supervisely-6.73.421.dist-info}/RECORD +74 -56
  71. supervisely/app/widgets/experiment_selector/style.css +0 -27
  72. supervisely/app/widgets/experiment_selector/template.html +0 -61
  73. {supervisely-6.73.420.dist-info → supervisely-6.73.421.dist-info}/LICENSE +0 -0
  74. {supervisely-6.73.420.dist-info → supervisely-6.73.421.dist-info}/WHEEL +0 -0
  75. {supervisely-6.73.420.dist-info → supervisely-6.73.421.dist-info}/entry_points.txt +0 -0
  76. {supervisely-6.73.420.dist-info → supervisely-6.73.421.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,87 @@
1
+ from typing import List
2
+
3
+ from supervisely.app.content import DataJson, StateJson
4
+ from supervisely.app.widgets.widget import Widget
5
+
6
+
7
+ class DropdownCheckboxSelector(Widget):
8
+ class Routes:
9
+ VALUE_CHANGED = "value_changed"
10
+
11
+ class Item:
12
+ def __init__(self, id: str, name: str = None, description: str = None):
13
+ self.id = id
14
+ if name is None:
15
+ name = id
16
+ self.name = name
17
+ self.description = description
18
+
19
+ def to_json(self):
20
+ return {
21
+ "id": self.id,
22
+ "name": self.name,
23
+ "description": self.description,
24
+ }
25
+
26
+ @classmethod
27
+ def from_json(cls, data):
28
+ return cls(
29
+ id=data["id"],
30
+ name=data["name"],
31
+ description=data.get("description", None),
32
+ )
33
+
34
+ def __init__(
35
+ self, items: List[Item], label: str = None, widget_id: str = None, multiple: bool = True
36
+ ):
37
+ self._items = items
38
+ self._label = label
39
+ self._multiple = multiple
40
+ self._changes_handled = False
41
+
42
+ super().__init__(widget_id=widget_id, file_path=__file__)
43
+
44
+ def get_json_data(self):
45
+ return {
46
+ "items": [item.to_json() for item in self._items],
47
+ "label": self._label,
48
+ }
49
+
50
+ def get_json_state(self):
51
+ return {
52
+ "selected": [],
53
+ }
54
+
55
+ def set(self, items: List[Item]):
56
+ self._items = items
57
+ DataJson()[self.widget_id]["items"] = [
58
+ item.to_json() for item in self._items
59
+ ]
60
+ DataJson().send_changes()
61
+
62
+ def get_selected(self) -> List[Item]:
63
+ selected = StateJson()[self.widget_id].get("selected", [])
64
+ return [item for item in self._items if item.id in selected]
65
+
66
+ def select(self, ids: List[str]):
67
+ selected = [item for item in self._items if item.id in ids]
68
+ StateJson()[self.widget_id]["selected"] = [item.to_json() for item in selected]
69
+ StateJson().send_changes()
70
+
71
+ def value_changed(self, func):
72
+ """
73
+ Decorator to handle value changes.
74
+ :param func: function to call when value changes
75
+ """
76
+
77
+ route_path = self.get_route_path(self.Routes.VALUE_CHANGED)
78
+ server = self._sly_app.get_server()
79
+
80
+ @server.post(route_path)
81
+ def on_value_changed():
82
+ selected_items = self.get_selected()
83
+ return func(selected_items)
84
+
85
+ self._changes_handled = True
86
+
87
+ return on_value_changed
@@ -0,0 +1,12 @@
1
+ <sly-dropdown-checkbox-selection
2
+ :label="data.{{{widget.widget_id}}}.label"
3
+ class="mr5"
4
+ :items="data.{{{widget.widget_id}}}.items"
5
+ :selected="state.{{{widget.widget_id}}}.selected"
6
+ options="{multipleSelection: {{{widget._multiple}}}}"
7
+ {% if widget._changes_handled == true %}
8
+ @update:selected="state.{{{widget.widget_id}}}.selected = $event; post('/{{{widget.widget_id}}}/value_changed')"
9
+ {% else %}
10
+ @update:selected="state.{{{widget.widget_id}}}.selected = $event"
11
+ {% endif %}
12
+ />
@@ -0,0 +1,190 @@
1
+ from typing import Dict, List, Tuple
2
+
3
+ import pandas as pd
4
+
5
+ from supervisely._utils import logger
6
+ from supervisely.api.api import Api
7
+ from supervisely.app.exceptions import show_dialog
8
+ from supervisely.app.widgets import Widget
9
+ from supervisely.app.widgets.container.container import Container
10
+ from supervisely.app.widgets.dropdown_checkbox_selector.dropdown_checkbox_selector import (
11
+ DropdownCheckboxSelector,
12
+ )
13
+ from supervisely.app.widgets.fast_table.fast_table import FastTable
14
+
15
+
16
+ class EcosystemModelSelector(Widget):
17
+ class COLUMN:
18
+ MODEL_NAME = "name"
19
+ FRAMEWORK = "framework"
20
+ TASK_TYPE = "task"
21
+ PARAMETERS = "params (M)"
22
+ # TODO: support metrics for different tasks
23
+ MAP = "mAP"
24
+
25
+ COLUMNS = [
26
+ str(COLUMN.MODEL_NAME),
27
+ str(COLUMN.FRAMEWORK),
28
+ str(COLUMN.TASK_TYPE),
29
+ str(COLUMN.PARAMETERS),
30
+ str(COLUMN.MAP),
31
+ ]
32
+
33
+ def __init__(self, frameworks: List[str] = None, task_types: List[str] = None, models: List[Dict] = None, api: Api = None, widget_id: str = None):
34
+ if api is None:
35
+ api = Api()
36
+ self.api = api
37
+ self.frameworks = None
38
+ self.task_types = None
39
+ self.models = None
40
+
41
+ self.set(frameworks, task_types, models)
42
+
43
+ self.framework_filter = DropdownCheckboxSelector(items=[], label="Frameworks")
44
+ self.task_filter = DropdownCheckboxSelector(items=[], label="Task Types")
45
+ self.table = FastTable(columns=self.COLUMNS, page_size=10, is_radio=True, header_right_content=Container(widgets=[self.framework_filter, self.task_filter], direction="horizontal"))
46
+ self.refresh_table()
47
+ self.table.set_filter(self._filter_function)
48
+
49
+ @self.framework_filter.value_changed
50
+ def _framework_filter_changed(frameworks: List[DropdownCheckboxSelector.Item]):
51
+ task_types = self.task_filter.get_selected()
52
+ self.table.filter(([f.id for f in frameworks], [t.id for t in task_types]))
53
+
54
+ @self.task_filter.value_changed
55
+ def _task_filter_changed(task_types: List[DropdownCheckboxSelector.Item]):
56
+ frameworks = self.framework_filter.get_selected()
57
+ self.table.filter(([f.id for f in frameworks], [t.id for t in task_types]))
58
+
59
+ super().__init__(widget_id=widget_id, file_path=__file__)
60
+
61
+ def _filter_function(
62
+ self, data: pd.DataFrame, filter_value: Tuple[List[str], List[str]]
63
+ ) -> pd.DataFrame:
64
+ try:
65
+ frameworks, task_types = filter_value
66
+ if not frameworks and not task_types:
67
+ return data
68
+ filtered_models = set()
69
+ for idx, model in enumerate(self.models):
70
+ should_add = True
71
+ if frameworks and model["framework"] not in frameworks:
72
+ should_add = False
73
+ if task_types and model["task"] not in task_types:
74
+ should_add = False
75
+ if should_add:
76
+ filtered_models.add(idx)
77
+
78
+ filtered_data = data.iloc[sorted(filtered_models)]
79
+ filtered_data.reset_index(inplace=True, drop=True)
80
+ except Exception as e:
81
+ logger.error(f"Error during filtering: {e}", exc_info=True)
82
+ show_dialog(title="Filtering Error", description=str(e), status="error")
83
+ return data
84
+ return filtered_data
85
+
86
+ def _filter_models(self, models: List[Dict], frameworks: List[str], task_types: List[str]) -> List[Dict]:
87
+ if frameworks is None and task_types is None:
88
+ return models
89
+
90
+ filtered_models = []
91
+ for model in models:
92
+ if frameworks and model["framework"] not in frameworks:
93
+ continue
94
+ if task_types and model["model"]["task"] not in task_types:
95
+ continue
96
+ filtered_models.append(model)
97
+ return filtered_models
98
+
99
+ def set(self, frameworks: List[str] = None, task_types: List[str] = None, models: List[Dict] = None):
100
+ self.frameworks = frameworks
101
+ self.task_types = task_types
102
+ if models is None:
103
+ models = self.api.nn.ecosystem_models_api.list_models()
104
+ self.models = models
105
+ self.models = self._filter_models(self.models, self.frameworks, self.task_types)
106
+
107
+ def _map_from_model(self, model: Dict):
108
+ try:
109
+ map = model.get("evaluation", {}).get("metrics", {}).get("mAP", None)
110
+ if map is None:
111
+ return None
112
+ return float(map)
113
+ except:
114
+ return None
115
+
116
+ def _params_from_model(self, model: Dict):
117
+ try:
118
+ params = model.get("paramsM", None)
119
+ if params is None:
120
+ return None
121
+ return float(params)
122
+ except:
123
+ return None
124
+
125
+ def _get_table_data(self, models: List[Dict] = None) -> List[Dict]:
126
+ if models is None:
127
+ models = self.models
128
+ data = [
129
+ {
130
+ self.COLUMN.FRAMEWORK: model_data["framework"],
131
+ self.COLUMN.MODEL_NAME: model_data["name"],
132
+ self.COLUMN.TASK_TYPE: model_data["task"],
133
+ self.COLUMN.PARAMETERS: self._params_from_model(model_data),
134
+ self.COLUMN.MAP: self._map_from_model(model_data),
135
+ }
136
+ for model_data in models
137
+ ]
138
+ return data
139
+
140
+ def refresh_table(self):
141
+ data = self._get_table_data()
142
+ df = pd.DataFrame.from_records(data=data, columns=self.COLUMNS)
143
+ self.table.read_pandas(df)
144
+ unique_frameworks = df[self.COLUMN.FRAMEWORK].unique().tolist()
145
+ self.framework_filter.set(items=[DropdownCheckboxSelector.Item(id=f, name=f) for f in unique_frameworks])
146
+ unique_task_types = df[self.COLUMN.TASK_TYPE].unique().tolist()
147
+ self.task_filter.set(items=[DropdownCheckboxSelector.Item(id=t, name=t) for t in unique_task_types])
148
+
149
+ def get_selected(self):
150
+ idx = self.table.get_selected_row().row_index
151
+ return self.models[idx]
152
+
153
+ def select(self, index: int):
154
+ self.table.select_row(index)
155
+
156
+ def select_framework_and_model_name(self, framework: str, model_name: str):
157
+ for idx, model in enumerate(self.models):
158
+ if model["name"] == model_name and model["framework"] == framework:
159
+ self.table.select_row(idx)
160
+ return
161
+ raise ValueError(f"Model with framework `{framework}` and name '{model_name}' not found.")
162
+
163
+ def get_json_data(self):
164
+ return {}
165
+
166
+ def get_json_state(self):
167
+ return {}
168
+
169
+ def to_html(self):
170
+ return self.table.to_html()
171
+
172
+ def disable(self):
173
+ return self.table.disable()
174
+
175
+ def enable(self):
176
+ return self.table.enable()
177
+
178
+ def hide(self):
179
+ return self.table.hide()
180
+
181
+ def show(self):
182
+ return self.table.show()
183
+
184
+ @property
185
+ def loading(self):
186
+ return self.table.loading
187
+
188
+ @loading.setter
189
+ def loading(self, value: bool):
190
+ self.table.loading = value