supervisely 6.73.452__py3-none-any.whl → 6.73.513__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.
- supervisely/__init__.py +25 -1
- supervisely/annotation/annotation.py +8 -2
- supervisely/annotation/json_geometries_map.py +13 -12
- supervisely/api/annotation_api.py +6 -3
- supervisely/api/api.py +2 -0
- supervisely/api/app_api.py +10 -1
- supervisely/api/dataset_api.py +74 -12
- supervisely/api/entities_collection_api.py +10 -0
- supervisely/api/entity_annotation/figure_api.py +28 -0
- supervisely/api/entity_annotation/object_api.py +3 -3
- supervisely/api/entity_annotation/tag_api.py +63 -12
- supervisely/api/guides_api.py +210 -0
- supervisely/api/image_api.py +4 -0
- supervisely/api/labeling_job_api.py +83 -1
- supervisely/api/labeling_queue_api.py +33 -7
- supervisely/api/module_api.py +5 -0
- supervisely/api/project_api.py +71 -26
- supervisely/api/storage_api.py +3 -1
- supervisely/api/task_api.py +13 -2
- supervisely/api/team_api.py +4 -3
- supervisely/api/video/video_annotation_api.py +119 -3
- supervisely/api/video/video_api.py +65 -14
- supervisely/app/__init__.py +1 -1
- supervisely/app/content.py +23 -7
- supervisely/app/development/development.py +18 -2
- supervisely/app/fastapi/__init__.py +1 -0
- supervisely/app/fastapi/custom_static_files.py +1 -1
- supervisely/app/fastapi/multi_user.py +105 -0
- supervisely/app/fastapi/subapp.py +88 -42
- supervisely/app/fastapi/websocket.py +77 -9
- supervisely/app/singleton.py +21 -0
- supervisely/app/v1/app_service.py +18 -2
- supervisely/app/v1/constants.py +7 -1
- supervisely/app/widgets/__init__.py +6 -0
- supervisely/app/widgets/activity_feed/__init__.py +0 -0
- supervisely/app/widgets/activity_feed/activity_feed.py +239 -0
- supervisely/app/widgets/activity_feed/style.css +78 -0
- supervisely/app/widgets/activity_feed/template.html +22 -0
- supervisely/app/widgets/card/card.py +20 -0
- supervisely/app/widgets/classes_list_selector/classes_list_selector.py +121 -9
- supervisely/app/widgets/classes_list_selector/template.html +60 -93
- supervisely/app/widgets/classes_mapping/classes_mapping.py +13 -12
- supervisely/app/widgets/classes_table/classes_table.py +1 -0
- supervisely/app/widgets/deploy_model/deploy_model.py +56 -35
- supervisely/app/widgets/ecosystem_model_selector/ecosystem_model_selector.py +1 -1
- supervisely/app/widgets/experiment_selector/experiment_selector.py +8 -0
- supervisely/app/widgets/fast_table/fast_table.py +184 -60
- supervisely/app/widgets/fast_table/template.html +1 -1
- supervisely/app/widgets/heatmap/__init__.py +0 -0
- supervisely/app/widgets/heatmap/heatmap.py +564 -0
- supervisely/app/widgets/heatmap/script.js +533 -0
- supervisely/app/widgets/heatmap/style.css +233 -0
- supervisely/app/widgets/heatmap/template.html +21 -0
- supervisely/app/widgets/modal/__init__.py +0 -0
- supervisely/app/widgets/modal/modal.py +198 -0
- supervisely/app/widgets/modal/template.html +10 -0
- supervisely/app/widgets/object_class_view/object_class_view.py +3 -0
- supervisely/app/widgets/radio_tabs/radio_tabs.py +18 -2
- supervisely/app/widgets/radio_tabs/template.html +1 -0
- supervisely/app/widgets/select/select.py +6 -3
- supervisely/app/widgets/select_class/__init__.py +0 -0
- supervisely/app/widgets/select_class/select_class.py +363 -0
- supervisely/app/widgets/select_class/template.html +50 -0
- supervisely/app/widgets/select_cuda/select_cuda.py +22 -0
- supervisely/app/widgets/select_dataset_tree/select_dataset_tree.py +65 -7
- supervisely/app/widgets/select_tag/__init__.py +0 -0
- supervisely/app/widgets/select_tag/select_tag.py +352 -0
- supervisely/app/widgets/select_tag/template.html +64 -0
- supervisely/app/widgets/select_team/select_team.py +37 -4
- supervisely/app/widgets/select_team/template.html +4 -5
- supervisely/app/widgets/select_user/__init__.py +0 -0
- supervisely/app/widgets/select_user/select_user.py +270 -0
- supervisely/app/widgets/select_user/template.html +13 -0
- supervisely/app/widgets/select_workspace/select_workspace.py +59 -10
- supervisely/app/widgets/select_workspace/template.html +9 -12
- supervisely/app/widgets/table/table.py +68 -13
- supervisely/app/widgets/tree_select/tree_select.py +2 -0
- supervisely/aug/aug.py +6 -2
- supervisely/convert/base_converter.py +1 -0
- supervisely/convert/converter.py +2 -2
- supervisely/convert/image/image_converter.py +3 -1
- supervisely/convert/image/image_helper.py +48 -4
- supervisely/convert/image/label_studio/label_studio_converter.py +2 -0
- supervisely/convert/image/medical2d/medical2d_helper.py +2 -24
- supervisely/convert/image/multispectral/multispectral_converter.py +6 -0
- supervisely/convert/image/pascal_voc/pascal_voc_converter.py +8 -5
- supervisely/convert/image/pascal_voc/pascal_voc_helper.py +7 -0
- supervisely/convert/pointcloud/kitti_3d/kitti_3d_converter.py +33 -3
- supervisely/convert/pointcloud/kitti_3d/kitti_3d_helper.py +12 -5
- supervisely/convert/pointcloud/las/las_converter.py +13 -1
- supervisely/convert/pointcloud/las/las_helper.py +110 -11
- supervisely/convert/pointcloud/nuscenes_conv/nuscenes_converter.py +27 -16
- supervisely/convert/pointcloud/pointcloud_converter.py +91 -3
- supervisely/convert/pointcloud_episodes/nuscenes_conv/nuscenes_converter.py +58 -22
- supervisely/convert/pointcloud_episodes/nuscenes_conv/nuscenes_helper.py +21 -47
- supervisely/convert/video/__init__.py +1 -0
- supervisely/convert/video/multi_view/__init__.py +0 -0
- supervisely/convert/video/multi_view/multi_view.py +543 -0
- supervisely/convert/video/sly/sly_video_converter.py +359 -3
- supervisely/convert/video/video_converter.py +22 -2
- supervisely/convert/volume/dicom/dicom_converter.py +13 -5
- supervisely/convert/volume/dicom/dicom_helper.py +30 -18
- supervisely/geometry/constants.py +1 -0
- supervisely/geometry/geometry.py +4 -0
- supervisely/geometry/helpers.py +5 -1
- supervisely/geometry/oriented_bbox.py +676 -0
- supervisely/geometry/rectangle.py +2 -1
- supervisely/io/env.py +76 -1
- supervisely/io/fs.py +21 -0
- supervisely/nn/benchmark/base_evaluator.py +104 -11
- supervisely/nn/benchmark/instance_segmentation/evaluator.py +1 -8
- supervisely/nn/benchmark/object_detection/evaluator.py +20 -4
- supervisely/nn/benchmark/object_detection/vis_metrics/pr_curve.py +10 -5
- supervisely/nn/benchmark/semantic_segmentation/evaluator.py +34 -16
- supervisely/nn/benchmark/semantic_segmentation/vis_metrics/confusion_matrix.py +1 -1
- supervisely/nn/benchmark/semantic_segmentation/vis_metrics/frequently_confused.py +1 -1
- supervisely/nn/benchmark/semantic_segmentation/vis_metrics/overview.py +1 -1
- supervisely/nn/benchmark/visualization/evaluation_result.py +66 -4
- supervisely/nn/inference/cache.py +43 -18
- supervisely/nn/inference/gui/serving_gui_template.py +5 -2
- supervisely/nn/inference/inference.py +795 -199
- supervisely/nn/inference/inference_request.py +42 -9
- supervisely/nn/inference/predict_app/gui/classes_selector.py +83 -12
- supervisely/nn/inference/predict_app/gui/gui.py +676 -488
- supervisely/nn/inference/predict_app/gui/input_selector.py +205 -26
- supervisely/nn/inference/predict_app/gui/model_selector.py +2 -4
- supervisely/nn/inference/predict_app/gui/output_selector.py +46 -6
- supervisely/nn/inference/predict_app/gui/settings_selector.py +756 -59
- supervisely/nn/inference/predict_app/gui/tags_selector.py +1 -1
- supervisely/nn/inference/predict_app/gui/utils.py +236 -119
- supervisely/nn/inference/predict_app/predict_app.py +2 -2
- supervisely/nn/inference/session.py +43 -35
- supervisely/nn/inference/tracking/bbox_tracking.py +113 -34
- supervisely/nn/inference/tracking/tracker_interface.py +7 -2
- supervisely/nn/inference/uploader.py +139 -12
- supervisely/nn/live_training/__init__.py +7 -0
- supervisely/nn/live_training/api_server.py +111 -0
- supervisely/nn/live_training/artifacts_utils.py +243 -0
- supervisely/nn/live_training/checkpoint_utils.py +229 -0
- supervisely/nn/live_training/dynamic_sampler.py +44 -0
- supervisely/nn/live_training/helpers.py +14 -0
- supervisely/nn/live_training/incremental_dataset.py +146 -0
- supervisely/nn/live_training/live_training.py +497 -0
- supervisely/nn/live_training/loss_plateau_detector.py +111 -0
- supervisely/nn/live_training/request_queue.py +52 -0
- supervisely/nn/model/model_api.py +9 -0
- supervisely/nn/prediction_dto.py +12 -1
- supervisely/nn/tracker/base_tracker.py +11 -1
- supervisely/nn/tracker/botsort/botsort_config.yaml +0 -1
- supervisely/nn/tracker/botsort/tracker/mc_bot_sort.py +7 -4
- supervisely/nn/tracker/botsort_tracker.py +94 -65
- supervisely/nn/tracker/visualize.py +87 -90
- supervisely/nn/training/gui/classes_selector.py +16 -1
- supervisely/nn/training/train_app.py +28 -29
- supervisely/project/data_version.py +115 -51
- supervisely/project/download.py +1 -1
- supervisely/project/pointcloud_episode_project.py +37 -8
- supervisely/project/pointcloud_project.py +30 -2
- supervisely/project/project.py +14 -2
- supervisely/project/project_meta.py +27 -1
- supervisely/project/project_settings.py +32 -18
- supervisely/project/versioning/__init__.py +1 -0
- supervisely/project/versioning/common.py +20 -0
- supervisely/project/versioning/schema_fields.py +35 -0
- supervisely/project/versioning/video_schema.py +221 -0
- supervisely/project/versioning/volume_schema.py +87 -0
- supervisely/project/video_project.py +717 -15
- supervisely/project/volume_project.py +623 -5
- supervisely/template/experiment/experiment.html.jinja +4 -4
- supervisely/template/experiment/experiment_generator.py +14 -21
- supervisely/template/live_training/__init__.py +0 -0
- supervisely/template/live_training/header.html.jinja +96 -0
- supervisely/template/live_training/live_training.html.jinja +51 -0
- supervisely/template/live_training/live_training_generator.py +464 -0
- supervisely/template/live_training/sly-style.css +402 -0
- supervisely/template/live_training/template.html.jinja +18 -0
- supervisely/versions.json +28 -26
- supervisely/video/sampling.py +39 -20
- supervisely/video/video.py +40 -11
- supervisely/video_annotation/video_object.py +29 -4
- supervisely/volume/stl_converter.py +2 -0
- supervisely/worker_api/agent_rpc.py +24 -1
- supervisely/worker_api/rpc_servicer.py +31 -7
- {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info}/METADATA +56 -39
- {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info}/RECORD +189 -142
- {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info}/WHEEL +1 -1
- {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info/licenses}/LICENSE +0 -0
- {supervisely-6.73.452.dist-info → supervisely-6.73.513.dist-info}/top_level.txt +0 -0
|
@@ -1,131 +1,98 @@
|
|
|
1
|
-
<link
|
|
2
|
-
rel="stylesheet"
|
|
3
|
-
href="./sly/css/app/widgets/classes_list_selector/style.css"
|
|
4
|
-
/>
|
|
1
|
+
<link rel="stylesheet" href="./sly/css/app/widgets/classes_list_selector/style.css" />
|
|
5
2
|
|
|
6
3
|
<div v-show="data.{{{widget.widget_id}}}.classes.length == 0">
|
|
7
4
|
{{{widget.empty_notification}}}
|
|
8
5
|
</div>
|
|
9
6
|
<div v-show="data.{{{widget.widget_id}}}.classes.length != 0">
|
|
10
|
-
<link
|
|
11
|
-
rel="stylesheet"
|
|
12
|
-
href="./sly/css/app/widgets/object_class_view/style.css"
|
|
13
|
-
/>
|
|
7
|
+
<link rel="stylesheet" href="./sly/css/app/widgets/object_class_view/style.css" />
|
|
14
8
|
{% if widget._multiple %}
|
|
15
9
|
<div>
|
|
16
|
-
<el-button
|
|
17
|
-
style="margin-right: 10px"
|
|
18
|
-
type="text"
|
|
19
|
-
{%
|
|
20
|
-
if
|
|
21
|
-
widget._checkboxes_handled
|
|
22
|
-
%}
|
|
23
|
-
@click="{
|
|
10
|
+
<el-button style="margin-right: 10px" type="text" {% if widget._checkboxes_handled %} @click="{
|
|
24
11
|
state.{{{widget.widget_id}}}.selected = state.{{{widget.widget_id}}}.selected.map(() => true);
|
|
25
12
|
post('/{{{widget.widget_id}}}/checkbox_cb');
|
|
26
|
-
}"
|
|
27
|
-
{%
|
|
28
|
-
|
|
29
|
-
%}
|
|
30
|
-
@click="state.{{{widget.widget_id}}}.selected = state.{{{widget.widget_id}}}.selected.map(() => true)"
|
|
31
|
-
{%
|
|
32
|
-
endif
|
|
33
|
-
%}
|
|
34
|
-
>
|
|
13
|
+
}" {% else %}
|
|
14
|
+
@click="state.{{{widget.widget_id}}}.selected = state.{{{widget.widget_id}}}.selected.map(() => true)" {%
|
|
15
|
+
endif %}>
|
|
35
16
|
<i class="zmdi zmdi-check-all"></i>
|
|
36
17
|
Select all
|
|
37
18
|
</el-button>
|
|
38
|
-
<el-button
|
|
39
|
-
style="margin-right: 10px"
|
|
40
|
-
type="text"
|
|
41
|
-
{%
|
|
42
|
-
if
|
|
43
|
-
widget._checkboxes_handled
|
|
44
|
-
%}
|
|
45
|
-
@click="{
|
|
19
|
+
<el-button style="margin-right: 10px" type="text" {% if widget._checkboxes_handled %} @click="{
|
|
46
20
|
state.{{{widget.widget_id}}}.selected = state.{{{widget.widget_id}}}.selected.map(() => false);
|
|
47
21
|
post('/{{{widget.widget_id}}}/checkbox_cb');
|
|
48
|
-
}"
|
|
49
|
-
{%
|
|
50
|
-
|
|
51
|
-
%}
|
|
52
|
-
@click="state.{{{widget.widget_id}}}.selected = state.{{{widget.widget_id}}}.selected.map(() => false)"
|
|
53
|
-
{%
|
|
54
|
-
endif
|
|
55
|
-
%}
|
|
56
|
-
>
|
|
22
|
+
}" {% else %}
|
|
23
|
+
@click="state.{{{widget.widget_id}}}.selected = state.{{{widget.widget_id}}}.selected.map(() => false)" {%
|
|
24
|
+
endif %}>
|
|
57
25
|
<i class="zmdi zmdi-square-o"></i>
|
|
58
26
|
Deselect all
|
|
59
27
|
</el-button>
|
|
60
28
|
</div>
|
|
61
29
|
{% endif %}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
%}
|
|
73
|
-
{%
|
|
74
|
-
if
|
|
75
|
-
not
|
|
76
|
-
widget._multiple
|
|
77
|
-
%}
|
|
78
|
-
@change="() => {
|
|
30
|
+
{% if widget._allow_new_classes %}
|
|
31
|
+
<div style="margin-bottom: 10px; margin-top: 10px">
|
|
32
|
+
<el-button type="primary" size="small" icon="el-icon-plus"
|
|
33
|
+
@click="state.{{{widget.widget_id}}}.createClassDialog.visible = true">
|
|
34
|
+
Add new class
|
|
35
|
+
</el-button>
|
|
36
|
+
</div>
|
|
37
|
+
{% endif %}
|
|
38
|
+
<div class="fflex" v-for="(obj_class, idx) in data.{{{widget.widget_id}}}.classes">
|
|
39
|
+
<el-checkbox v-model="state.{{{widget.widget_id}}}.selected[idx]" style="margin-right: 10px" {% if
|
|
40
|
+
widget._checkboxes_handled %} {% if not widget._multiple %} @change="() => {
|
|
79
41
|
if ($event.target.checked) {
|
|
80
42
|
state.{{{widget.widget_id}}}.selected = state.{{{widget.widget_id}}}.selected.map((_, i) => i == idx);
|
|
81
43
|
}
|
|
82
44
|
post('/{{{widget.widget_id}}}/checkbox_cb');
|
|
83
|
-
}"
|
|
84
|
-
{%
|
|
85
|
-
else
|
|
86
|
-
%}
|
|
87
|
-
@change="() => {
|
|
45
|
+
}" {% else %} @change="() => {
|
|
88
46
|
post('/{{{widget.widget_id}}}/checkbox_cb');
|
|
89
|
-
}"
|
|
90
|
-
{%
|
|
91
|
-
endif
|
|
92
|
-
%}
|
|
93
|
-
{%
|
|
94
|
-
else
|
|
95
|
-
%}
|
|
96
|
-
{%
|
|
97
|
-
if
|
|
98
|
-
not
|
|
99
|
-
widget._multiple
|
|
100
|
-
%}
|
|
47
|
+
}" {% endif %} {% else %} {% if not widget._multiple %}
|
|
101
48
|
@change="if ($event.target.checked) {state.{{{widget.widget_id}}}.selected = state.{{{widget.widget_id}}}.selected.map((_, i) => i == idx);}"
|
|
102
|
-
{%
|
|
103
|
-
endif
|
|
104
|
-
%}
|
|
105
|
-
{%
|
|
106
|
-
endif
|
|
107
|
-
%}
|
|
108
|
-
>
|
|
49
|
+
{% endif %} {% endif %}>
|
|
109
50
|
</el-checkbox>
|
|
110
51
|
<span class="icon-text-line classes-list-preview-sidebar">
|
|
111
|
-
<i
|
|
112
|
-
class="zmdi zmdi-circle"
|
|
113
|
-
style="margin-right: 5px"
|
|
114
|
-
:style="{color: obj_class.color}"
|
|
115
|
-
></i>
|
|
52
|
+
<i class="zmdi zmdi-circle" style="margin-right: 5px" :style="{color: obj_class.color}"></i>
|
|
116
53
|
<b style="font-size: 16">{{obj_class.title}}</b>
|
|
117
|
-
<span
|
|
118
|
-
v-if="obj_class.shape_text"
|
|
119
|
-
style="
|
|
54
|
+
<span v-if="obj_class.shape_text" style="
|
|
120
55
|
flex: none;
|
|
121
56
|
margin-left: 5px;
|
|
122
57
|
font-size: 12px;
|
|
123
58
|
color: #8492a6;
|
|
124
59
|
line-height: initial;
|
|
125
|
-
"
|
|
126
|
-
>
|
|
60
|
+
">
|
|
127
61
|
{{obj_class.shape_text}}
|
|
128
62
|
</span>
|
|
129
63
|
</span>
|
|
130
64
|
</div>
|
|
131
65
|
</div>
|
|
66
|
+
|
|
67
|
+
{% if widget._allow_new_classes %}
|
|
68
|
+
<!-- Dialog for creating new class -->
|
|
69
|
+
<el-dialog title="Create New Class" :visible.sync="state.{{{widget.widget_id}}}.createClassDialog.visible" width="450px"
|
|
70
|
+
:close-on-click-modal="false" @open="state.{{{widget.widget_id}}}.createClassDialog.showError = false">
|
|
71
|
+
<el-form label-width="120px" label-position="left">
|
|
72
|
+
<el-form-item label="Class Name">
|
|
73
|
+
<el-input v-model="state.{{{widget.widget_id}}}.createClassDialog.className" placeholder="Enter class name"
|
|
74
|
+
@input="state.{{{widget.widget_id}}}.createClassDialog.showError = false"
|
|
75
|
+
@keyup.enter.native="post('/{{{widget.widget_id}}}/class_created_cb')"></el-input>
|
|
76
|
+
</el-form-item>
|
|
77
|
+
<el-form-item label="Geometry Type">
|
|
78
|
+
<el-select v-model="state.{{{widget.widget_id}}}.createClassDialog.geometryType"
|
|
79
|
+
placeholder="Select geometry type" style="width: 100%">
|
|
80
|
+
<el-option v-for="geom in data.{{{widget.widget_id}}}.availableGeometryTypes" :key="geom.value"
|
|
81
|
+
:label="geom.label" :value="geom.value">
|
|
82
|
+
</el-option>
|
|
83
|
+
</el-select>
|
|
84
|
+
</el-form-item>
|
|
85
|
+
<div v-show="state.{{{widget.widget_id}}}.createClassDialog.showError" style="margin-top: 10px;">
|
|
86
|
+
{{{widget._error_message}}}
|
|
87
|
+
</div>
|
|
88
|
+
</el-form>
|
|
89
|
+
<span slot="footer" class="dialog-footer">
|
|
90
|
+
<el-button @click="state.{{{widget.widget_id}}}.createClassDialog.visible = false">
|
|
91
|
+
Cancel
|
|
92
|
+
</el-button>
|
|
93
|
+
<el-button type="primary" @click="post('/{{{widget.widget_id}}}/class_created_cb')">
|
|
94
|
+
Create
|
|
95
|
+
</el-button>
|
|
96
|
+
</span>
|
|
97
|
+
</el-dialog>
|
|
98
|
+
{% endif %}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
from typing import Optional, Union
|
|
2
|
-
|
|
1
|
+
from typing import List, Optional, Union
|
|
2
|
+
|
|
3
3
|
from supervisely import ObjClass, ObjClassCollection
|
|
4
4
|
from supervisely.app import DataJson, StateJson
|
|
5
|
-
|
|
6
|
-
from supervisely.geometry.bitmap import Bitmap
|
|
5
|
+
from supervisely.app.widgets import Button, NotificationBox, Widget, generate_id
|
|
7
6
|
from supervisely.geometry.alpha_mask import AlphaMask
|
|
7
|
+
from supervisely.geometry.any_geometry import AnyGeometry
|
|
8
|
+
from supervisely.geometry.bitmap import Bitmap
|
|
9
|
+
from supervisely.geometry.closed_surface_mesh import ClosedSurfaceMesh
|
|
8
10
|
from supervisely.geometry.cuboid import Cuboid
|
|
11
|
+
from supervisely.geometry.cuboid_3d import Cuboid3d
|
|
12
|
+
from supervisely.geometry.graph import GraphNodes
|
|
13
|
+
from supervisely.geometry.multichannel_bitmap import MultichannelBitmap
|
|
14
|
+
from supervisely.geometry.oriented_bbox import OrientedBBox
|
|
9
15
|
from supervisely.geometry.point import Point
|
|
16
|
+
from supervisely.geometry.point_3d import Point3d
|
|
17
|
+
from supervisely.geometry.pointcloud import Pointcloud
|
|
10
18
|
from supervisely.geometry.polygon import Polygon
|
|
11
19
|
from supervisely.geometry.polyline import Polyline
|
|
12
20
|
from supervisely.geometry.rectangle import Rectangle
|
|
13
|
-
from supervisely.geometry.graph import GraphNodes
|
|
14
|
-
from supervisely.geometry.any_geometry import AnyGeometry
|
|
15
|
-
from supervisely.geometry.cuboid_3d import Cuboid3d
|
|
16
|
-
from supervisely.geometry.pointcloud import Pointcloud
|
|
17
|
-
from supervisely.geometry.point_3d import Point3d
|
|
18
|
-
from supervisely.geometry.multichannel_bitmap import MultichannelBitmap
|
|
19
|
-
from supervisely.geometry.closed_surface_mesh import ClosedSurfaceMesh
|
|
20
|
-
|
|
21
21
|
|
|
22
22
|
type_to_shape_text = {
|
|
23
23
|
AnyGeometry: "any shape",
|
|
@@ -34,6 +34,7 @@ type_to_shape_text = {
|
|
|
34
34
|
Point3d: "point 3d", # "zmdi zmdi-select-all"
|
|
35
35
|
GraphNodes: "keypoints",
|
|
36
36
|
ClosedSurfaceMesh: "volume (3d mask)",
|
|
37
|
+
OrientedBBox: "oriented bbox",
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
|
|
@@ -24,6 +24,7 @@ type_to_zmdi_icon = {
|
|
|
24
24
|
Pointcloud: "zmdi zmdi-cloud-outline", # "zmdi zmdi-border-clear"
|
|
25
25
|
sly.MultichannelBitmap: "zmdi zmdi-layers", # "zmdi zmdi-collection-item"
|
|
26
26
|
Point3d: "zmdi zmdi-filter-center-focus", # "zmdi zmdi-select-all"
|
|
27
|
+
sly.OrientedBBox: "zmdi zmdi-rotate-cw",
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
import tempfile
|
|
3
|
+
import threading
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from typing import Any, Dict, List, Literal
|
|
5
6
|
|
|
6
7
|
import pandas as pd
|
|
7
|
-
import yaml
|
|
8
8
|
|
|
9
9
|
from supervisely._utils import logger
|
|
10
10
|
from supervisely.api.api import Api
|
|
@@ -12,8 +12,6 @@ from supervisely.api.app_api import ModuleInfo
|
|
|
12
12
|
from supervisely.app.widgets.agent_selector.agent_selector import AgentSelector
|
|
13
13
|
from supervisely.app.widgets.button.button import Button
|
|
14
14
|
from supervisely.app.widgets.container.container import Container
|
|
15
|
-
from supervisely.app.widgets.card.card import Card
|
|
16
|
-
from supervisely.app.widgets.model_info.model_info import ModelInfo
|
|
17
15
|
from supervisely.app.widgets.ecosystem_model_selector.ecosystem_model_selector import (
|
|
18
16
|
EcosystemModelSelector,
|
|
19
17
|
)
|
|
@@ -23,7 +21,8 @@ from supervisely.app.widgets.experiment_selector.experiment_selector import (
|
|
|
23
21
|
from supervisely.app.widgets.fast_table.fast_table import FastTable
|
|
24
22
|
from supervisely.app.widgets.field.field import Field
|
|
25
23
|
from supervisely.app.widgets.flexbox.flexbox import Flexbox
|
|
26
|
-
from supervisely.app.widgets.
|
|
24
|
+
from supervisely.app.widgets.model_info.model_info import ModelInfo
|
|
25
|
+
from supervisely.app.widgets.radio_tabs.radio_tabs import RadioTabs
|
|
27
26
|
from supervisely.app.widgets.text.text import Text
|
|
28
27
|
from supervisely.app.widgets.widget import Widget
|
|
29
28
|
from supervisely.io import env
|
|
@@ -211,24 +210,31 @@ class DeployModel(Widget):
|
|
|
211
210
|
return self._layout
|
|
212
211
|
|
|
213
212
|
def _create_layout(self) -> Container:
|
|
214
|
-
frameworks = self.deploy_model.get_frameworks()
|
|
215
|
-
experiment_infos = []
|
|
216
|
-
for framework_name in frameworks:
|
|
217
|
-
experiment_infos.extend(
|
|
218
|
-
get_experiment_infos(self.api, self.team_id, framework_name=framework_name)
|
|
219
|
-
)
|
|
220
213
|
self.experiment_table = ExperimentSelector(
|
|
221
|
-
experiment_infos=experiment_infos,
|
|
222
|
-
team_id=self.team_id,
|
|
223
214
|
api=self.api,
|
|
215
|
+
team_id=self.team_id,
|
|
224
216
|
)
|
|
225
217
|
|
|
226
218
|
@self.experiment_table.checkpoint_changed
|
|
227
219
|
def _checkpoint_changed(row: ExperimentSelector.ModelRow, checkpoint_value: str):
|
|
228
220
|
print(f"Checkpoint changed for {row._experiment_info.task_id}: {checkpoint_value}")
|
|
229
221
|
|
|
222
|
+
threading.Thread(target=self.refresh_experiments, daemon=True).start()
|
|
223
|
+
|
|
230
224
|
return self.experiment_table
|
|
231
225
|
|
|
226
|
+
def refresh_experiments(self):
|
|
227
|
+
self.experiment_table.loading = True
|
|
228
|
+
frameworks = self.deploy_model.get_frameworks()
|
|
229
|
+
experiment_infos = []
|
|
230
|
+
for framework_name in frameworks:
|
|
231
|
+
experiment_infos.extend(
|
|
232
|
+
get_experiment_infos(self.api, self.team_id, framework_name=framework_name)
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
self.experiment_table.set_experiment_infos(experiment_infos)
|
|
236
|
+
self.experiment_table.loading = False
|
|
237
|
+
|
|
232
238
|
def get_deploy_parameters(self) -> Dict[str, Any]:
|
|
233
239
|
experiment_info = self.experiment_table.get_selected_experiment_info()
|
|
234
240
|
return {
|
|
@@ -267,8 +273,8 @@ class DeployModel(Widget):
|
|
|
267
273
|
MODES = [str(MODE.CONNECT), str(MODE.PRETRAINED), str(MODE.CUSTOM)]
|
|
268
274
|
MODE_TO_CLASS = {
|
|
269
275
|
str(MODE.CONNECT): Connect,
|
|
270
|
-
str(MODE.PRETRAINED): Pretrained,
|
|
271
276
|
str(MODE.CUSTOM): Custom,
|
|
277
|
+
str(MODE.PRETRAINED): Pretrained,
|
|
272
278
|
}
|
|
273
279
|
|
|
274
280
|
def __init__(
|
|
@@ -295,6 +301,11 @@ class DeployModel(Widget):
|
|
|
295
301
|
self.MODE.PRETRAINED: "Pretrained",
|
|
296
302
|
self.MODE.CUSTOM: "Custom",
|
|
297
303
|
}
|
|
304
|
+
self.modes_descriptions = {
|
|
305
|
+
self.MODE.CONNECT: "Connect to an already deployed model",
|
|
306
|
+
self.MODE.PRETRAINED: "Deploy a pretrained model from the ecosystem",
|
|
307
|
+
self.MODE.CUSTOM: "Deploy a custom model from your experiments",
|
|
308
|
+
}
|
|
298
309
|
|
|
299
310
|
# GUI
|
|
300
311
|
self.layout: Widget = None
|
|
@@ -444,31 +455,41 @@ class DeployModel(Widget):
|
|
|
444
455
|
|
|
445
456
|
self._init_modes(modes)
|
|
446
457
|
_labels = []
|
|
458
|
+
_descriptions = []
|
|
447
459
|
_contents = []
|
|
460
|
+
self.statuses_widgets = Container(
|
|
461
|
+
widgets=[
|
|
462
|
+
self.sesson_link,
|
|
463
|
+
self._model_info_container,
|
|
464
|
+
],
|
|
465
|
+
gap=20,
|
|
466
|
+
)
|
|
467
|
+
self.statuses_widgets.hide()
|
|
448
468
|
for mode_name, mode in self.modes.items():
|
|
449
469
|
label = self.modes_labels[mode_name]
|
|
470
|
+
description = self.modes_descriptions[mode_name]
|
|
450
471
|
if mode_name == str(self.MODE.CONNECT):
|
|
451
472
|
widgets = [
|
|
452
473
|
mode.layout,
|
|
453
|
-
self._model_info_card,
|
|
454
|
-
self.connect_stop_buttons,
|
|
455
474
|
self.status,
|
|
456
|
-
self.
|
|
475
|
+
self.statuses_widgets,
|
|
476
|
+
self.connect_stop_buttons,
|
|
457
477
|
]
|
|
458
478
|
else:
|
|
459
479
|
widgets = [
|
|
460
480
|
mode.layout,
|
|
461
|
-
self._model_info_card,
|
|
462
481
|
self.select_agent_field,
|
|
463
|
-
self.deploy_stop_buttons,
|
|
464
482
|
self.status,
|
|
465
|
-
self.
|
|
483
|
+
self.statuses_widgets,
|
|
484
|
+
self.deploy_stop_buttons,
|
|
466
485
|
]
|
|
486
|
+
|
|
467
487
|
content = Container(widgets=widgets, gap=20)
|
|
468
488
|
_labels.append(label)
|
|
489
|
+
_descriptions.append(description)
|
|
469
490
|
_contents.append(content)
|
|
470
491
|
|
|
471
|
-
self.tabs =
|
|
492
|
+
self.tabs = RadioTabs(titles=_labels, descriptions=_descriptions, contents=_contents)
|
|
472
493
|
if len(self.modes) == 1:
|
|
473
494
|
self.layout = _contents[0]
|
|
474
495
|
else:
|
|
@@ -490,7 +511,7 @@ class DeployModel(Widget):
|
|
|
490
511
|
def _disconnect_button_clicked():
|
|
491
512
|
self.disconnect()
|
|
492
513
|
|
|
493
|
-
@self.tabs.
|
|
514
|
+
@self.tabs.value_changed
|
|
494
515
|
def _active_tab_changed(tab_name: str):
|
|
495
516
|
self.set_model_message_by_tab(tab_name)
|
|
496
517
|
|
|
@@ -573,6 +594,7 @@ class DeployModel(Widget):
|
|
|
573
594
|
f"Model {framework}: {model_name} deployed with session ID {model_api.task_id}."
|
|
574
595
|
)
|
|
575
596
|
self.model_api = model_api
|
|
597
|
+
self.statuses_widgets.show()
|
|
576
598
|
self.set_model_status("connected")
|
|
577
599
|
self.set_session_info(task_info)
|
|
578
600
|
self.set_model_info(model_api.task_id)
|
|
@@ -603,12 +625,14 @@ class DeployModel(Widget):
|
|
|
603
625
|
self.set_session_info(task_info)
|
|
604
626
|
self.set_model_info(model_api.task_id)
|
|
605
627
|
self.show_stop()
|
|
628
|
+
self.statuses_widgets.show()
|
|
606
629
|
except Exception as e:
|
|
607
630
|
logger.error(f"Failed to deploy model: {e}", exc_info=True)
|
|
608
631
|
self.set_model_status("error", str(e))
|
|
609
632
|
self.set_session_info(None)
|
|
610
633
|
self.reset_model_info()
|
|
611
634
|
self.show_deploy_button()
|
|
635
|
+
self.statuses_widgets.hide()
|
|
612
636
|
self.enable_modes()
|
|
613
637
|
else:
|
|
614
638
|
if str(self.MODE.CONNECT) in self.modes:
|
|
@@ -634,6 +658,7 @@ class DeployModel(Widget):
|
|
|
634
658
|
self.enable_modes()
|
|
635
659
|
self.reset_model_info()
|
|
636
660
|
self.show_deploy_button()
|
|
661
|
+
self.statuses_widgets.hide()
|
|
637
662
|
if str(self.MODE.CONNECT) in self.modes:
|
|
638
663
|
self.modes[str(self.MODE.CONNECT)]._update_sessions()
|
|
639
664
|
|
|
@@ -645,6 +670,7 @@ class DeployModel(Widget):
|
|
|
645
670
|
self.set_session_info(None)
|
|
646
671
|
self.reset_model_info()
|
|
647
672
|
self.show_deploy_button()
|
|
673
|
+
self.statuses_widgets.hide()
|
|
648
674
|
self.enable_modes()
|
|
649
675
|
|
|
650
676
|
def load_from_json(self, data: Dict[str, Any]) -> None:
|
|
@@ -690,29 +716,24 @@ class DeployModel(Widget):
|
|
|
690
716
|
title="Model Info",
|
|
691
717
|
description="Information about the deployed model",
|
|
692
718
|
)
|
|
693
|
-
|
|
694
|
-
self._model_info_container = Container([self._model_info_widget_field])
|
|
695
|
-
self._model_info_container.hide()
|
|
696
719
|
self._model_info_message = Text("Connect to model to see the session information.")
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
title="Session Info",
|
|
700
|
-
description="Model parameters and classes",
|
|
701
|
-
collapsable=True,
|
|
702
|
-
content=Container([self._model_info_container, self._model_info_message]),
|
|
720
|
+
self._model_info_container = Container(
|
|
721
|
+
[self._model_info_widget_field, self._model_info_message], gap=0
|
|
703
722
|
)
|
|
704
|
-
self.
|
|
723
|
+
self._model_info_widget_field.hide()
|
|
724
|
+
|
|
725
|
+
self._model_info_container.hide()
|
|
705
726
|
|
|
706
727
|
def set_model_info(self, session_id):
|
|
707
|
-
self._model_info_widget.
|
|
728
|
+
self._model_info_widget.set_session_id(session_id)
|
|
708
729
|
|
|
709
730
|
self._model_info_message.hide()
|
|
731
|
+
self._model_info_widget_field.show()
|
|
710
732
|
self._model_info_container.show()
|
|
711
|
-
self._model_info_card.uncollapse()
|
|
712
733
|
|
|
713
734
|
def reset_model_info(self):
|
|
714
|
-
self._model_info_card.collapse()
|
|
715
735
|
self._model_info_container.hide()
|
|
736
|
+
self._model_info_widget_field.hide()
|
|
716
737
|
self._model_info_message.show()
|
|
717
738
|
|
|
718
739
|
def set_model_message_by_tab(self, tab_name: str):
|
|
@@ -724,6 +745,6 @@ class DeployModel(Widget):
|
|
|
724
745
|
self._model_info_message.set(
|
|
725
746
|
"Deploy model to see the session information.", status="text"
|
|
726
747
|
)
|
|
727
|
-
self.
|
|
748
|
+
self._model_info_widget_field.hide()
|
|
728
749
|
|
|
729
750
|
# ------------------------------------------------------------ #
|
|
@@ -95,7 +95,7 @@ class EcosystemModelSelector(Widget):
|
|
|
95
95
|
for model in models:
|
|
96
96
|
if frameworks and model["framework"] not in frameworks:
|
|
97
97
|
continue
|
|
98
|
-
if task_types and model["
|
|
98
|
+
if task_types and model["task"] not in task_types:
|
|
99
99
|
continue
|
|
100
100
|
filtered_models.append(model)
|
|
101
101
|
return filtered_models
|
|
@@ -721,6 +721,14 @@ class ExperimentSelector(Widget):
|
|
|
721
721
|
def enable(self):
|
|
722
722
|
return self.table.enable()
|
|
723
723
|
|
|
724
|
+
@property
|
|
725
|
+
def loading(self):
|
|
726
|
+
return self.table.loading
|
|
727
|
+
|
|
728
|
+
@loading.setter
|
|
729
|
+
def loading(self, value: bool):
|
|
730
|
+
self.table.loading = value
|
|
731
|
+
|
|
724
732
|
def get_json_data(self):
|
|
725
733
|
return {}
|
|
726
734
|
|