label-studio-sdk 2.0.6__py3-none-any.whl → 2.0.8__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.
- label_studio_sdk/__init__.py +32 -2
- label_studio_sdk/base_client.py +4 -0
- label_studio_sdk/converter/exports/yolo.py +89 -74
- label_studio_sdk/core/client_wrapper.py +1 -1
- label_studio_sdk/import_storage/azure_spi/client.py +30 -0
- label_studio_sdk/label_interface/control_tags.py +38 -0
- label_studio_sdk/label_interface/data_examples.json +10 -0
- label_studio_sdk/label_interface/interface.py +13 -0
- label_studio_sdk/label_interface/object_tags.py +9 -0
- label_studio_sdk/ml/client.py +124 -0
- label_studio_sdk/organizations/__init__.py +3 -2
- label_studio_sdk/organizations/client.py +540 -1
- label_studio_sdk/organizations/invites/__init__.py +2 -0
- label_studio_sdk/organizations/invites/client.py +368 -0
- label_studio_sdk/organizations/permissions/__init__.py +2 -0
- label_studio_sdk/organizations/permissions/client.py +1129 -0
- label_studio_sdk/organizations/types/__init__.py +5 -0
- label_studio_sdk/organizations/types/patched_default_role_request_custom_scripts_editable_by.py +7 -0
- label_studio_sdk/project_templates/__init__.py +2 -0
- label_studio_sdk/project_templates/client.py +909 -0
- label_studio_sdk/projects/__init__.py +30 -0
- label_studio_sdk/projects/client.py +355 -0
- label_studio_sdk/projects/stats/__init__.py +28 -0
- label_studio_sdk/projects/stats/client.py +1002 -43
- label_studio_sdk/projects/stats/types/__init__.py +30 -0
- label_studio_sdk/projects/stats/types/stats_agreement_annotator_response.py +26 -0
- label_studio_sdk/projects/stats/types/stats_data_filters_response.py +23 -0
- label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters.py +34 -0
- label_studio_sdk/projects/stats/types/stats_data_filters_response_user_filters_stats_item.py +22 -0
- label_studio_sdk/projects/stats/types/stats_finished_tasks_response.py +32 -0
- label_studio_sdk/projects/stats/types/stats_lead_time_response.py +23 -0
- label_studio_sdk/projects/stats/types/stats_lead_time_response_lead_time_stats_item.py +37 -0
- label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response.py +20 -0
- label_studio_sdk/projects/stats/types/stats_user_ground_truth_agreement_response_agreement.py +5 -0
- label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response.py +24 -0
- label_studio_sdk/projects/stats/types/stats_user_prediction_agreement_response_average_prediction_agreement_per_user.py +5 -0
- label_studio_sdk/projects/stats/types/stats_user_review_score_response.py +22 -0
- label_studio_sdk/projects/stats/types/stats_user_review_score_response_performance_score.py +5 -0
- label_studio_sdk/projects/stats/types/stats_user_review_score_response_review_score.py +5 -0
- label_studio_sdk/projects/types/__init__.py +2 -0
- label_studio_sdk/projects/types/projects_import_predictions_response.py +26 -0
- label_studio_sdk/prompts/versions/client.py +4 -16
- label_studio_sdk/types/__init__.py +26 -2
- label_studio_sdk/types/azure_service_principal_import_storage.py +5 -0
- label_studio_sdk/types/azure_service_principal_import_storage_request.py +5 -0
- label_studio_sdk/types/configurable_permission_option.py +25 -0
- label_studio_sdk/types/configurable_permission_option_default.py +7 -0
- label_studio_sdk/types/default_role.py +75 -0
- label_studio_sdk/types/default_role_custom_scripts_editable_by.py +7 -0
- label_studio_sdk/types/lse_organization.py +2 -2
- label_studio_sdk/types/lse_project.py +223 -0
- label_studio_sdk/types/lse_project_counts.py +46 -0
- label_studio_sdk/types/lse_project_sampling.py +7 -0
- label_studio_sdk/types/lse_project_skip_queue.py +7 -0
- label_studio_sdk/types/lse_task.py +1 -1
- label_studio_sdk/types/lse_task_serializer_for_reviewers.py +1 -1
- label_studio_sdk/types/organization_permission.py +31 -0
- label_studio_sdk/types/organization_permission_request.py +24 -0
- label_studio_sdk/types/paginated_lse_project_counts_list.py +23 -0
- label_studio_sdk/types/project_template.py +41 -0
- label_studio_sdk/types/project_template_request.py +38 -0
- label_studio_sdk/types/who_am_i_user.py +1 -0
- {label_studio_sdk-2.0.6.dist-info → label_studio_sdk-2.0.8.dist-info}/METADATA +1 -1
- {label_studio_sdk-2.0.6.dist-info → label_studio_sdk-2.0.8.dist-info}/RECORD +66 -31
- label_studio_sdk/types/default_role_enum.py +0 -5
- {label_studio_sdk-2.0.6.dist-info → label_studio_sdk-2.0.8.dist-info}/LICENSE +0 -0
- {label_studio_sdk-2.0.6.dist-info → label_studio_sdk-2.0.8.dist-info}/WHEEL +0 -0
label_studio_sdk/__init__.py
CHANGED
|
@@ -42,11 +42,14 @@ from .types import (
|
|
|
42
42
|
Comment,
|
|
43
43
|
CommentRequest,
|
|
44
44
|
CommentSerializerWithExpandedUser,
|
|
45
|
+
ConfigurablePermissionOption,
|
|
46
|
+
ConfigurablePermissionOptionDefault,
|
|
45
47
|
ConvertedFormat,
|
|
46
48
|
ConvertedFormatRequest,
|
|
47
49
|
CountLimit,
|
|
48
50
|
CustomScriptsEditableByEnum,
|
|
49
|
-
|
|
51
|
+
DefaultRole,
|
|
52
|
+
DefaultRoleCustomScriptsEditableBy,
|
|
50
53
|
EditionEnum,
|
|
51
54
|
Export,
|
|
52
55
|
FileUpload,
|
|
@@ -78,9 +81,13 @@ from .types import (
|
|
|
78
81
|
LseOrganization,
|
|
79
82
|
LseOrganizationCustomScriptsEditableBy,
|
|
80
83
|
LseOrganizationMemberList,
|
|
84
|
+
LseProject,
|
|
85
|
+
LseProjectCounts,
|
|
81
86
|
LseProjectCreate,
|
|
82
87
|
LseProjectCreateSampling,
|
|
83
88
|
LseProjectCreateSkipQueue,
|
|
89
|
+
LseProjectSampling,
|
|
90
|
+
LseProjectSkipQueue,
|
|
84
91
|
LseProjectUpdate,
|
|
85
92
|
LseProjectUpdateSampling,
|
|
86
93
|
LseProjectUpdateSkipQueue,
|
|
@@ -132,9 +139,12 @@ from .types import (
|
|
|
132
139
|
OrganizationInvite,
|
|
133
140
|
OrganizationMember,
|
|
134
141
|
OrganizationMembership,
|
|
142
|
+
OrganizationPermission,
|
|
143
|
+
OrganizationPermissionRequest,
|
|
135
144
|
PaginatedAllRolesProjectListList,
|
|
136
145
|
PaginatedAnnotationHistoryList,
|
|
137
146
|
PaginatedLseOrganizationMemberListList,
|
|
147
|
+
PaginatedLseProjectCountsList,
|
|
138
148
|
PaginatedLseUserList,
|
|
139
149
|
PaginatedPaginatedProjectMemberList,
|
|
140
150
|
PaginatedProjectMember,
|
|
@@ -154,6 +164,8 @@ from .types import (
|
|
|
154
164
|
ProjectSampling,
|
|
155
165
|
ProjectSkipQueue,
|
|
156
166
|
ProjectSubsetEnum,
|
|
167
|
+
ProjectTemplate,
|
|
168
|
+
ProjectTemplateRequest,
|
|
157
169
|
PromptsStatusEnum,
|
|
158
170
|
ProviderEnum,
|
|
159
171
|
ReasonEnum,
|
|
@@ -238,6 +250,7 @@ from . import (
|
|
|
238
250
|
model_providers,
|
|
239
251
|
organizations,
|
|
240
252
|
predictions,
|
|
253
|
+
project_templates,
|
|
241
254
|
projects,
|
|
242
255
|
prompts,
|
|
243
256
|
session_policy,
|
|
@@ -275,12 +288,14 @@ from .export_storage import ExportStorageListTypesResponseItem
|
|
|
275
288
|
from .import_storage import ImportStorageListTypesResponseItem
|
|
276
289
|
from .ml import MlCreateRequestAuthMethod, MlListModelVersionsResponse, MlUpdateRequestAuthMethod
|
|
277
290
|
from .model_providers import ModelProvidersListModelProviderChoicesResponse
|
|
291
|
+
from .organizations import PatchedDefaultRoleRequestCustomScriptsEditableBy
|
|
278
292
|
from .projects import (
|
|
279
293
|
LseProjectCreateRequestSampling,
|
|
280
294
|
LseProjectCreateRequestSkipQueue,
|
|
281
295
|
PatchedLseProjectUpdateRequestSampling,
|
|
282
296
|
PatchedLseProjectUpdateRequestSkipQueue,
|
|
283
297
|
ProjectsDuplicateResponse,
|
|
298
|
+
ProjectsImportPredictionsResponse,
|
|
284
299
|
ProjectsImportTasksResponse,
|
|
285
300
|
ProjectsListRequestFilter,
|
|
286
301
|
)
|
|
@@ -387,11 +402,14 @@ __all__ = [
|
|
|
387
402
|
"Comment",
|
|
388
403
|
"CommentRequest",
|
|
389
404
|
"CommentSerializerWithExpandedUser",
|
|
405
|
+
"ConfigurablePermissionOption",
|
|
406
|
+
"ConfigurablePermissionOptionDefault",
|
|
390
407
|
"ConvertedFormat",
|
|
391
408
|
"ConvertedFormatRequest",
|
|
392
409
|
"CountLimit",
|
|
393
410
|
"CustomScriptsEditableByEnum",
|
|
394
|
-
"
|
|
411
|
+
"DefaultRole",
|
|
412
|
+
"DefaultRoleCustomScriptsEditableBy",
|
|
395
413
|
"EditionEnum",
|
|
396
414
|
"Export",
|
|
397
415
|
"ExportStorageListTypesResponseItem",
|
|
@@ -429,11 +447,15 @@ __all__ = [
|
|
|
429
447
|
"LseOrganization",
|
|
430
448
|
"LseOrganizationCustomScriptsEditableBy",
|
|
431
449
|
"LseOrganizationMemberList",
|
|
450
|
+
"LseProject",
|
|
451
|
+
"LseProjectCounts",
|
|
432
452
|
"LseProjectCreate",
|
|
433
453
|
"LseProjectCreateRequestSampling",
|
|
434
454
|
"LseProjectCreateRequestSkipQueue",
|
|
435
455
|
"LseProjectCreateSampling",
|
|
436
456
|
"LseProjectCreateSkipQueue",
|
|
457
|
+
"LseProjectSampling",
|
|
458
|
+
"LseProjectSkipQueue",
|
|
437
459
|
"LseProjectUpdate",
|
|
438
460
|
"LseProjectUpdateSampling",
|
|
439
461
|
"LseProjectUpdateSkipQueue",
|
|
@@ -491,13 +513,17 @@ __all__ = [
|
|
|
491
513
|
"OrganizationInvite",
|
|
492
514
|
"OrganizationMember",
|
|
493
515
|
"OrganizationMembership",
|
|
516
|
+
"OrganizationPermission",
|
|
517
|
+
"OrganizationPermissionRequest",
|
|
494
518
|
"PaginatedAllRolesProjectListList",
|
|
495
519
|
"PaginatedAnnotationHistoryList",
|
|
496
520
|
"PaginatedLseOrganizationMemberListList",
|
|
521
|
+
"PaginatedLseProjectCountsList",
|
|
497
522
|
"PaginatedLseUserList",
|
|
498
523
|
"PaginatedPaginatedProjectMemberList",
|
|
499
524
|
"PaginatedProjectMember",
|
|
500
525
|
"PaginatedRoleBasedTaskList",
|
|
526
|
+
"PatchedDefaultRoleRequestCustomScriptsEditableBy",
|
|
501
527
|
"PatchedLseProjectUpdateRequestSampling",
|
|
502
528
|
"PatchedLseProjectUpdateRequestSkipQueue",
|
|
503
529
|
"Pause",
|
|
@@ -515,7 +541,10 @@ __all__ = [
|
|
|
515
541
|
"ProjectSampling",
|
|
516
542
|
"ProjectSkipQueue",
|
|
517
543
|
"ProjectSubsetEnum",
|
|
544
|
+
"ProjectTemplate",
|
|
545
|
+
"ProjectTemplateRequest",
|
|
518
546
|
"ProjectsDuplicateResponse",
|
|
547
|
+
"ProjectsImportPredictionsResponse",
|
|
519
548
|
"ProjectsImportTasksResponse",
|
|
520
549
|
"ProjectsListRequestFilter",
|
|
521
550
|
"PromptsCompatibleProjectsRequestProjectType",
|
|
@@ -630,6 +659,7 @@ __all__ = [
|
|
|
630
659
|
"model_providers",
|
|
631
660
|
"organizations",
|
|
632
661
|
"predictions",
|
|
662
|
+
"project_templates",
|
|
633
663
|
"projects",
|
|
634
664
|
"prompts",
|
|
635
665
|
"session_policy",
|
label_studio_sdk/base_client.py
CHANGED
|
@@ -23,6 +23,7 @@ from .ml.client import MlClient
|
|
|
23
23
|
from .model_providers.client import ModelProvidersClient
|
|
24
24
|
from .prompts.client import PromptsClient
|
|
25
25
|
from .predictions.client import PredictionsClient
|
|
26
|
+
from .project_templates.client import ProjectTemplatesClient
|
|
26
27
|
from .projects.client import ProjectsClient
|
|
27
28
|
from .tasks.client import TasksClient
|
|
28
29
|
from .session_policy.client import SessionPolicyClient
|
|
@@ -51,6 +52,7 @@ from .ml.client import AsyncMlClient
|
|
|
51
52
|
from .model_providers.client import AsyncModelProvidersClient
|
|
52
53
|
from .prompts.client import AsyncPromptsClient
|
|
53
54
|
from .predictions.client import AsyncPredictionsClient
|
|
55
|
+
from .project_templates.client import AsyncProjectTemplatesClient
|
|
54
56
|
from .projects.client import AsyncProjectsClient
|
|
55
57
|
from .tasks.client import AsyncTasksClient
|
|
56
58
|
from .session_policy.client import AsyncSessionPolicyClient
|
|
@@ -142,6 +144,7 @@ class LabelStudioBase:
|
|
|
142
144
|
self.model_providers = ModelProvidersClient(client_wrapper=self._client_wrapper)
|
|
143
145
|
self.prompts = PromptsClient(client_wrapper=self._client_wrapper)
|
|
144
146
|
self.predictions = PredictionsClient(client_wrapper=self._client_wrapper)
|
|
147
|
+
self.project_templates = ProjectTemplatesClient(client_wrapper=self._client_wrapper)
|
|
145
148
|
self.projects = ProjectsClient(client_wrapper=self._client_wrapper)
|
|
146
149
|
self.tasks = TasksClient(client_wrapper=self._client_wrapper)
|
|
147
150
|
self.session_policy = SessionPolicyClient(client_wrapper=self._client_wrapper)
|
|
@@ -233,6 +236,7 @@ class AsyncLabelStudioBase:
|
|
|
233
236
|
self.model_providers = AsyncModelProvidersClient(client_wrapper=self._client_wrapper)
|
|
234
237
|
self.prompts = AsyncPromptsClient(client_wrapper=self._client_wrapper)
|
|
235
238
|
self.predictions = AsyncPredictionsClient(client_wrapper=self._client_wrapper)
|
|
239
|
+
self.project_templates = AsyncProjectTemplatesClient(client_wrapper=self._client_wrapper)
|
|
236
240
|
self.projects = AsyncProjectsClient(client_wrapper=self._client_wrapper)
|
|
237
241
|
self.tasks = AsyncTasksClient(client_wrapper=self._client_wrapper)
|
|
238
242
|
self.session_policy = AsyncSessionPolicyClient(client_wrapper=self._client_wrapper)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import os
|
|
2
3
|
from label_studio_sdk.converter.utils import convert_annotation_to_yolo, convert_annotation_to_yolo_obb
|
|
3
4
|
from label_studio_sdk.converter.keypoints import build_kp_order
|
|
4
5
|
|
|
@@ -69,81 +70,95 @@ def process_and_save_yolo_annotations(labels, label_path, category_name_to_id, c
|
|
|
69
70
|
process_keypoints_for_yolo(labels, label_path, category_name_to_id, categories, is_obb, kp_order)
|
|
70
71
|
return categories, category_name_to_id
|
|
71
72
|
|
|
72
|
-
annotations
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
category_id = len(categories)
|
|
91
|
-
category_name_to_id[category_name] = category_id
|
|
92
|
-
categories.append({"id": category_id, "name": category_name})
|
|
93
|
-
category_id = category_name_to_id[category_name]
|
|
94
|
-
|
|
95
|
-
if (
|
|
96
|
-
"rectanglelabels" in label
|
|
97
|
-
or "rectangle" in label
|
|
98
|
-
or "labels" in label
|
|
99
|
-
):
|
|
100
|
-
# yolo obb
|
|
101
|
-
if is_obb:
|
|
102
|
-
obb_annotation = convert_annotation_to_yolo_obb(label)
|
|
103
|
-
if obb_annotation is None:
|
|
104
|
-
continue
|
|
105
|
-
|
|
106
|
-
top_left, top_right, bottom_right, bottom_left = (
|
|
107
|
-
obb_annotation
|
|
73
|
+
# Stream annotations directly to a temporary file to avoid
|
|
74
|
+
# accumulating them in memory and to preserve atomic writes.
|
|
75
|
+
tmp_path = f"{label_path}.tmp"
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
with open(tmp_path, "w") as f:
|
|
79
|
+
for label in labels:
|
|
80
|
+
category_name = None
|
|
81
|
+
category_names = [] # considering multi-label
|
|
82
|
+
for key in ["rectanglelabels", "polygonlabels", "labels"]:
|
|
83
|
+
if key in label and len(label[key]) > 0:
|
|
84
|
+
# change to save multi-label
|
|
85
|
+
for category_name in label[key]:
|
|
86
|
+
category_names.append(category_name)
|
|
87
|
+
|
|
88
|
+
if len(category_names) == 0:
|
|
89
|
+
logger.debug(
|
|
90
|
+
"Unknown label type or labels are empty: " + str(label)
|
|
108
91
|
)
|
|
109
|
-
x1, y1 = top_left
|
|
110
|
-
x2, y2 = top_right
|
|
111
|
-
x3, y3 = bottom_right
|
|
112
|
-
x4, y4 = bottom_left
|
|
113
|
-
annotations.append(
|
|
114
|
-
[category_id, x1, y1, x2, y2, x3, y3, x4, y4]
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
# simple yolo
|
|
118
|
-
else:
|
|
119
|
-
annotation = convert_annotation_to_yolo(label)
|
|
120
|
-
if annotation is None:
|
|
121
|
-
continue
|
|
122
|
-
|
|
123
|
-
(
|
|
124
|
-
x,
|
|
125
|
-
y,
|
|
126
|
-
w,
|
|
127
|
-
h,
|
|
128
|
-
) = annotation
|
|
129
|
-
annotations.append([category_id, x, y, w, h])
|
|
130
|
-
|
|
131
|
-
elif "polygonlabels" in label or "polygon" in label:
|
|
132
|
-
if not ('points' in label):
|
|
133
92
|
continue
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
93
|
+
|
|
94
|
+
for category_name in category_names:
|
|
95
|
+
if category_name not in category_name_to_id:
|
|
96
|
+
category_id = len(categories)
|
|
97
|
+
category_name_to_id[category_name] = category_id
|
|
98
|
+
categories.append({"id": category_id, "name": category_name})
|
|
99
|
+
category_id = category_name_to_id[category_name]
|
|
100
|
+
|
|
101
|
+
if (
|
|
102
|
+
"rectanglelabels" in label
|
|
103
|
+
or "rectangle" in label
|
|
104
|
+
or "labels" in label
|
|
105
|
+
):
|
|
106
|
+
# yolo obb
|
|
107
|
+
if is_obb:
|
|
108
|
+
obb_annotation = convert_annotation_to_yolo_obb(label)
|
|
109
|
+
if obb_annotation is None:
|
|
110
|
+
continue
|
|
111
|
+
|
|
112
|
+
top_left, top_right, bottom_right, bottom_left = (
|
|
113
|
+
obb_annotation
|
|
114
|
+
)
|
|
115
|
+
x1, y1 = top_left
|
|
116
|
+
x2, y2 = top_right
|
|
117
|
+
x3, y3 = bottom_right
|
|
118
|
+
x4, y4 = bottom_left
|
|
119
|
+
annotation_values = [category_id, x1, y1, x2, y2, x3, y3, x4, y4]
|
|
120
|
+
|
|
121
|
+
# simple yolo
|
|
122
|
+
else:
|
|
123
|
+
annotation = convert_annotation_to_yolo(label)
|
|
124
|
+
if annotation is None:
|
|
125
|
+
continue
|
|
126
|
+
|
|
127
|
+
(
|
|
128
|
+
x,
|
|
129
|
+
y,
|
|
130
|
+
w,
|
|
131
|
+
h,
|
|
132
|
+
) = annotation
|
|
133
|
+
annotation_values = [category_id, x, y, w, h]
|
|
134
|
+
|
|
135
|
+
elif "polygonlabels" in label or "polygon" in label:
|
|
136
|
+
if not ('points' in label):
|
|
137
|
+
continue
|
|
138
|
+
points_abs = [(x / 100, y / 100) for x, y in label["points"]]
|
|
139
|
+
annotation_values = (
|
|
140
|
+
[category_id]
|
|
141
|
+
+ [coord for point in points_abs for coord in point]
|
|
142
|
+
)
|
|
143
|
+
else:
|
|
144
|
+
raise ValueError(f"Unknown label type {label}")
|
|
145
|
+
|
|
146
|
+
# Write the annotation line immediately
|
|
147
|
+
for idx, val in enumerate(annotation_values):
|
|
148
|
+
if idx == len(annotation_values) - 1:
|
|
149
|
+
f.write(f"{val}\n")
|
|
150
|
+
else:
|
|
151
|
+
f.write(f"{val} ")
|
|
152
|
+
|
|
153
|
+
# Replace the target file atomically after successful write
|
|
154
|
+
os.replace(tmp_path, label_path)
|
|
155
|
+
|
|
156
|
+
finally:
|
|
157
|
+
# Clean up the temp file in case of exceptions before replace
|
|
158
|
+
try:
|
|
159
|
+
if os.path.exists(tmp_path):
|
|
160
|
+
os.remove(tmp_path)
|
|
161
|
+
except Exception:
|
|
162
|
+
pass
|
|
148
163
|
|
|
149
164
|
return categories, category_name_to_id
|
|
@@ -94,6 +94,7 @@ class AzureSpiClient:
|
|
|
94
94
|
prefix: typing.Optional[str] = OMIT,
|
|
95
95
|
presign: typing.Optional[bool] = OMIT,
|
|
96
96
|
presign_ttl: typing.Optional[int] = OMIT,
|
|
97
|
+
recursive_scan: typing.Optional[bool] = OMIT,
|
|
97
98
|
regex_filter: typing.Optional[str] = OMIT,
|
|
98
99
|
status: typing.Optional[StatusC5AEnum] = OMIT,
|
|
99
100
|
synchronizable: typing.Optional[bool] = OMIT,
|
|
@@ -146,6 +147,9 @@ class AzureSpiClient:
|
|
|
146
147
|
presign_ttl : typing.Optional[int]
|
|
147
148
|
Presigned URLs TTL (in minutes)
|
|
148
149
|
|
|
150
|
+
recursive_scan : typing.Optional[bool]
|
|
151
|
+
Perform recursive scan
|
|
152
|
+
|
|
149
153
|
regex_filter : typing.Optional[str]
|
|
150
154
|
Cloud storage regex for filtering objects
|
|
151
155
|
|
|
@@ -204,6 +208,7 @@ class AzureSpiClient:
|
|
|
204
208
|
"presign": presign,
|
|
205
209
|
"presign_ttl": presign_ttl,
|
|
206
210
|
"project": project,
|
|
211
|
+
"recursive_scan": recursive_scan,
|
|
207
212
|
"regex_filter": regex_filter,
|
|
208
213
|
"status": status,
|
|
209
214
|
"synchronizable": synchronizable,
|
|
@@ -246,6 +251,7 @@ class AzureSpiClient:
|
|
|
246
251
|
prefix: typing.Optional[str] = OMIT,
|
|
247
252
|
presign: typing.Optional[bool] = OMIT,
|
|
248
253
|
presign_ttl: typing.Optional[int] = OMIT,
|
|
254
|
+
recursive_scan: typing.Optional[bool] = OMIT,
|
|
249
255
|
regex_filter: typing.Optional[str] = OMIT,
|
|
250
256
|
status: typing.Optional[StatusC5AEnum] = OMIT,
|
|
251
257
|
synchronizable: typing.Optional[bool] = OMIT,
|
|
@@ -298,6 +304,9 @@ class AzureSpiClient:
|
|
|
298
304
|
presign_ttl : typing.Optional[int]
|
|
299
305
|
Presigned URLs TTL (in minutes)
|
|
300
306
|
|
|
307
|
+
recursive_scan : typing.Optional[bool]
|
|
308
|
+
Perform recursive scan
|
|
309
|
+
|
|
301
310
|
regex_filter : typing.Optional[str]
|
|
302
311
|
Cloud storage regex for filtering objects
|
|
303
312
|
|
|
@@ -355,6 +364,7 @@ class AzureSpiClient:
|
|
|
355
364
|
"presign": presign,
|
|
356
365
|
"presign_ttl": presign_ttl,
|
|
357
366
|
"project": project,
|
|
367
|
+
"recursive_scan": recursive_scan,
|
|
358
368
|
"regex_filter": regex_filter,
|
|
359
369
|
"status": status,
|
|
360
370
|
"synchronizable": synchronizable,
|
|
@@ -479,6 +489,7 @@ class AzureSpiClient:
|
|
|
479
489
|
presign: typing.Optional[bool] = OMIT,
|
|
480
490
|
presign_ttl: typing.Optional[int] = OMIT,
|
|
481
491
|
project: typing.Optional[int] = OMIT,
|
|
492
|
+
recursive_scan: typing.Optional[bool] = OMIT,
|
|
482
493
|
regex_filter: typing.Optional[str] = OMIT,
|
|
483
494
|
status: typing.Optional[StatusC5AEnum] = OMIT,
|
|
484
495
|
synchronizable: typing.Optional[bool] = OMIT,
|
|
@@ -533,6 +544,9 @@ class AzureSpiClient:
|
|
|
533
544
|
project : typing.Optional[int]
|
|
534
545
|
A unique integer value identifying this project.
|
|
535
546
|
|
|
547
|
+
recursive_scan : typing.Optional[bool]
|
|
548
|
+
Perform recursive scan
|
|
549
|
+
|
|
536
550
|
regex_filter : typing.Optional[str]
|
|
537
551
|
Cloud storage regex for filtering objects
|
|
538
552
|
|
|
@@ -591,6 +605,7 @@ class AzureSpiClient:
|
|
|
591
605
|
"presign": presign,
|
|
592
606
|
"presign_ttl": presign_ttl,
|
|
593
607
|
"project": project,
|
|
608
|
+
"recursive_scan": recursive_scan,
|
|
594
609
|
"regex_filter": regex_filter,
|
|
595
610
|
"status": status,
|
|
596
611
|
"synchronizable": synchronizable,
|
|
@@ -755,6 +770,7 @@ class AsyncAzureSpiClient:
|
|
|
755
770
|
prefix: typing.Optional[str] = OMIT,
|
|
756
771
|
presign: typing.Optional[bool] = OMIT,
|
|
757
772
|
presign_ttl: typing.Optional[int] = OMIT,
|
|
773
|
+
recursive_scan: typing.Optional[bool] = OMIT,
|
|
758
774
|
regex_filter: typing.Optional[str] = OMIT,
|
|
759
775
|
status: typing.Optional[StatusC5AEnum] = OMIT,
|
|
760
776
|
synchronizable: typing.Optional[bool] = OMIT,
|
|
@@ -807,6 +823,9 @@ class AsyncAzureSpiClient:
|
|
|
807
823
|
presign_ttl : typing.Optional[int]
|
|
808
824
|
Presigned URLs TTL (in minutes)
|
|
809
825
|
|
|
826
|
+
recursive_scan : typing.Optional[bool]
|
|
827
|
+
Perform recursive scan
|
|
828
|
+
|
|
810
829
|
regex_filter : typing.Optional[str]
|
|
811
830
|
Cloud storage regex for filtering objects
|
|
812
831
|
|
|
@@ -873,6 +892,7 @@ class AsyncAzureSpiClient:
|
|
|
873
892
|
"presign": presign,
|
|
874
893
|
"presign_ttl": presign_ttl,
|
|
875
894
|
"project": project,
|
|
895
|
+
"recursive_scan": recursive_scan,
|
|
876
896
|
"regex_filter": regex_filter,
|
|
877
897
|
"status": status,
|
|
878
898
|
"synchronizable": synchronizable,
|
|
@@ -915,6 +935,7 @@ class AsyncAzureSpiClient:
|
|
|
915
935
|
prefix: typing.Optional[str] = OMIT,
|
|
916
936
|
presign: typing.Optional[bool] = OMIT,
|
|
917
937
|
presign_ttl: typing.Optional[int] = OMIT,
|
|
938
|
+
recursive_scan: typing.Optional[bool] = OMIT,
|
|
918
939
|
regex_filter: typing.Optional[str] = OMIT,
|
|
919
940
|
status: typing.Optional[StatusC5AEnum] = OMIT,
|
|
920
941
|
synchronizable: typing.Optional[bool] = OMIT,
|
|
@@ -967,6 +988,9 @@ class AsyncAzureSpiClient:
|
|
|
967
988
|
presign_ttl : typing.Optional[int]
|
|
968
989
|
Presigned URLs TTL (in minutes)
|
|
969
990
|
|
|
991
|
+
recursive_scan : typing.Optional[bool]
|
|
992
|
+
Perform recursive scan
|
|
993
|
+
|
|
970
994
|
regex_filter : typing.Optional[str]
|
|
971
995
|
Cloud storage regex for filtering objects
|
|
972
996
|
|
|
@@ -1032,6 +1056,7 @@ class AsyncAzureSpiClient:
|
|
|
1032
1056
|
"presign": presign,
|
|
1033
1057
|
"presign_ttl": presign_ttl,
|
|
1034
1058
|
"project": project,
|
|
1059
|
+
"recursive_scan": recursive_scan,
|
|
1035
1060
|
"regex_filter": regex_filter,
|
|
1036
1061
|
"status": status,
|
|
1037
1062
|
"synchronizable": synchronizable,
|
|
@@ -1172,6 +1197,7 @@ class AsyncAzureSpiClient:
|
|
|
1172
1197
|
presign: typing.Optional[bool] = OMIT,
|
|
1173
1198
|
presign_ttl: typing.Optional[int] = OMIT,
|
|
1174
1199
|
project: typing.Optional[int] = OMIT,
|
|
1200
|
+
recursive_scan: typing.Optional[bool] = OMIT,
|
|
1175
1201
|
regex_filter: typing.Optional[str] = OMIT,
|
|
1176
1202
|
status: typing.Optional[StatusC5AEnum] = OMIT,
|
|
1177
1203
|
synchronizable: typing.Optional[bool] = OMIT,
|
|
@@ -1226,6 +1252,9 @@ class AsyncAzureSpiClient:
|
|
|
1226
1252
|
project : typing.Optional[int]
|
|
1227
1253
|
A unique integer value identifying this project.
|
|
1228
1254
|
|
|
1255
|
+
recursive_scan : typing.Optional[bool]
|
|
1256
|
+
Perform recursive scan
|
|
1257
|
+
|
|
1229
1258
|
regex_filter : typing.Optional[str]
|
|
1230
1259
|
Cloud storage regex for filtering objects
|
|
1231
1260
|
|
|
@@ -1292,6 +1321,7 @@ class AsyncAzureSpiClient:
|
|
|
1292
1321
|
"presign": presign,
|
|
1293
1322
|
"presign_ttl": presign_ttl,
|
|
1294
1323
|
"project": project,
|
|
1324
|
+
"recursive_scan": recursive_scan,
|
|
1295
1325
|
"regex_filter": regex_filter,
|
|
1296
1326
|
"status": status,
|
|
1297
1327
|
"synchronizable": synchronizable,
|
|
@@ -39,6 +39,7 @@ _TAG_TO_CLASS = {
|
|
|
39
39
|
"taxonomy": "TaxonomyTag",
|
|
40
40
|
"textarea": "TextAreaTag",
|
|
41
41
|
"timeserieslabels": "TimeSeriesLabelsTag",
|
|
42
|
+
"chatmessage": "ChatMessageTag",
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
|
|
@@ -950,6 +951,43 @@ class RatingTag(ControlTag):
|
|
|
950
951
|
}
|
|
951
952
|
|
|
952
953
|
|
|
954
|
+
class ChatMessageContent(BaseModel):
|
|
955
|
+
role: str
|
|
956
|
+
content: str
|
|
957
|
+
createdAt: Optional[int] = None
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
class ChatMessageValue(BaseModel):
|
|
961
|
+
chatmessage: ChatMessageContent
|
|
962
|
+
|
|
963
|
+
|
|
964
|
+
class ChatMessageTag(ControlTag):
|
|
965
|
+
"""Control tag for chat messages targeting a `<Chat>` object.
|
|
966
|
+
|
|
967
|
+
This tag is a hybrid where `from_name == to_name` and `type == 'chatmessage'`.
|
|
968
|
+
"""
|
|
969
|
+
tag: str = "ChatMessage"
|
|
970
|
+
_value_class: Type[ChatMessageValue] = ChatMessageValue
|
|
971
|
+
|
|
972
|
+
def to_json_schema(self):
|
|
973
|
+
return {
|
|
974
|
+
"type": "object",
|
|
975
|
+
"required": ["chatmessage"],
|
|
976
|
+
"properties": {
|
|
977
|
+
"chatmessage": {
|
|
978
|
+
"type": "object",
|
|
979
|
+
"required": ["role", "content"],
|
|
980
|
+
"properties": {
|
|
981
|
+
"role": {"type": "string"},
|
|
982
|
+
"content": {"type": "string"},
|
|
983
|
+
"createdAt": {"type": "number"}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
},
|
|
987
|
+
"description": f"Chat message for {self.to_name[0]}"
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
|
|
953
991
|
class RelationsTag(ControlTag):
|
|
954
992
|
""" """
|
|
955
993
|
tag: str = "Relations"
|
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
"Header": "Task header",
|
|
11
11
|
"Paragraphs": [{"author": "Alice", "text": "Hi, Bob."}, {"author": "Bob", "text": "Hello, Alice!"}, {"author": "Alice", "text": "What's up?"}, {"author": "Bob", "text": "Good. Ciao!"}, {"author": "Alice", "text": "Bye, Bob."}],
|
|
12
12
|
"ParagraphsUrl": "<HOSTNAME>/samples/paragraphs.json?",
|
|
13
|
+
"Chat": [
|
|
14
|
+
{"role": "user", "content": "Hi there!", "createdAt": 1710000000000},
|
|
15
|
+
{"role": "assistant", "content": "Hello! How can I help you today?", "createdAt": 1710000005000},
|
|
16
|
+
{"role": "user", "content": "Can you summarize our onboarding checklist?", "createdAt": 1710000010000},
|
|
17
|
+
{"role": "assistant", "content": "Sure. It includes account setup, roles, labeling instructions, GT tasks, overlap and review.", "createdAt": 1710000015000}
|
|
18
|
+
],
|
|
13
19
|
"Table": {"Card number": 18799210, "First name": "Max", "Last name": "Nobel"},
|
|
14
20
|
"$videoHack": "<video src='<HOSTNAME>/static/samples/opossum_snow.mp4' width=100% controls>",
|
|
15
21
|
"Video": "<HOSTNAME>/static/samples/opossum_snow.mp4",
|
|
@@ -85,6 +91,10 @@
|
|
|
85
91
|
"AudioPlus": "<HOSTNAME>/static/samples/game.wav",
|
|
86
92
|
"Header": "Task header",
|
|
87
93
|
"Paragraphs": [{"author": "Alice", "text": "Hi, Bob."}, {"author": "Bob", "text": "Hello, Alice!"}, {"author": "Alice", "text": "What's up?"}, {"author": "Bob", "text": "Good. Ciao!"}, {"author": "Alice", "text": "Bye, Bob."}],
|
|
94
|
+
"Chat": [
|
|
95
|
+
{"role": "user", "content": "Hello!", "createdAt": 1710000000000},
|
|
96
|
+
{"role": "assistant", "content": "Hi! What can I do for you?", "createdAt": 1710000004000}
|
|
97
|
+
],
|
|
88
98
|
"Table": {"Card number": 18799210, "First name": "Max", "Last name": "Nobel"},
|
|
89
99
|
"$videoHack": "<video src='static/samples/opossum_snow.mp4' width=100% controls>",
|
|
90
100
|
"Video": "<HOSTNAME>/static/samples/opossum_snow.mp4",
|
|
@@ -27,6 +27,7 @@ from label_studio_sdk._legacy.exceptions import (
|
|
|
27
27
|
|
|
28
28
|
from .base import LabelStudioTag
|
|
29
29
|
from .control_tags import (
|
|
30
|
+
ChatMessageTag,
|
|
30
31
|
ControlTag,
|
|
31
32
|
ChoicesTag,
|
|
32
33
|
LabelsTag,
|
|
@@ -623,6 +624,18 @@ class LabelInterface:
|
|
|
623
624
|
if lb:
|
|
624
625
|
labels[lb.parent_name][lb.value] = lb
|
|
625
626
|
|
|
627
|
+
# Special handling: auto-create ChatMessage control for each Chat object
|
|
628
|
+
chat_object_names = [name for name, obj in objects.items() if getattr(obj, 'tag', '').lower() == 'chat']
|
|
629
|
+
for name in chat_object_names:
|
|
630
|
+
if name not in controls:
|
|
631
|
+
controls[name] = ChatMessageTag(
|
|
632
|
+
tag='ChatMessage',
|
|
633
|
+
name=name,
|
|
634
|
+
to_name=[name],
|
|
635
|
+
attr={"name": name, "toName": name}
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
|
|
626
639
|
return controls, objects, labels, xml_tree
|
|
627
640
|
|
|
628
641
|
@classmethod
|
|
@@ -20,6 +20,7 @@ _TAG_TO_CLASS = {
|
|
|
20
20
|
"list": "ListTag",
|
|
21
21
|
"paragraphs": "ParagraphsTag",
|
|
22
22
|
"timeseries": "TimeSeriesTag",
|
|
23
|
+
"chat": "ChatTag",
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
_DATA_EXAMPLES = None
|
|
@@ -306,3 +307,11 @@ class TimeSeriesTag(ObjectTag):
|
|
|
306
307
|
else:
|
|
307
308
|
# data is JSON
|
|
308
309
|
return generate_time_series_json(time_column, value_columns, time_format)
|
|
310
|
+
|
|
311
|
+
class ChatTag(ObjectTag):
|
|
312
|
+
""" """
|
|
313
|
+
tag: str = "Chat"
|
|
314
|
+
|
|
315
|
+
def _generate_example(self, examples, only_urls=False):
|
|
316
|
+
""" """
|
|
317
|
+
return examples.get("Chat")
|