supervisely 6.73.438__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 +137 -1
- supervisely/_utils.py +81 -0
- supervisely/annotation/annotation.py +8 -2
- supervisely/annotation/json_geometries_map.py +14 -11
- supervisely/annotation/label.py +80 -3
- supervisely/api/annotation_api.py +14 -11
- supervisely/api/api.py +59 -38
- supervisely/api/app_api.py +11 -2
- supervisely/api/dataset_api.py +74 -12
- supervisely/api/entities_collection_api.py +10 -0
- supervisely/api/entity_annotation/figure_api.py +52 -4
- 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 +72 -1
- supervisely/api/labeling_job_api.py +83 -1
- supervisely/api/labeling_queue_api.py +33 -7
- supervisely/api/module_api.py +9 -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/api/video/video_figure_api.py +24 -11
- 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/dialog/dialog.py +12 -0
- supervisely/app/widgets/dialog/template.html +2 -1
- 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/csv/csv_converter.py +24 -15
- 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 +24 -4
- 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/polyline_3d.py +110 -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 +916 -222
- supervisely/nn/inference/inference_request.py +55 -10
- 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 +118 -35
- supervisely/nn/inference/tracking/point_tracking.py +5 -1
- supervisely/nn/inference/tracking/tracker_interface.py +10 -1
- 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/model/prediction.py +2 -1
- supervisely/nn/model/prediction_session.py +26 -14
- supervisely/nn/prediction_dto.py +19 -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/utils.py +4 -5
- supervisely/nn/tracker/visualize.py +93 -93
- supervisely/nn/training/gui/classes_selector.py +16 -1
- supervisely/nn/training/gui/train_val_splits_selector.py +52 -31
- supervisely/nn/training/train_app.py +46 -31
- 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 +41 -12
- supervisely/video_annotation/video_figure.py +38 -4
- 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.438.dist-info → supervisely-6.73.513.dist-info}/METADATA +58 -40
- {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/RECORD +203 -155
- {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/WHEEL +1 -1
- supervisely_lib/__init__.py +6 -1
- {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info/licenses}/LICENSE +0 -0
- {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
"""create or manipulate guides that can be assigned to labeling jobs and labeling queues"""
|
|
3
|
+
|
|
4
|
+
# docs
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Dict, List, NamedTuple, Optional
|
|
8
|
+
|
|
9
|
+
from supervisely.api.module_api import ApiField, ModuleApiBase
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GuideInfo(NamedTuple):
|
|
13
|
+
"""
|
|
14
|
+
Information about a Guide.
|
|
15
|
+
|
|
16
|
+
:param id: Guide ID in Supervisely.
|
|
17
|
+
:type id: int
|
|
18
|
+
:param name: Guide name.
|
|
19
|
+
:type name: str
|
|
20
|
+
:param description: Guide description.
|
|
21
|
+
:type description: str
|
|
22
|
+
:param file_path: Path to the guide file (PDF or other).
|
|
23
|
+
:type file_path: str
|
|
24
|
+
:param created_at: Guide creation date.
|
|
25
|
+
:type created_at: str
|
|
26
|
+
:param updated_at: Guide last update date.
|
|
27
|
+
:type updated_at: str
|
|
28
|
+
:param created_by_id: ID of the User who created the Guide.
|
|
29
|
+
:type created_by_id: int
|
|
30
|
+
:param team_id: Team ID where the Guide is located.
|
|
31
|
+
:type team_id: int
|
|
32
|
+
:param video_id: ID of the video associated with the guide (if any).
|
|
33
|
+
:type video_id: Optional[int]
|
|
34
|
+
:param disabled_by: ID of the User who disabled the Guide (if disabled).
|
|
35
|
+
:type disabled_by: Optional[int]
|
|
36
|
+
:param disabled_at: Date when the Guide was disabled (if disabled).
|
|
37
|
+
:type disabled_at: Optional[str]
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
id: int
|
|
41
|
+
name: str
|
|
42
|
+
description: str
|
|
43
|
+
file_path: str
|
|
44
|
+
created_at: str
|
|
45
|
+
updated_at: str
|
|
46
|
+
created_by_id: int
|
|
47
|
+
team_id: int
|
|
48
|
+
video_id: Optional[int] = None
|
|
49
|
+
disabled_by: Optional[int] = None
|
|
50
|
+
disabled_at: Optional[str] = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class GuidesApi(ModuleApiBase):
|
|
54
|
+
"""
|
|
55
|
+
API for working with Guides. :class:`GuidesApi<GuidesApi>` object is immutable.
|
|
56
|
+
|
|
57
|
+
:param api: API connection to the server.
|
|
58
|
+
:type api: Api
|
|
59
|
+
:Usage example:
|
|
60
|
+
|
|
61
|
+
.. code-block:: python
|
|
62
|
+
|
|
63
|
+
import os
|
|
64
|
+
from dotenv import load_dotenv
|
|
65
|
+
|
|
66
|
+
import supervisely as sly
|
|
67
|
+
|
|
68
|
+
# Load secrets and create API object from .env file (recommended)
|
|
69
|
+
# Learn more here: https://developer.supervisely.com/getting-started/basics-of-authentication
|
|
70
|
+
|
|
71
|
+
api = sly.Api.from_env()
|
|
72
|
+
|
|
73
|
+
# Get list of guides in team
|
|
74
|
+
guides = api.guides.get_list(team_id=123)
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def info_sequence():
|
|
79
|
+
"""
|
|
80
|
+
NamedTuple GuideInfo information about Guide.
|
|
81
|
+
|
|
82
|
+
:Example:
|
|
83
|
+
|
|
84
|
+
.. code-block:: python
|
|
85
|
+
|
|
86
|
+
GuideInfo(
|
|
87
|
+
id=1,
|
|
88
|
+
name='How to label objects',
|
|
89
|
+
description='Comprehensive guide on object labeling',
|
|
90
|
+
file_path='/path/to/guide.pdf',
|
|
91
|
+
created_at='2023-01-01T00:00:00.000Z',
|
|
92
|
+
updated_at='2025-11-17T18:21:10.217Z',
|
|
93
|
+
created_by_id=1,
|
|
94
|
+
team_id=1,
|
|
95
|
+
video_id=None,
|
|
96
|
+
disabled_by=None,
|
|
97
|
+
disabled_at=None
|
|
98
|
+
)
|
|
99
|
+
"""
|
|
100
|
+
return [
|
|
101
|
+
ApiField.ID,
|
|
102
|
+
ApiField.NAME,
|
|
103
|
+
ApiField.DESCRIPTION,
|
|
104
|
+
ApiField.FILE_PATH,
|
|
105
|
+
ApiField.CREATED_AT,
|
|
106
|
+
ApiField.UPDATED_AT,
|
|
107
|
+
ApiField.CREATED_BY_ID,
|
|
108
|
+
ApiField.TEAM_ID,
|
|
109
|
+
ApiField.VIDEO_ID,
|
|
110
|
+
ApiField.DISABLED_BY,
|
|
111
|
+
ApiField.DISABLED_AT,
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def info_tuple_name():
|
|
116
|
+
"""
|
|
117
|
+
NamedTuple name - **GuideInfo**.
|
|
118
|
+
"""
|
|
119
|
+
return "GuideInfo"
|
|
120
|
+
|
|
121
|
+
def get_list(
|
|
122
|
+
self, team_id: int, filters: Optional[List[Dict[str, str]]] = None
|
|
123
|
+
) -> List[GuideInfo]:
|
|
124
|
+
"""
|
|
125
|
+
Get list of Guides in the given Team.
|
|
126
|
+
|
|
127
|
+
:param team_id: Team ID in Supervisely.
|
|
128
|
+
:type team_id: int
|
|
129
|
+
:param filters: List of parameters to filter Guides.
|
|
130
|
+
:type filters: List[Dict[str, str]], optional
|
|
131
|
+
:return: List of information about Guides.
|
|
132
|
+
:rtype: :class:`List[GuideInfo]`
|
|
133
|
+
:Usage example:
|
|
134
|
+
|
|
135
|
+
.. code-block:: python
|
|
136
|
+
|
|
137
|
+
import os
|
|
138
|
+
from dotenv import load_dotenv
|
|
139
|
+
|
|
140
|
+
import supervisely as sly
|
|
141
|
+
|
|
142
|
+
# Load secrets and create API object from .env file (recommended)
|
|
143
|
+
# Learn more here: https://developer.supervisely.com/getting-started/basics-of-authentication
|
|
144
|
+
|
|
145
|
+
api = sly.Api.from_env()
|
|
146
|
+
|
|
147
|
+
team_id = 123
|
|
148
|
+
guides = api.guides.get_list(team_id)
|
|
149
|
+
print(guides)
|
|
150
|
+
# Output: [
|
|
151
|
+
# GuideInfo(
|
|
152
|
+
# id=1,
|
|
153
|
+
# name='How to label objects',
|
|
154
|
+
# description='Comprehensive guide on object labeling',
|
|
155
|
+
# file_path='/path/to/guide.pdf',
|
|
156
|
+
# created_at='2023-01-01T00:00:00.000Z',
|
|
157
|
+
# updated_at='2025-11-17T18:21:10.217Z',
|
|
158
|
+
# created_by_id=1,
|
|
159
|
+
# team_id=1,
|
|
160
|
+
# video_id=None,
|
|
161
|
+
# disabled_by=None,
|
|
162
|
+
# disabled_at=None
|
|
163
|
+
# )
|
|
164
|
+
# ]
|
|
165
|
+
"""
|
|
166
|
+
return self.get_list_all_pages(
|
|
167
|
+
"guides.list",
|
|
168
|
+
{ApiField.TEAM_ID: team_id, ApiField.FILTER: filters or []},
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
def get_info_by_id(self, id: int) -> GuideInfo:
|
|
172
|
+
"""
|
|
173
|
+
Get Guide information by ID.
|
|
174
|
+
|
|
175
|
+
:param id: Guide ID in Supervisely.
|
|
176
|
+
:type id: int
|
|
177
|
+
:return: Information about Guide.
|
|
178
|
+
:rtype: :class:`GuideInfo`
|
|
179
|
+
:Usage example:
|
|
180
|
+
|
|
181
|
+
.. code-block:: python
|
|
182
|
+
|
|
183
|
+
import os
|
|
184
|
+
from dotenv import load_dotenv
|
|
185
|
+
|
|
186
|
+
import supervisely as sly
|
|
187
|
+
|
|
188
|
+
# Load secrets and create API object from .env file (recommended)
|
|
189
|
+
# Learn more here: https://developer.supervisely.com/getting-started/basics-of-authentication
|
|
190
|
+
|
|
191
|
+
api = sly.Api.from_env()
|
|
192
|
+
|
|
193
|
+
guide_id = 1
|
|
194
|
+
guide_info = api.guides.get_info_by_id(guide_id)
|
|
195
|
+
print(guide_info)
|
|
196
|
+
# Output: GuideInfo(
|
|
197
|
+
# id=1,
|
|
198
|
+
# name='How to label objects',
|
|
199
|
+
# description='Comprehensive guide on object labeling',
|
|
200
|
+
# file_path='/path/to/guide.pdf',
|
|
201
|
+
# created_at='2023-01-01T00:00:00.000Z',
|
|
202
|
+
# updated_at='2025-11-17T18:21:10.217Z',
|
|
203
|
+
# created_by_id=1,
|
|
204
|
+
# team_id=1,
|
|
205
|
+
# video_id=None,
|
|
206
|
+
# disabled_by=None,
|
|
207
|
+
# disabled_at=None
|
|
208
|
+
# )
|
|
209
|
+
"""
|
|
210
|
+
return self._get_info_by_id(id, "guides.info")
|
supervisely/api/image_api.py
CHANGED
|
@@ -70,7 +70,11 @@ from supervisely.api.module_api import (
|
|
|
70
70
|
_get_single_item,
|
|
71
71
|
)
|
|
72
72
|
from supervisely.imaging import image as sly_image
|
|
73
|
-
from supervisely.io.env import
|
|
73
|
+
from supervisely.io.env import (
|
|
74
|
+
add_uploaded_ids_to_env,
|
|
75
|
+
app_categories,
|
|
76
|
+
increment_upload_count,
|
|
77
|
+
)
|
|
74
78
|
from supervisely.io.fs import (
|
|
75
79
|
OFFSETS_PKL_BATCH_SIZE,
|
|
76
80
|
OFFSETS_PKL_SUFFIX,
|
|
@@ -393,6 +397,9 @@ class ImageInfo(NamedTuple):
|
|
|
393
397
|
#: Format: "YYYY-MM-DDTHH:MM:SS.sssZ"
|
|
394
398
|
embeddings_updated_at: Optional[str] = None
|
|
395
399
|
|
|
400
|
+
#: :class:`int`: :class:`Dataset<supervisely.project.project.Project>` ID in Supervisely.
|
|
401
|
+
project_id: int = None
|
|
402
|
+
|
|
396
403
|
# DO NOT DELETE THIS COMMENT
|
|
397
404
|
#! New fields must be added with default values to keep backward compatibility.
|
|
398
405
|
|
|
@@ -472,6 +479,7 @@ class ImageApi(RemoveableBulkModuleApi):
|
|
|
472
479
|
ApiField.OFFSET_END,
|
|
473
480
|
ApiField.AI_SEARCH_META,
|
|
474
481
|
ApiField.EMBEDDINGS_UPDATED_AT,
|
|
482
|
+
ApiField.PROJECT_ID,
|
|
475
483
|
]
|
|
476
484
|
|
|
477
485
|
@staticmethod
|
|
@@ -5519,3 +5527,66 @@ class ImageApi(RemoveableBulkModuleApi):
|
|
|
5519
5527
|
method,
|
|
5520
5528
|
{ApiField.IMAGES: images},
|
|
5521
5529
|
)
|
|
5530
|
+
|
|
5531
|
+
def get_subsequent_image_ids(
|
|
5532
|
+
self,
|
|
5533
|
+
image_id: int,
|
|
5534
|
+
images_count: Optional[int] = None,
|
|
5535
|
+
job_id: Optional[int] = None,
|
|
5536
|
+
params: Optional[dict] = None,
|
|
5537
|
+
dataset_id: Optional[int] = None,
|
|
5538
|
+
project_id: Optional[int] = None,
|
|
5539
|
+
) -> List[int]:
|
|
5540
|
+
"""
|
|
5541
|
+
Get list of subsequent image IDs after the specified image ID.
|
|
5542
|
+
|
|
5543
|
+
:param image_id: Image ID in Supervisely.
|
|
5544
|
+
:type image_id: int
|
|
5545
|
+
:param images_count: Number of subsequent images to retrieve. If None, retrieves all subsequent images.
|
|
5546
|
+
:type images_count: int, optional
|
|
5547
|
+
:param job_id: Job ID to filter images. If None, does not filter by job ID.
|
|
5548
|
+
:type job_id: int, optional
|
|
5549
|
+
:param params: Additional parameters for filtering and sorting images.
|
|
5550
|
+
:type params: dict, optional
|
|
5551
|
+
:param dataset_id: Dataset ID to filter images.
|
|
5552
|
+
:type dataset_id: int, optional
|
|
5553
|
+
:param project_id: Project ID to filter images. If None, makes a request to retrieve it from the specified image.
|
|
5554
|
+
:type project_id: int, optional
|
|
5555
|
+
"""
|
|
5556
|
+
data = {
|
|
5557
|
+
"recursive": True,
|
|
5558
|
+
"projectId": project_id,
|
|
5559
|
+
"filters": [],
|
|
5560
|
+
"sort": "name",
|
|
5561
|
+
"sort_order": "asc",
|
|
5562
|
+
}
|
|
5563
|
+
|
|
5564
|
+
if params is not None:
|
|
5565
|
+
data.update(params)
|
|
5566
|
+
|
|
5567
|
+
if data["projectId"] is None:
|
|
5568
|
+
image_info = self.get_info_by_id(image_id)
|
|
5569
|
+
if image_info is None:
|
|
5570
|
+
raise ValueError(f"Image with ID {image_id} not found.")
|
|
5571
|
+
project_id = self._api.dataset.get_info_by_id(image_info.dataset_id).project_id
|
|
5572
|
+
if job_id is not None:
|
|
5573
|
+
self._api.add_header("x-job-id", str(job_id))
|
|
5574
|
+
if dataset_id is not None:
|
|
5575
|
+
data["datasetId"] = dataset_id
|
|
5576
|
+
|
|
5577
|
+
image_infos = self.get_list_all_pages(
|
|
5578
|
+
"images.list",
|
|
5579
|
+
data,
|
|
5580
|
+
limit=None,
|
|
5581
|
+
return_first_response=False,
|
|
5582
|
+
)
|
|
5583
|
+
self._api.headers.pop("x-job-id", None)
|
|
5584
|
+
image_ids = [img_info.id for img_info in image_infos]
|
|
5585
|
+
if len(image_ids) == 0:
|
|
5586
|
+
raise ValueError("No images found with the specified criteria.")
|
|
5587
|
+
elif image_id not in image_ids:
|
|
5588
|
+
raise ValueError(f"Image with ID {image_id} not found in the specified entity.")
|
|
5589
|
+
|
|
5590
|
+
target_idx = image_ids.index(image_id) + 1
|
|
5591
|
+
to_idx = target_idx + images_count if images_count is not None else len(image_ids)
|
|
5592
|
+
return image_ids[target_idx:to_idx]
|
|
@@ -89,6 +89,7 @@ class LabelingJobInfo(NamedTuple):
|
|
|
89
89
|
exclude_images_with_tags: list
|
|
90
90
|
entities: list
|
|
91
91
|
priority: int
|
|
92
|
+
guide_id: Optional[int] = None
|
|
92
93
|
|
|
93
94
|
|
|
94
95
|
class LabelingJobApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
@@ -223,6 +224,7 @@ class LabelingJobApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
223
224
|
ApiField.EXCLUDE_IMAGES_WITH_TAGS,
|
|
224
225
|
ApiField.ENTITIES,
|
|
225
226
|
ApiField.PRIORITY,
|
|
227
|
+
ApiField.M_GUIDE_ID,
|
|
226
228
|
]
|
|
227
229
|
|
|
228
230
|
@staticmethod
|
|
@@ -261,7 +263,10 @@ class LabelingJobApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
261
263
|
else:
|
|
262
264
|
value = info[sub_name]
|
|
263
265
|
else:
|
|
264
|
-
|
|
266
|
+
if skip_missing is True:
|
|
267
|
+
value = value.get(sub_name, None)
|
|
268
|
+
else:
|
|
269
|
+
value = value[sub_name]
|
|
265
270
|
else:
|
|
266
271
|
raise RuntimeError("Can not parse field {!r}".format(field_name))
|
|
267
272
|
|
|
@@ -341,6 +346,8 @@ class LabelingJobApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
341
346
|
disable_submit: Optional[bool] = None,
|
|
342
347
|
toolbox_settings: Optional[Dict] = None,
|
|
343
348
|
enable_quality_check: Optional[bool] = None,
|
|
349
|
+
guide_id: Optional[int] = None,
|
|
350
|
+
allow_restore: bool = False,
|
|
344
351
|
) -> List[LabelingJobInfo]:
|
|
345
352
|
"""
|
|
346
353
|
Creates Labeling Job and assigns given Users to it.
|
|
@@ -385,6 +392,10 @@ class LabelingJobApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
385
392
|
:type toolbox_settings: Dict, optional
|
|
386
393
|
:param enable_quality_check: If True, adds an intermediate step between "review" and completing the Labeling Job.
|
|
387
394
|
:type enable_quality_check: bool, optional
|
|
395
|
+
:param guide_id: Guide ID in Supervisely to assign a guide to the Labeling Job.
|
|
396
|
+
:type guide_id: int, optional
|
|
397
|
+
:param allow_restore: If True, allows restoring a previously deleted labeling job with the same name in the same dataset.
|
|
398
|
+
:type allow_restore: bool
|
|
388
399
|
:return: List of information about new Labeling Job. See :class:`info_sequence<info_sequence>`
|
|
389
400
|
:rtype: :class:`List[LabelingJobInfo]`
|
|
390
401
|
:Usage example:
|
|
@@ -463,8 +474,18 @@ class LabelingJobApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
463
474
|
"entityIds": images_ids,
|
|
464
475
|
"dynamicClasses": dynamic_classes,
|
|
465
476
|
"dynamicTags": dynamic_tags,
|
|
477
|
+
"allowRestore": allow_restore,
|
|
466
478
|
}
|
|
467
479
|
|
|
480
|
+
if guide_id is not None:
|
|
481
|
+
try:
|
|
482
|
+
guide_id = int(guide_id)
|
|
483
|
+
except Exception as e:
|
|
484
|
+
raise ValueError(
|
|
485
|
+
f"guide_id must be an integer, got {type(guide_id)} with value '{guide_id}'"
|
|
486
|
+
) from None
|
|
487
|
+
meta["guide"] = guide_id
|
|
488
|
+
|
|
468
489
|
if toolbox_settings is not None:
|
|
469
490
|
dataset_info = self._api.dataset.get_info_by_id(dataset_id)
|
|
470
491
|
project_id = dataset_info.project_id
|
|
@@ -1460,3 +1481,64 @@ class LabelingJobApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
1460
1481
|
|
|
1461
1482
|
response = self._api.post("jobs.restart", data).json()
|
|
1462
1483
|
return response
|
|
1484
|
+
|
|
1485
|
+
def get_custom_data(self, id: int) -> dict:
|
|
1486
|
+
"""
|
|
1487
|
+
Get custom data of Labeling Job with given ID.
|
|
1488
|
+
|
|
1489
|
+
:param id: Labeling Job ID in Supervisely.
|
|
1490
|
+
:type id: int
|
|
1491
|
+
:return: Custom data of the job
|
|
1492
|
+
:rtype: :class:`dict`
|
|
1493
|
+
:Usage example:
|
|
1494
|
+
|
|
1495
|
+
.. code-block:: python
|
|
1496
|
+
|
|
1497
|
+
import supervisely as sly
|
|
1498
|
+
|
|
1499
|
+
os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
|
|
1500
|
+
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
|
|
1501
|
+
api = sly.Api.from_env()
|
|
1502
|
+
|
|
1503
|
+
custom_data = api.labeling_job.get_custom_data(9)
|
|
1504
|
+
print(custom_data)
|
|
1505
|
+
"""
|
|
1506
|
+
method = "jobs.info"
|
|
1507
|
+
response = self._get_response_by_id(id, method, id_field=ApiField.ID)
|
|
1508
|
+
json_response = response.json() if response is not None else None
|
|
1509
|
+
if json_response is not None:
|
|
1510
|
+
return json_response.get(ApiField.CUSTOM_DATA, {})
|
|
1511
|
+
return {}
|
|
1512
|
+
|
|
1513
|
+
def set_custom_data(self, id: int, custom_data: dict, update: bool = True) -> None:
|
|
1514
|
+
"""
|
|
1515
|
+
Update or replace custom data of Labeling Job with given ID.
|
|
1516
|
+
By default, updates existing custom data. To replace it entirely, set `update` to False.
|
|
1517
|
+
|
|
1518
|
+
:param id: Labeling Job ID in Supervisely.
|
|
1519
|
+
:type id: int
|
|
1520
|
+
:param custom_data: Custom data to set
|
|
1521
|
+
:type custom_data: dict
|
|
1522
|
+
:param update: Whether to update existing custom data or replace it entirely.
|
|
1523
|
+
:type update: bool
|
|
1524
|
+
:return: None
|
|
1525
|
+
:rtype: :class:`NoneType`
|
|
1526
|
+
:Usage example:
|
|
1527
|
+
|
|
1528
|
+
.. code-block:: python
|
|
1529
|
+
|
|
1530
|
+
import supervisely as sly
|
|
1531
|
+
|
|
1532
|
+
os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
|
|
1533
|
+
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
|
|
1534
|
+
api = sly.Api.from_env()
|
|
1535
|
+
|
|
1536
|
+
api.labeling_job.set_custom_data(9, {"key": "value"})
|
|
1537
|
+
"""
|
|
1538
|
+
method = "jobs.editInfo"
|
|
1539
|
+
|
|
1540
|
+
if update is True:
|
|
1541
|
+
existing_custom_data = self.get_custom_data(id)
|
|
1542
|
+
existing_custom_data.update(custom_data)
|
|
1543
|
+
custom_data = existing_custom_data
|
|
1544
|
+
self._api.post(method, {ApiField.ID: id, ApiField.CUSTOM_DATA: custom_data})
|
|
@@ -37,6 +37,7 @@ class LabelingQueueInfo(NamedTuple):
|
|
|
37
37
|
in_progress_count: int
|
|
38
38
|
pending_count: int
|
|
39
39
|
meta: dict
|
|
40
|
+
collection_id: Optional[int] = None
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
@@ -93,7 +94,8 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
93
94
|
annotated_count=3,
|
|
94
95
|
in_progress_count=2,
|
|
95
96
|
pending_count=1,
|
|
96
|
-
meta={}
|
|
97
|
+
meta={},
|
|
98
|
+
collection_id=None,
|
|
97
99
|
)
|
|
98
100
|
"""
|
|
99
101
|
return [
|
|
@@ -115,6 +117,7 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
115
117
|
ApiField.IN_PROGRESS_COUNT,
|
|
116
118
|
ApiField.PENDING_COUNT,
|
|
117
119
|
ApiField.META,
|
|
120
|
+
ApiField.COLLECTION_ID,
|
|
118
121
|
]
|
|
119
122
|
|
|
120
123
|
@staticmethod
|
|
@@ -200,24 +203,24 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
200
203
|
skip_complete_job_on_empty: Optional[bool] = False,
|
|
201
204
|
enable_quality_check: Optional[bool] = None,
|
|
202
205
|
quality_check_user_ids: Optional[List[int]] = None,
|
|
206
|
+
guide_id: Optional[int] = None,
|
|
207
|
+
description: Optional[str] = None,
|
|
203
208
|
) -> int:
|
|
204
209
|
"""
|
|
205
210
|
Creates Labeling Queue and assigns given Users to it.
|
|
206
211
|
|
|
207
212
|
:param name: Labeling Queue name in Supervisely.
|
|
208
213
|
:type name: str
|
|
209
|
-
:param dataset_id: Dataset ID in Supervisely.
|
|
210
|
-
:type dataset_id: int
|
|
211
|
-
:param collection_id: Entities Collection ID in Supervisely.
|
|
212
|
-
:type collection_id: int, optional
|
|
213
214
|
:param user_ids: User IDs in Supervisely to assign Users as labelers to Labeling Queue.
|
|
214
215
|
:type user_ids: List[int]
|
|
215
216
|
:param reviewer_ids: User IDs in Supervisely to assign Users as reviewers to Labeling Queue.
|
|
216
217
|
:type reviewer_ids: List[int]
|
|
218
|
+
:param dataset_id: Dataset ID in Supervisely.
|
|
219
|
+
:type dataset_id: int
|
|
220
|
+
:param collection_id: Entities Collection ID in Supervisely.
|
|
221
|
+
:type collection_id: int, optional
|
|
217
222
|
:param readme: Additional information about Labeling Queue.
|
|
218
223
|
:type readme: str, optional
|
|
219
|
-
:param description: Description of Labeling Queue.
|
|
220
|
-
:type description: str, optional
|
|
221
224
|
:param classes_to_label: List of classes to label in Dataset.
|
|
222
225
|
:type classes_to_label: List[str], optional
|
|
223
226
|
:param objects_limit_per_image: Limit the number of objects that the labeler can create on each image.
|
|
@@ -256,6 +259,10 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
256
259
|
:type enable_quality_check: bool, optional
|
|
257
260
|
:param quality_check_user_ids: List of User IDs in Supervisely to assign Users as Quality Checkers to Labeling Queue.
|
|
258
261
|
:type quality_check_user_ids: List[int], optional
|
|
262
|
+
:param guide_id: Guide ID in Supervisely to assign a guide to the Labeling Queue.
|
|
263
|
+
:type guide_id: int, optional
|
|
264
|
+
:param description: Description of Labeling Queue.
|
|
265
|
+
:type description: str, optional
|
|
259
266
|
:return: Labeling Queue ID in Supervisely.
|
|
260
267
|
:rtype: int
|
|
261
268
|
:Usage example:
|
|
@@ -340,6 +347,15 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
340
347
|
if images_ids is not None:
|
|
341
348
|
meta["entityIds"] = images_ids
|
|
342
349
|
|
|
350
|
+
if guide_id is not None:
|
|
351
|
+
try:
|
|
352
|
+
guide_id = int(guide_id)
|
|
353
|
+
except Exception as e:
|
|
354
|
+
raise ValueError(
|
|
355
|
+
f"guide_id must be an integer, got {type(guide_id)} with value '{guide_id}'"
|
|
356
|
+
) from None
|
|
357
|
+
meta["guide"] = guide_id
|
|
358
|
+
|
|
343
359
|
if toolbox_settings is not None:
|
|
344
360
|
if dataset_id is not None:
|
|
345
361
|
dataset_info = self._api.dataset.get_info_by_id(dataset_id)
|
|
@@ -399,6 +415,9 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
399
415
|
if readme is not None:
|
|
400
416
|
data[ApiField.README] = str(readme)
|
|
401
417
|
|
|
418
|
+
if description is not None:
|
|
419
|
+
data[ApiField.DESCRIPTION] = str(description)
|
|
420
|
+
|
|
402
421
|
if images_range is not None and images_range != (None, None):
|
|
403
422
|
if len(images_range) != 2:
|
|
404
423
|
raise RuntimeError("images_range has to contain 2 elements (start, end)")
|
|
@@ -419,6 +438,7 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
419
438
|
ids: Optional[List[int]] = None,
|
|
420
439
|
names: Optional[List[str]] = None,
|
|
421
440
|
show_disabled: Optional[bool] = False,
|
|
441
|
+
collection_id: Optional[int] = None,
|
|
422
442
|
) -> List[LabelingQueueInfo]:
|
|
423
443
|
"""
|
|
424
444
|
Get list of information about Labeling Queues in the given Team.
|
|
@@ -435,6 +455,8 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
435
455
|
:type names: List[str], optional
|
|
436
456
|
:param show_disabled: Show disabled Labeling Queues.
|
|
437
457
|
:type show_disabled: bool, optional
|
|
458
|
+
:param collection_id: Entities Collection ID in Supervisely.
|
|
459
|
+
:type collection_id: int, optional
|
|
438
460
|
:return: List of information about Labeling Queues. See :class:`info_sequence<info_sequence>`
|
|
439
461
|
:rtype: :class:`List[LabelingQueueInfo]`
|
|
440
462
|
:Usage example:
|
|
@@ -455,6 +477,10 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
455
477
|
filters.append({"field": ApiField.PROJECT_ID, "operator": "=", "value": project_id})
|
|
456
478
|
if dataset_id is not None:
|
|
457
479
|
filters.append({"field": ApiField.DATASET_ID, "operator": "=", "value": dataset_id})
|
|
480
|
+
if collection_id is not None:
|
|
481
|
+
filters.append(
|
|
482
|
+
{"field": ApiField.COLLECTION_ID, "operator": "=", "value": collection_id}
|
|
483
|
+
)
|
|
458
484
|
if names is not None:
|
|
459
485
|
filters.append({"field": ApiField.NAME, "operator": "in", "value": names})
|
|
460
486
|
if ids is not None:
|
supervisely/api/module_api.py
CHANGED
|
@@ -709,6 +709,15 @@ class ApiField:
|
|
|
709
709
|
""""""
|
|
710
710
|
UNIQUE_ITEMS = "uniqueItems"
|
|
711
711
|
""""""
|
|
712
|
+
NN_CREATED = "nnCreated"
|
|
713
|
+
""""""
|
|
714
|
+
NN_UPDATED = "nnUpdated"
|
|
715
|
+
""""""
|
|
716
|
+
M_GUIDE_ID = (["meta", "guide"], "guide_id")
|
|
717
|
+
""""""
|
|
718
|
+
GUIDE_ID = "guideId"
|
|
719
|
+
""""""
|
|
720
|
+
SINGLE_SESSION_MODE = "singleSessionMode"
|
|
712
721
|
|
|
713
722
|
|
|
714
723
|
def _get_single_item(items):
|