supervisely 6.73.408__py3-none-any.whl → 6.73.410__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 +6 -4
- supervisely/_utils.py +39 -0
- supervisely/api/module_api.py +8 -0
- supervisely/api/project_api.py +169 -26
- supervisely/io/env.py +15 -0
- supervisely/nn/benchmark/object_detection/vis_metrics/f1_score_at_different_iou.py +3 -0
- supervisely/pointcloud_annotation/pointcloud_episode_tag.py +23 -3
- supervisely/versions.json +26 -0
- {supervisely-6.73.408.dist-info → supervisely-6.73.410.dist-info}/METADATA +1 -1
- {supervisely-6.73.408.dist-info → supervisely-6.73.410.dist-info}/RECORD +14 -13
- {supervisely-6.73.408.dist-info → supervisely-6.73.410.dist-info}/LICENSE +0 -0
- {supervisely-6.73.408.dist-info → supervisely-6.73.410.dist-info}/WHEEL +0 -0
- {supervisely-6.73.408.dist-info → supervisely-6.73.410.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.408.dist-info → supervisely-6.73.410.dist-info}/top_level.txt +0 -0
supervisely/__init__.py
CHANGED
|
@@ -312,7 +312,9 @@ try:
|
|
|
312
312
|
except Exception as e:
|
|
313
313
|
logger.warn(f"Failed to setup certificates. Reason: {repr(e)}", exc_info=True)
|
|
314
314
|
|
|
315
|
-
#
|
|
316
|
-
#
|
|
317
|
-
#
|
|
318
|
-
|
|
315
|
+
# Configure minimum instance version automatically from versions.json
|
|
316
|
+
# if new changes in Supervisely Python SDK require upgrade of the Supervisely instance.
|
|
317
|
+
# If the instance version is lower than the SDK version, users can face compatibility issues.
|
|
318
|
+
from supervisely.io.env import configure_minimum_instance_version
|
|
319
|
+
|
|
320
|
+
configure_minimum_instance_version()
|
supervisely/_utils.py
CHANGED
|
@@ -597,3 +597,42 @@ def remove_non_printable(text: str) -> str:
|
|
|
597
597
|
:rtype: str
|
|
598
598
|
"""
|
|
599
599
|
return "".join(char for char in text if char.isprintable()).strip()
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
def get_latest_instance_version_from_json() -> Optional[str]:
|
|
603
|
+
"""
|
|
604
|
+
Get the latest (last) instance version from versions.json file.
|
|
605
|
+
|
|
606
|
+
The versions.json file should contain a mapping of SDK versions to instance versions.
|
|
607
|
+
This function returns the instance version from the last entry in the file.
|
|
608
|
+
|
|
609
|
+
:return: Latest instance version or None if not found
|
|
610
|
+
:rtype: Optional[str]
|
|
611
|
+
"""
|
|
612
|
+
import json
|
|
613
|
+
|
|
614
|
+
try:
|
|
615
|
+
# Get the path to versions.json relative to this file
|
|
616
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
617
|
+
versions_file = os.path.join(current_dir, "versions.json")
|
|
618
|
+
|
|
619
|
+
if not os.path.exists(versions_file):
|
|
620
|
+
logger.debug(f"versions.json file not found at {versions_file}")
|
|
621
|
+
return None
|
|
622
|
+
|
|
623
|
+
with open(versions_file, "r", encoding="utf-8") as f:
|
|
624
|
+
versions_mapping = json.load(f)
|
|
625
|
+
|
|
626
|
+
if not versions_mapping:
|
|
627
|
+
return None
|
|
628
|
+
|
|
629
|
+
# Get the last (latest) entry from the versions mapping
|
|
630
|
+
# Since JSON preserves order in Python 3.7+, the last item is the latest
|
|
631
|
+
latest_instance_version = list(versions_mapping.keys())[-1]
|
|
632
|
+
logger.debug(f"Latest instance version found: {latest_instance_version}")
|
|
633
|
+
return latest_instance_version
|
|
634
|
+
|
|
635
|
+
except Exception:
|
|
636
|
+
# Silently fail - don't break the import if versions.json is missing or malformed
|
|
637
|
+
logger.debug("Failed to get latest instance version from versions.json")
|
|
638
|
+
return None
|
supervisely/api/module_api.py
CHANGED
|
@@ -695,6 +695,14 @@ class ApiField:
|
|
|
695
695
|
""""""
|
|
696
696
|
REMOTE_ENTITIES_COUNT = "remoteEntitiesCount"
|
|
697
697
|
""""""
|
|
698
|
+
RESTRICTED_IMAGE_IDS = "restrictedImageIds"
|
|
699
|
+
""""""
|
|
700
|
+
NUMBER_OF_CLUSTERS = "numberOfClusters"
|
|
701
|
+
""""""
|
|
702
|
+
CLUSTERING_METHOD = "clusteringMethod"
|
|
703
|
+
""""""
|
|
704
|
+
ERROR_MESSAGE = "errorMessage"
|
|
705
|
+
""""""
|
|
698
706
|
|
|
699
707
|
|
|
700
708
|
def _get_single_item(items):
|
supervisely/api/project_api.py
CHANGED
|
@@ -215,6 +215,39 @@ class ProjectApi(CloneableModuleApi, UpdateableModule, RemoveableModuleApi):
|
|
|
215
215
|
ApiField.REMOTE_ENTITIES_COUNT,
|
|
216
216
|
]
|
|
217
217
|
|
|
218
|
+
@staticmethod
|
|
219
|
+
def info_sequence_for_listing():
|
|
220
|
+
"""
|
|
221
|
+
NamedTuple ProjectInfo fields available for listing operations.
|
|
222
|
+
|
|
223
|
+
This subset includes only fields that are available in the `projects.list` API endpoint.
|
|
224
|
+
For complete project information, use `get_info_by_id()`.
|
|
225
|
+
|
|
226
|
+
:return: List of API field names available for listing
|
|
227
|
+
:rtype: List[str]
|
|
228
|
+
"""
|
|
229
|
+
return [
|
|
230
|
+
ApiField.ID,
|
|
231
|
+
ApiField.NAME,
|
|
232
|
+
ApiField.DESCRIPTION,
|
|
233
|
+
ApiField.SIZE,
|
|
234
|
+
ApiField.README,
|
|
235
|
+
ApiField.WORKSPACE_ID,
|
|
236
|
+
ApiField.IMAGES_COUNT, # for compatibility with existing code
|
|
237
|
+
ApiField.DATASETS_COUNT,
|
|
238
|
+
ApiField.CREATED_AT,
|
|
239
|
+
ApiField.UPDATED_AT,
|
|
240
|
+
ApiField.TYPE,
|
|
241
|
+
ApiField.REFERENCE_IMAGE_URL,
|
|
242
|
+
ApiField.CUSTOM_DATA,
|
|
243
|
+
ApiField.BACKUP_ARCHIVE,
|
|
244
|
+
ApiField.TEAM_ID,
|
|
245
|
+
ApiField.IMPORT_SETTINGS,
|
|
246
|
+
ApiField.EMBEDDINGS_ENABLED,
|
|
247
|
+
ApiField.EMBEDDINGS_UPDATED_AT,
|
|
248
|
+
ApiField.EMBEDDINGS_IN_PROGRESS,
|
|
249
|
+
]
|
|
250
|
+
|
|
218
251
|
@staticmethod
|
|
219
252
|
def info_tuple_name():
|
|
220
253
|
"""
|
|
@@ -347,7 +380,7 @@ class ProjectApi(CloneableModuleApi, UpdateableModule, RemoveableModuleApi):
|
|
|
347
380
|
id: int,
|
|
348
381
|
expected_type: Optional[str] = None,
|
|
349
382
|
raise_error: bool = False,
|
|
350
|
-
extra_fields: Optional[List[str]] = None
|
|
383
|
+
extra_fields: Optional[List[str]] = None,
|
|
351
384
|
) -> ProjectInfo:
|
|
352
385
|
"""
|
|
353
386
|
Get Project information by ID.
|
|
@@ -457,21 +490,24 @@ class ProjectApi(CloneableModuleApi, UpdateableModule, RemoveableModuleApi):
|
|
|
457
490
|
# import_settings={}
|
|
458
491
|
# )
|
|
459
492
|
"""
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
ApiField.SETTINGS,
|
|
468
|
-
ApiField.CREATED_BY_ID,
|
|
469
|
-
ApiField.LOCAL_ENTITIES_COUNT,
|
|
470
|
-
ApiField.REMOTE_ENTITIES_COUNT,
|
|
493
|
+
try:
|
|
494
|
+
fields = self.info_sequence_for_listing()
|
|
495
|
+
info = super().get_info_by_name(parent_id, name, fields)
|
|
496
|
+
except Exception as e:
|
|
497
|
+
logger.trace(
|
|
498
|
+
f"Failed to get info by name with all available fields for 'projects.list' endpoint: {e} "
|
|
499
|
+
"Falling back to minimal fields (id) and get_info_by_id()."
|
|
471
500
|
)
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
501
|
+
fields = [ApiField.ID]
|
|
502
|
+
info = super().get_info_by_name(parent_id, name, fields)
|
|
503
|
+
if info is None:
|
|
504
|
+
if raise_error:
|
|
505
|
+
raise ProjectNotFound(
|
|
506
|
+
f"Project with name {name!r} not found in workspace {parent_id!r}."
|
|
507
|
+
)
|
|
508
|
+
else:
|
|
509
|
+
return None
|
|
510
|
+
info = self.get_info_by_id(info.id)
|
|
475
511
|
self._check_project_info(
|
|
476
512
|
info, name=name, expected_type=expected_type, raise_error=raise_error
|
|
477
513
|
)
|
|
@@ -2213,7 +2249,21 @@ class ProjectApi(CloneableModuleApi, UpdateableModule, RemoveableModuleApi):
|
|
|
2213
2249
|
{ApiField.ID: id, ApiField.EMBEDDINGS_ENABLED: False, ApiField.SILENT: silent},
|
|
2214
2250
|
)
|
|
2215
2251
|
|
|
2216
|
-
def
|
|
2252
|
+
def is_embeddings_enabled(self, id: int) -> bool:
|
|
2253
|
+
"""
|
|
2254
|
+
Check if embeddings are enabled for the project.
|
|
2255
|
+
|
|
2256
|
+
:param id: Project ID
|
|
2257
|
+
:type id: int
|
|
2258
|
+
:return: True if embeddings are enabled, False otherwise.
|
|
2259
|
+
:rtype: bool
|
|
2260
|
+
"""
|
|
2261
|
+
info = self.get_info_by_id(id, extra_fields=[ApiField.EMBEDDINGS_ENABLED])
|
|
2262
|
+
return info.embeddings_enabled
|
|
2263
|
+
|
|
2264
|
+
def set_embeddings_in_progress(
|
|
2265
|
+
self, id: int, in_progress: bool, error_message: Optional[str] = None
|
|
2266
|
+
) -> None:
|
|
2217
2267
|
"""
|
|
2218
2268
|
Set embeddings in progress status for the project.
|
|
2219
2269
|
This method is used to indicate whether embeddings are currently being created for the project.
|
|
@@ -2222,13 +2272,34 @@ class ProjectApi(CloneableModuleApi, UpdateableModule, RemoveableModuleApi):
|
|
|
2222
2272
|
:type id: int
|
|
2223
2273
|
:param in_progress: Status to set. If True, embeddings are in progress right now.
|
|
2224
2274
|
:type in_progress: bool
|
|
2275
|
+
:param error_message: Optional error message to provide additional context.
|
|
2276
|
+
:type error_message: Optional[str]
|
|
2225
2277
|
:return: None
|
|
2226
2278
|
:rtype: :class:`NoneType`
|
|
2227
2279
|
"""
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
)
|
|
2280
|
+
data = {ApiField.ID: id, ApiField.EMBEDDINGS_IN_PROGRESS: in_progress}
|
|
2281
|
+
if error_message is not None:
|
|
2282
|
+
data[ApiField.ERROR_MESSAGE] = error_message
|
|
2283
|
+
self._api.post("projects.embeddings-in-progress.update", data)
|
|
2284
|
+
|
|
2285
|
+
def get_embeddings_in_progress(self, id: int) -> bool:
|
|
2286
|
+
"""
|
|
2287
|
+
Get the embeddings in progress status for the project.
|
|
2288
|
+
This method checks whether embeddings are currently being created for the project.
|
|
2289
|
+
|
|
2290
|
+
:param id: Project ID
|
|
2291
|
+
:type id: int
|
|
2292
|
+
:return: True if embeddings are in progress, False otherwise.
|
|
2293
|
+
:rtype: bool
|
|
2294
|
+
"""
|
|
2295
|
+
info = self.get_info_by_id(id, extra_fields=[ApiField.EMBEDDINGS_IN_PROGRESS])
|
|
2296
|
+
if info is None:
|
|
2297
|
+
raise RuntimeError(f"Project with ID {id} not found.")
|
|
2298
|
+
if not hasattr(info, "embeddings_in_progress"):
|
|
2299
|
+
raise RuntimeError(
|
|
2300
|
+
f"Project with ID {id} does not have 'embeddings_in_progress' field in its info."
|
|
2301
|
+
)
|
|
2302
|
+
return info.embeddings_in_progress
|
|
2232
2303
|
|
|
2233
2304
|
def set_embeddings_updated_at(
|
|
2234
2305
|
self, id: int, timestamp: Optional[str] = None, silent: bool = True
|
|
@@ -2267,14 +2338,46 @@ class ProjectApi(CloneableModuleApi, UpdateableModule, RemoveableModuleApi):
|
|
|
2267
2338
|
{ApiField.ID: id, ApiField.EMBEDDINGS_UPDATED_AT: timestamp, ApiField.SILENT: silent},
|
|
2268
2339
|
)
|
|
2269
2340
|
|
|
2341
|
+
def get_embeddings_updated_at(self, id: int) -> Optional[str]:
|
|
2342
|
+
"""
|
|
2343
|
+
Get the timestamp when embeddings were last updated for the project.
|
|
2344
|
+
|
|
2345
|
+
:param id: Project ID
|
|
2346
|
+
:type id: int
|
|
2347
|
+
:return: ISO format timestamp (YYYY-MM-DDTHH:MM:SS.fffZ) or None if not set.
|
|
2348
|
+
:rtype: Optional[str]
|
|
2349
|
+
:Usage example:
|
|
2350
|
+
|
|
2351
|
+
.. code-block:: python
|
|
2352
|
+
|
|
2353
|
+
api = sly.Api.from_env()
|
|
2354
|
+
project_id = 123
|
|
2355
|
+
|
|
2356
|
+
# Get embeddings updated timestamp
|
|
2357
|
+
updated_at = api.project.get_embeddings_updated_at(project_id)
|
|
2358
|
+
print(updated_at) # Output: "2025-06-01T10:30:45.123Z" or None
|
|
2359
|
+
"""
|
|
2360
|
+
info = self.get_info_by_id(id, extra_fields=[ApiField.EMBEDDINGS_UPDATED_AT])
|
|
2361
|
+
if info is None:
|
|
2362
|
+
raise RuntimeError(f"Project with ID {id} not found.")
|
|
2363
|
+
if not hasattr(info, "embeddings_updated_at"):
|
|
2364
|
+
raise RuntimeError(
|
|
2365
|
+
f"Project with ID {id} does not have 'embeddings_updated_at' field in its info."
|
|
2366
|
+
)
|
|
2367
|
+
return info.embeddings_updated_at
|
|
2368
|
+
|
|
2270
2369
|
def perform_ai_search(
|
|
2271
2370
|
self,
|
|
2272
2371
|
project_id: int,
|
|
2273
2372
|
dataset_id: Optional[int] = None,
|
|
2274
|
-
image_id: Optional[int] = None,
|
|
2373
|
+
image_id: Optional[Union[int, List[int]]] = None,
|
|
2275
2374
|
prompt: Optional[str] = None,
|
|
2276
2375
|
method: Optional[Literal["centroids", "random"]] = None,
|
|
2277
2376
|
limit: int = 100,
|
|
2377
|
+
clustering_method: Optional[Literal["kmeans", "dbscan"]] = None,
|
|
2378
|
+
num_clusters: Optional[int] = None,
|
|
2379
|
+
image_id_scope: Optional[List[int]] = None,
|
|
2380
|
+
threshold: Optional[float] = None,
|
|
2278
2381
|
) -> Optional[int]:
|
|
2279
2382
|
"""
|
|
2280
2383
|
Send AI search request to initiate search process.
|
|
@@ -2285,14 +2388,22 @@ class ProjectApi(CloneableModuleApi, UpdateableModule, RemoveableModuleApi):
|
|
|
2285
2388
|
:type project_id: int
|
|
2286
2389
|
:param dataset_id: ID of the Dataset. If not None - search will be limited to this dataset.
|
|
2287
2390
|
:type dataset_id: Optional[int]
|
|
2288
|
-
:param image_id: ID of the Image. Searches for images similar to the specified image.
|
|
2289
|
-
:type image_id: Optional[int]
|
|
2391
|
+
:param image_id: ID(s) of the Image(s). Searches for images similar to the specified image(s).
|
|
2392
|
+
:type image_id: Optional[Union[int, List[int]]]
|
|
2290
2393
|
:param prompt: Text prompt for search request. Searches for similar images based on a text description.
|
|
2291
2394
|
:type prompt: Optional[str]
|
|
2292
2395
|
:param method: Activates diverse search using one of the following methods: "centroids", "random".
|
|
2293
2396
|
:type method: Optional[Literal["centroids", "random"]]
|
|
2294
2397
|
:param limit: Limit for search request
|
|
2295
2398
|
:type limit: int
|
|
2399
|
+
:param clustering_method: Method for clustering results. Can be "kmeans" or "dbscan". If None, no clustering is applied.
|
|
2400
|
+
:type clustering_method: Optional[Literal["kmeans", "dbscan"]]
|
|
2401
|
+
:param num_clusters: Number of clusters to create if clustering_method is specified. Required for "kmeans" method.
|
|
2402
|
+
:type num_clusters: Optional[int]
|
|
2403
|
+
:param image_id_scope: List of image IDs to limit the search scope. If None, the search will be performed across all images in the project if other filters are not set.
|
|
2404
|
+
:type image_id_scope: Optional[List[int]]
|
|
2405
|
+
:param threshold: Threshold for similarity. If provided, only images with similarity above this threshold will be returned.
|
|
2406
|
+
:type threshold: Optional[float]
|
|
2296
2407
|
:return: Entitites Collection ID of the search results, or None if no collection was created.
|
|
2297
2408
|
:rtype: Optional[int]
|
|
2298
2409
|
:raises ValueError: only one of `prompt`, `image_id` or `method`must be provided, and `method` must be one of the allowed values.
|
|
@@ -2349,15 +2460,45 @@ class ProjectApi(CloneableModuleApi, UpdateableModule, RemoveableModuleApi):
|
|
|
2349
2460
|
if dataset_id is not None:
|
|
2350
2461
|
request_body[ApiField.DATASET_ID] = dataset_id
|
|
2351
2462
|
|
|
2352
|
-
if image_id is not None:
|
|
2353
|
-
request_body[ApiField.IMAGE_ID] = image_id
|
|
2354
|
-
|
|
2355
2463
|
if prompt is not None:
|
|
2356
2464
|
request_body[ApiField.PROMPT] = prompt
|
|
2357
2465
|
|
|
2466
|
+
if image_id is not None:
|
|
2467
|
+
if prompt is not None or method is not None:
|
|
2468
|
+
raise ValueError("If 'image_id' is provided, 'prompt' and 'method' must be None.")
|
|
2469
|
+
if isinstance(image_id, int):
|
|
2470
|
+
image_id = [image_id]
|
|
2471
|
+
if not isinstance(image_id, list):
|
|
2472
|
+
raise ValueError("image_id must be a list of image IDs.")
|
|
2473
|
+
request_body[ApiField.IMAGE_IDS] = image_id
|
|
2474
|
+
|
|
2358
2475
|
if method is not None:
|
|
2476
|
+
if image_id is not None or prompt is not None:
|
|
2477
|
+
raise ValueError("If 'method' is provided, 'image_id' and 'prompt' must be None.")
|
|
2359
2478
|
request_body[ApiField.METHOD] = method
|
|
2360
2479
|
|
|
2480
|
+
if clustering_method is not None:
|
|
2481
|
+
if clustering_method not in ["kmeans", "dbscan"]:
|
|
2482
|
+
raise ValueError("Clustering method must be either 'kmeans' or 'dbscan'.")
|
|
2483
|
+
request_body[ApiField.CLUSTERING_METHOD] = clustering_method
|
|
2484
|
+
|
|
2485
|
+
if num_clusters is not None:
|
|
2486
|
+
if clustering_method != "kmeans":
|
|
2487
|
+
raise ValueError(
|
|
2488
|
+
"Number of clusters is only applicable for 'kmeans' clustering method."
|
|
2489
|
+
)
|
|
2490
|
+
request_body[ApiField.NUMBER_OF_CLUSTERS] = num_clusters
|
|
2491
|
+
|
|
2492
|
+
if image_id_scope is not None:
|
|
2493
|
+
if not isinstance(image_id_scope, list):
|
|
2494
|
+
raise ValueError("image_id_scope must be a list of image IDs.")
|
|
2495
|
+
request_body[ApiField.RESTRICTED_IMAGE_IDS] = image_id_scope
|
|
2496
|
+
|
|
2497
|
+
if threshold is not None:
|
|
2498
|
+
if not isinstance(threshold, (int, float)):
|
|
2499
|
+
raise ValueError("Threshold must be a number.")
|
|
2500
|
+
request_body[ApiField.THRESHOLD] = threshold
|
|
2501
|
+
|
|
2361
2502
|
response = self._api.post("embeddings.send-ai-search", request_body)
|
|
2362
2503
|
return response.json().get(ApiField.COLLECTION_ID, None)
|
|
2363
2504
|
|
|
@@ -2366,6 +2507,8 @@ class ProjectApi(CloneableModuleApi, UpdateableModule, RemoveableModuleApi):
|
|
|
2366
2507
|
Calculate embeddings for the project.
|
|
2367
2508
|
This method is used to calculate embeddings for all images in the project.
|
|
2368
2509
|
|
|
2510
|
+
To check status of embeddings calculation, use :meth:`get_embeddings_in_progress`
|
|
2511
|
+
|
|
2369
2512
|
:param id: Project ID
|
|
2370
2513
|
:type id: int
|
|
2371
2514
|
:return: None
|
supervisely/io/env.py
CHANGED
|
@@ -671,3 +671,18 @@ def supervisely_skip_https_user_helper_check() -> bool:
|
|
|
671
671
|
default=False,
|
|
672
672
|
raise_not_found=False,
|
|
673
673
|
)
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
def configure_minimum_instance_version() -> None:
|
|
677
|
+
"""
|
|
678
|
+
Configure MINIMUM_INSTANCE_VERSION_FOR_SDK environment variable
|
|
679
|
+
from the latest entry in versions.json file.
|
|
680
|
+
|
|
681
|
+
This function should be called during SDK initialization to automatically
|
|
682
|
+
set the minimum required instance version based on the versions.json file.
|
|
683
|
+
"""
|
|
684
|
+
from supervisely._utils import get_latest_instance_version_from_json
|
|
685
|
+
|
|
686
|
+
latest_version = get_latest_instance_version_from_json()
|
|
687
|
+
if latest_version:
|
|
688
|
+
os.environ["MINIMUM_INSTANCE_VERSION_FOR_SDK"] = latest_version
|
|
@@ -57,6 +57,9 @@ class F1ScoreAtDifferentIOU(DetectionVisMetric):
|
|
|
57
57
|
|
|
58
58
|
# add annotations for maximum F1-Score for each IoU threshold
|
|
59
59
|
for i, iou in enumerate(iou_names):
|
|
60
|
+
# Skip if all F1 scores are NaN for this IoU threshold
|
|
61
|
+
if np.isnan(f1s[i]).all():
|
|
62
|
+
continue
|
|
60
63
|
argmax_f1 = np.nanargmax(f1s[i])
|
|
61
64
|
max_f1 = f1s[i][argmax_f1]
|
|
62
65
|
score = self.eval_result.mp.m_full.score_profile["scores"][argmax_f1]
|
|
@@ -6,6 +6,7 @@ from typing import Dict, Optional, Tuple, Union
|
|
|
6
6
|
from supervisely._utils import take_with_default
|
|
7
7
|
from supervisely.annotation.tag_meta import TagMeta
|
|
8
8
|
from supervisely.annotation.tag_meta_collection import TagMetaCollection
|
|
9
|
+
from supervisely.api.module_api import ApiField
|
|
9
10
|
from supervisely.video_annotation.key_id_map import KeyIdMap
|
|
10
11
|
from supervisely.video_annotation.video_tag import VideoTag
|
|
11
12
|
|
|
@@ -30,6 +31,10 @@ class PointcloudEpisodeTag(VideoTag):
|
|
|
30
31
|
:type updated_at: str, optional
|
|
31
32
|
:param created_at: Date and Time when PointcloudEpisodeTag was created. Date Format is the same as in "updated_at" parameter.
|
|
32
33
|
:type created_at: str, optional
|
|
34
|
+
:param is_finished: Pointcloud Episode Tag is finished or not (applicable for range tags).
|
|
35
|
+
:type is_finished: bool, optional
|
|
36
|
+
:param non_final_value: Pointcloud Episode Tag value is final or not. Can be useful to create tag without value.
|
|
37
|
+
:type non_final_value: bool, optional
|
|
33
38
|
:Usage example:
|
|
34
39
|
|
|
35
40
|
.. code-block:: python
|
|
@@ -37,7 +42,7 @@ class PointcloudEpisodeTag(VideoTag):
|
|
|
37
42
|
import supervisely as sly
|
|
38
43
|
|
|
39
44
|
meta_car = sly.TagMeta('car', sly.TagValueType.NONE)
|
|
40
|
-
# Now we can create a
|
|
45
|
+
# Now we can create a PointcloudEpisodeTag using our TagMeta
|
|
41
46
|
tag_car = sly.PointcloudEpisodeTag(meta_car)
|
|
42
47
|
# When you are creating a new Tag
|
|
43
48
|
# Tag.value is automatically cross-checked against your TagMeta value type to make sure the value is valid.
|
|
@@ -60,7 +65,7 @@ class PointcloudEpisodeTag(VideoTag):
|
|
|
60
65
|
# Output: ValueError: Tag car color can not have value yellow
|
|
61
66
|
"""
|
|
62
67
|
|
|
63
|
-
_SUPPORT_UNFINISHED_TAGS =
|
|
68
|
+
_SUPPORT_UNFINISHED_TAGS = True
|
|
64
69
|
|
|
65
70
|
def __init__(
|
|
66
71
|
self,
|
|
@@ -72,6 +77,8 @@ class PointcloudEpisodeTag(VideoTag):
|
|
|
72
77
|
labeler_login=None,
|
|
73
78
|
updated_at=None,
|
|
74
79
|
created_at=None,
|
|
80
|
+
is_finished=None,
|
|
81
|
+
non_final_value=None,
|
|
75
82
|
):
|
|
76
83
|
super().__init__(
|
|
77
84
|
meta,
|
|
@@ -82,6 +89,8 @@ class PointcloudEpisodeTag(VideoTag):
|
|
|
82
89
|
labeler_login,
|
|
83
90
|
updated_at,
|
|
84
91
|
created_at,
|
|
92
|
+
is_finished=is_finished,
|
|
93
|
+
non_final_value=non_final_value,
|
|
85
94
|
)
|
|
86
95
|
|
|
87
96
|
@classmethod
|
|
@@ -121,7 +130,8 @@ class PointcloudEpisodeTag(VideoTag):
|
|
|
121
130
|
|
|
122
131
|
tag_car_color = sly.PointcloudEpisodeTag.from_json(tag_car_color_json, meta_car_collection)
|
|
123
132
|
"""
|
|
124
|
-
|
|
133
|
+
is_finished = data.get(ApiField.IS_FINISHED, True)
|
|
134
|
+
non_final_value = data.get(ApiField.NON_FINAL_VALUE, False)
|
|
125
135
|
temp = super(PointcloudEpisodeTag, cls).from_json(data, tag_meta_collection, key_id_map)
|
|
126
136
|
|
|
127
137
|
return cls(
|
|
@@ -133,6 +143,8 @@ class PointcloudEpisodeTag(VideoTag):
|
|
|
133
143
|
labeler_login=temp.labeler_login,
|
|
134
144
|
updated_at=temp.updated_at,
|
|
135
145
|
created_at=temp.created_at,
|
|
146
|
+
is_finished=is_finished,
|
|
147
|
+
non_final_value=non_final_value,
|
|
136
148
|
)
|
|
137
149
|
|
|
138
150
|
def __eq__(self, other: PointcloudEpisodeTag) -> bool:
|
|
@@ -148,6 +160,8 @@ class PointcloudEpisodeTag(VideoTag):
|
|
|
148
160
|
labeler_login: Optional[str] = None,
|
|
149
161
|
updated_at: Optional[str] = None,
|
|
150
162
|
created_at: Optional[str] = None,
|
|
163
|
+
is_finished: Optional[bool] = None,
|
|
164
|
+
non_final_value: Optional[bool] = None,
|
|
151
165
|
) -> PointcloudEpisodeTag:
|
|
152
166
|
"""
|
|
153
167
|
Makes a copy of PointcloudEpisodeTag with new fields, if fields are given, otherwise it will use fields of the original PointcloudEpisodeTag.
|
|
@@ -168,6 +182,10 @@ class PointcloudEpisodeTag(VideoTag):
|
|
|
168
182
|
:type updated_at: str, optional
|
|
169
183
|
:param created_at: Date and Time when PointcloudEpisodeTag was created. Date Format is the same as in "updated_at" parameter.
|
|
170
184
|
:type created_at: str, optional
|
|
185
|
+
:param is_finished: Pointcloud Episode Tag is finished or not (applicable for range tags).
|
|
186
|
+
:type is_finished: bool, optional
|
|
187
|
+
:param non_final_value: Pointcloud Episode Tag value is final or not. Can be useful to create tag without value.
|
|
188
|
+
:type non_final_value: bool, optional
|
|
171
189
|
:Usage example:
|
|
172
190
|
|
|
173
191
|
.. code-block:: python
|
|
@@ -201,4 +219,6 @@ class PointcloudEpisodeTag(VideoTag):
|
|
|
201
219
|
labeler_login=take_with_default(labeler_login, self.labeler_login),
|
|
202
220
|
updated_at=take_with_default(updated_at, self.updated_at),
|
|
203
221
|
created_at=take_with_default(created_at, self.created_at),
|
|
222
|
+
is_finished=take_with_default(is_finished, self.is_finished),
|
|
223
|
+
non_final_value=take_with_default(non_final_value, self.non_final_value),
|
|
204
224
|
)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"6.9.11": "6.72.70",
|
|
3
|
+
"6.9.13": "6.73.76",
|
|
4
|
+
"6.9.18": "6.73.81",
|
|
5
|
+
"6.9.22": "6.73.90",
|
|
6
|
+
"6.9.31": "6.73.123",
|
|
7
|
+
"6.10.0": "6.73.126",
|
|
8
|
+
"6.11.8": "6.73.159",
|
|
9
|
+
"6.11.10": "6.73.166",
|
|
10
|
+
"6.11.16": "6.73.184",
|
|
11
|
+
"6.11.19": "6.73.199",
|
|
12
|
+
"6.12.2": "6.73.222",
|
|
13
|
+
"6.12.5": "6.73.226",
|
|
14
|
+
"6.12.12": "6.73.241",
|
|
15
|
+
"6.12.17": "6.73.263",
|
|
16
|
+
"6.12.23": "6.73.281",
|
|
17
|
+
"6.12.28": "6.73.292",
|
|
18
|
+
"6.12.30": "6.73.312",
|
|
19
|
+
"6.12.34": "6.73.324",
|
|
20
|
+
"6.12.44": "6.73.344",
|
|
21
|
+
"6.12.46": "6.73.375",
|
|
22
|
+
"6.13.1": "6.73.379",
|
|
23
|
+
"6.13.8": "6.73.394",
|
|
24
|
+
"6.14.0": "6.73.400",
|
|
25
|
+
"6.14.4": "6.73.410"
|
|
26
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
supervisely/README.md,sha256=XM-DiMC6To3I9RjQZ0c61905EFRR_jnCUx2q3uNR-X8,3331
|
|
2
|
-
supervisely/__init__.py,sha256=
|
|
3
|
-
supervisely/_utils.py,sha256=
|
|
2
|
+
supervisely/__init__.py,sha256=ojclMFGrJk0YVXxFU5wcUOQINaeFQ_eiZ1-GzModiYs,11035
|
|
3
|
+
supervisely/_utils.py,sha256=59vOeNOnmVHODnlAvULT8jdwvHHVTs2FOtAFw8mvaqE,20643
|
|
4
4
|
supervisely/function_wrapper.py,sha256=R5YajTQ0GnRp2vtjwfC9hINkzQc0JiyGsu8TER373xY,1912
|
|
5
5
|
supervisely/sly_logger.py,sha256=z92Vu5hmC0GgTIJO1n6kPDayRW9__8ix8hL6poDZj-Y,6274
|
|
6
6
|
supervisely/tiny_timer.py,sha256=hkpe_7FE6bsKL79blSs7WBaktuPavEVu67IpEPrfmjE,183
|
|
7
|
+
supervisely/versions.json,sha256=xfHoZZTqcNGMK-BumXLEQnTmSyvCjdATci45G6a_MJk,562
|
|
7
8
|
supervisely/annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
9
|
supervisely/annotation/annotation.py,sha256=th4gsIU-LNGcMRohHrtupmjxDwdzx1g4_0xIAa6NyJU,114717
|
|
9
10
|
supervisely/annotation/annotation_transforms.py,sha256=TlVy_gUbM-XH6GbLpZPrAi6pMIGTr7Ow02iSKOSTa-I,9582
|
|
@@ -35,10 +36,10 @@ supervisely/api/import_storage_api.py,sha256=BDCgmR0Hv6OoiRHLCVPKt3iDxSVlQp1WrnK
|
|
|
35
36
|
supervisely/api/issues_api.py,sha256=BqDJXmNoTzwc3xe6_-mA7FDFC5QQ-ahGbXk_HmpkSeQ,17925
|
|
36
37
|
supervisely/api/labeling_job_api.py,sha256=G2_BV_WtA2lAhfw_nAQmWmv1P-pwimD0ba9GVKoGjiA,55537
|
|
37
38
|
supervisely/api/labeling_queue_api.py,sha256=ilNjAL1d9NSa9yabQn6E-W26YdtooT3ZGXIFZtGnAvY,30158
|
|
38
|
-
supervisely/api/module_api.py,sha256=
|
|
39
|
+
supervisely/api/module_api.py,sha256=vqojLHCC-uCNVnqB2FUMCJdXAElg5FON3BZTr8AkiiE,46340
|
|
39
40
|
supervisely/api/object_class_api.py,sha256=7-npNFMYjWNtSXYZg6syc6bX56_oCzDU2kFRPGQWCwA,10399
|
|
40
41
|
supervisely/api/plugin_api.py,sha256=SFm0IlTTOjuHBLUMgG4d4k6U3cWJocE-SVb-f08fwMQ,5286
|
|
41
|
-
supervisely/api/project_api.py,sha256=
|
|
42
|
+
supervisely/api/project_api.py,sha256=ZTmPEqWUQgYv5s5nEvnb2qobaiYxHFxibYZrtsJ-QAs,96362
|
|
42
43
|
supervisely/api/project_class_api.py,sha256=5cyjdGPPb2tpttu5WmYoOxUNiDxqiojschkhZumF0KM,1426
|
|
43
44
|
supervisely/api/remote_storage_api.py,sha256=1O4rTIwW8s9gxC00yvFuKbEMGNsa7YSRlZ8j494ARwY,17793
|
|
44
45
|
supervisely/api/report_api.py,sha256=Om7CGulUbQ4BuJ16eDtz7luLe0JQNqab-LoLpUXu7YE,7123
|
|
@@ -723,7 +724,7 @@ supervisely/imaging/font.py,sha256=0XcmWhlw7y2PAhrWgcsfInyRWj0WnlFpMSEXXilR8UA,2
|
|
|
723
724
|
supervisely/imaging/image.py,sha256=1KNc4qRbP9OlI4Yta07Kc2ohAgSBJ_9alF9Jag74w30,41873
|
|
724
725
|
supervisely/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
725
726
|
supervisely/io/docker_utils.py,sha256=hb_HXGM8IYB0PF-nD7NxMwaHgzaxIFxofsUzQ_RCUZI,7935
|
|
726
|
-
supervisely/io/env.py,sha256=
|
|
727
|
+
supervisely/io/env.py,sha256=fK-v4rW_tWiS6qjZtv91WM7uNtem27E_F1zDvaYfjN4,21766
|
|
727
728
|
supervisely/io/exception_handlers.py,sha256=22LPlLgyq59DnrhpaFrbGBYJE7uxO64VTZjsPJC0PLE,36757
|
|
728
729
|
supervisely/io/fs.py,sha256=pzNAK5fbT3G-7PKRY5oYcOPjgXeZ9x5Dyry7fzzZsr8,63604
|
|
729
730
|
supervisely/io/fs_cache.py,sha256=985gvBGzveLcDudgz10E4EWVjP9jxdU1Pa0GFfCBoCA,6520
|
|
@@ -815,7 +816,7 @@ supervisely/nn/benchmark/object_detection/vis_metrics/confidence_distribution.py
|
|
|
815
816
|
supervisely/nn/benchmark/object_detection/vis_metrics/confidence_score.py,sha256=pmxnF_UJk0WhqEdL7O_yIjIBtxPipLQZVJwCr6XB3zc,4751
|
|
816
817
|
supervisely/nn/benchmark/object_detection/vis_metrics/confusion_matrix.py,sha256=2PJUt0-njRpzN7XBGjkSt9kkh5tDPuv_Sne-2v8DWHc,3731
|
|
817
818
|
supervisely/nn/benchmark/object_detection/vis_metrics/explore_predictions.py,sha256=sMSFntieAdmL8siTKwppB4RxIhfZlsg1loUeOEhiKOg,5234
|
|
818
|
-
supervisely/nn/benchmark/object_detection/vis_metrics/f1_score_at_different_iou.py,sha256=
|
|
819
|
+
supervisely/nn/benchmark/object_detection/vis_metrics/f1_score_at_different_iou.py,sha256=UAYw_e2p60_vURs2gT584sfxy0eU2kar4beHIy-gRVg,3023
|
|
819
820
|
supervisely/nn/benchmark/object_detection/vis_metrics/frequently_confused.py,sha256=7rObk7WNsfwK7xBWl3aOxcn0uD48njEc04fQIPHc3_4,4678
|
|
820
821
|
supervisely/nn/benchmark/object_detection/vis_metrics/iou_distribution.py,sha256=lv4Bk8W4X8ZhvQKyMXI46d240PNlMFx1hdji_aoTS50,3601
|
|
821
822
|
supervisely/nn/benchmark/object_detection/vis_metrics/key_metrics.py,sha256=cbGwhG95rp5NmOy0qHvpSiAjWqtQQMWCfKs7FzbuKzc,4747
|
|
@@ -1026,7 +1027,7 @@ supervisely/pointcloud_annotation/pointcloud_episode_frame.py,sha256=XI1tZVs7vPN
|
|
|
1026
1027
|
supervisely/pointcloud_annotation/pointcloud_episode_frame_collection.py,sha256=_nyvoN8dQ9mMdNKlPqGAiXnoWJl7TlmcODZNI-Cx29M,16113
|
|
1027
1028
|
supervisely/pointcloud_annotation/pointcloud_episode_object.py,sha256=kkjLwxm6clLTFMmXXyM8n-k58Jyzmf3buJsEWyRK2Pg,2221
|
|
1028
1029
|
supervisely/pointcloud_annotation/pointcloud_episode_object_collection.py,sha256=emP5RuejfwuUhyA5MmgGPXMinowNBkFREHe7qEKUdfE,2707
|
|
1029
|
-
supervisely/pointcloud_annotation/pointcloud_episode_tag.py,sha256=
|
|
1030
|
+
supervisely/pointcloud_annotation/pointcloud_episode_tag.py,sha256=msFhL7MkWO_beE6PJ_PvSU2nPMLhUV6J6iBwOlqkJEY,10257
|
|
1030
1031
|
supervisely/pointcloud_annotation/pointcloud_episode_tag_collection.py,sha256=B4b9Ob26kAdpLWzBlHSeZNn7OPw8E7nHdHpnFrEbF-E,10358
|
|
1031
1032
|
supervisely/pointcloud_annotation/pointcloud_figure.py,sha256=URhVTChvF2WCLTYhT2UFzYE1pU5JWr_TGz-TAsfW3u0,11194
|
|
1032
1033
|
supervisely/pointcloud_annotation/pointcloud_object.py,sha256=7SB_t-kLxY_dwxbVbjfGqB-n_vLKhkhGJV9Epgq-fa4,5652
|
|
@@ -1114,9 +1115,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
1114
1115
|
supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
|
|
1115
1116
|
supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
|
|
1116
1117
|
supervisely_lib/__init__.py,sha256=7-3QnN8Zf0wj8NCr2oJmqoQWMKKPKTECvjH9pd2S5vY,159
|
|
1117
|
-
supervisely-6.73.
|
|
1118
|
-
supervisely-6.73.
|
|
1119
|
-
supervisely-6.73.
|
|
1120
|
-
supervisely-6.73.
|
|
1121
|
-
supervisely-6.73.
|
|
1122
|
-
supervisely-6.73.
|
|
1118
|
+
supervisely-6.73.410.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
1119
|
+
supervisely-6.73.410.dist-info/METADATA,sha256=CNGxrr7PWqWR6ZPxhf6ujqvjgoEq4TxkKeUbTRLoiEw,35254
|
|
1120
|
+
supervisely-6.73.410.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
1121
|
+
supervisely-6.73.410.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
|
|
1122
|
+
supervisely-6.73.410.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
|
|
1123
|
+
supervisely-6.73.410.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|