label-studio-sdk 1.0.7__py3-none-any.whl → 1.0.10__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.
Potentially problematic release.
This version of label-studio-sdk might be problematic. Click here for more details.
- label_studio_sdk/__init__.py +26 -7
- label_studio_sdk/_extensions/label_studio_tools/core/label_config.py +13 -4
- label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py +16 -4
- label_studio_sdk/_extensions/label_studio_tools/core/utils/json_schema.py +86 -0
- label_studio_sdk/_extensions/pager_ext.py +8 -0
- label_studio_sdk/_legacy/schema/label_config_schema.json +42 -11
- label_studio_sdk/actions/client.py +91 -40
- label_studio_sdk/actions/types/actions_create_request_filters.py +14 -24
- label_studio_sdk/actions/types/actions_create_request_filters_items_item.py +16 -26
- label_studio_sdk/actions/types/actions_create_request_filters_items_item_value.py +3 -1
- label_studio_sdk/actions/types/actions_create_request_selected_items.py +1 -2
- label_studio_sdk/actions/types/actions_create_request_selected_items_excluded.py +15 -25
- label_studio_sdk/actions/types/actions_create_request_selected_items_included.py +15 -25
- label_studio_sdk/annotations/__init__.py +2 -2
- label_studio_sdk/annotations/client.py +278 -104
- label_studio_sdk/annotations/types/__init__.py +2 -1
- label_studio_sdk/annotations/types/annotations_create_bulk_request_selected_items.py +34 -0
- label_studio_sdk/annotations/types/annotations_create_bulk_response_item.py +11 -21
- label_studio_sdk/base_client.py +46 -27
- label_studio_sdk/client.py +1 -0
- label_studio_sdk/comments/client.py +190 -44
- label_studio_sdk/converter/converter.py +66 -18
- label_studio_sdk/converter/imports/yolo.py +1 -1
- label_studio_sdk/converter/utils.py +3 -2
- label_studio_sdk/core/__init__.py +21 -4
- label_studio_sdk/core/client_wrapper.py +9 -10
- label_studio_sdk/core/file.py +37 -8
- label_studio_sdk/core/http_client.py +52 -28
- label_studio_sdk/core/jsonable_encoder.py +33 -31
- label_studio_sdk/core/pagination.py +5 -4
- label_studio_sdk/core/pydantic_utilities.py +272 -4
- label_studio_sdk/core/query_encoder.py +38 -13
- label_studio_sdk/core/request_options.py +3 -0
- label_studio_sdk/core/serialization.py +272 -0
- label_studio_sdk/errors/bad_request_error.py +2 -3
- label_studio_sdk/export_storage/azure/client.py +228 -58
- label_studio_sdk/export_storage/azure/types/azure_create_response.py +19 -29
- label_studio_sdk/export_storage/azure/types/azure_update_response.py +19 -29
- label_studio_sdk/export_storage/client.py +48 -18
- label_studio_sdk/export_storage/gcs/client.py +228 -58
- label_studio_sdk/export_storage/gcs/types/gcs_create_response.py +19 -29
- label_studio_sdk/export_storage/gcs/types/gcs_update_response.py +19 -29
- label_studio_sdk/export_storage/local/client.py +222 -56
- label_studio_sdk/export_storage/local/types/local_create_response.py +17 -27
- label_studio_sdk/export_storage/local/types/local_update_response.py +17 -27
- label_studio_sdk/export_storage/redis/client.py +228 -58
- label_studio_sdk/export_storage/redis/types/redis_create_response.py +20 -30
- label_studio_sdk/export_storage/redis/types/redis_update_response.py +20 -30
- label_studio_sdk/export_storage/s3/client.py +228 -58
- label_studio_sdk/export_storage/s3/types/s3create_response.py +27 -35
- label_studio_sdk/export_storage/s3/types/s3update_response.py +27 -35
- label_studio_sdk/export_storage/s3s/client.py +187 -43
- label_studio_sdk/export_storage/types/export_storage_list_types_response_item.py +11 -21
- label_studio_sdk/files/client.py +172 -56
- label_studio_sdk/import_storage/azure/client.py +223 -53
- label_studio_sdk/import_storage/azure/types/azure_create_response.py +22 -32
- label_studio_sdk/import_storage/azure/types/azure_update_response.py +22 -32
- label_studio_sdk/import_storage/client.py +48 -18
- label_studio_sdk/import_storage/gcs/client.py +223 -53
- label_studio_sdk/import_storage/gcs/types/gcs_create_response.py +22 -32
- label_studio_sdk/import_storage/gcs/types/gcs_update_response.py +22 -32
- label_studio_sdk/import_storage/local/client.py +223 -53
- label_studio_sdk/import_storage/local/types/local_create_response.py +17 -27
- label_studio_sdk/import_storage/local/types/local_update_response.py +17 -27
- label_studio_sdk/import_storage/redis/client.py +223 -53
- label_studio_sdk/import_storage/redis/types/redis_create_response.py +20 -30
- label_studio_sdk/import_storage/redis/types/redis_update_response.py +20 -30
- label_studio_sdk/import_storage/s3/client.py +223 -53
- label_studio_sdk/import_storage/s3/types/s3create_response.py +31 -39
- label_studio_sdk/import_storage/s3/types/s3update_response.py +31 -39
- label_studio_sdk/import_storage/s3s/client.py +222 -52
- label_studio_sdk/import_storage/types/import_storage_list_types_response_item.py +11 -21
- label_studio_sdk/label_interface/control_tags.py +205 -10
- label_studio_sdk/label_interface/interface.py +80 -6
- label_studio_sdk/label_interface/region.py +1 -10
- label_studio_sdk/ml/client.py +280 -78
- label_studio_sdk/ml/types/ml_create_response.py +21 -31
- label_studio_sdk/ml/types/ml_update_response.py +21 -31
- label_studio_sdk/model_providers/client.py +656 -21
- label_studio_sdk/predictions/client.py +247 -101
- label_studio_sdk/projects/__init__.py +3 -0
- label_studio_sdk/projects/client.py +309 -115
- label_studio_sdk/projects/client_ext.py +16 -0
- label_studio_sdk/projects/exports/__init__.py +3 -0
- label_studio_sdk/projects/exports/client.py +447 -296
- label_studio_sdk/projects/exports/client_ext.py +134 -0
- label_studio_sdk/projects/exports/types/__init__.py +6 -0
- label_studio_sdk/projects/exports/types/exports_convert_response.py +24 -0
- label_studio_sdk/projects/exports/types/exports_list_formats_response_item.py +44 -0
- label_studio_sdk/projects/types/projects_create_response.py +29 -34
- label_studio_sdk/projects/types/projects_import_tasks_response.py +19 -29
- label_studio_sdk/projects/types/projects_list_response.py +11 -21
- label_studio_sdk/projects/types/projects_update_response.py +24 -34
- label_studio_sdk/prompts/client.py +309 -92
- label_studio_sdk/prompts/indicators/client.py +67 -23
- label_studio_sdk/prompts/runs/client.py +95 -40
- label_studio_sdk/prompts/types/prompts_batch_failed_predictions_request_failed_predictions_item.py +14 -24
- label_studio_sdk/prompts/types/prompts_batch_failed_predictions_response.py +11 -21
- label_studio_sdk/prompts/types/prompts_batch_predictions_request_results_item.py +26 -29
- label_studio_sdk/prompts/types/prompts_batch_predictions_response.py +11 -21
- label_studio_sdk/prompts/versions/client.py +389 -75
- label_studio_sdk/tasks/client.py +263 -90
- label_studio_sdk/tasks/types/tasks_list_response.py +15 -25
- label_studio_sdk/types/__init__.py +16 -6
- label_studio_sdk/types/annotation.py +29 -38
- label_studio_sdk/types/annotation_filter_options.py +14 -24
- label_studio_sdk/types/annotations_dm_field.py +30 -39
- label_studio_sdk/types/azure_blob_export_storage.py +28 -37
- label_studio_sdk/types/azure_blob_import_storage.py +28 -37
- label_studio_sdk/types/base_task.py +30 -39
- label_studio_sdk/types/base_task_updated_by.py +3 -1
- label_studio_sdk/types/base_user.py +14 -21
- label_studio_sdk/types/comment.py +12 -21
- label_studio_sdk/types/comment_created_by.py +1 -1
- label_studio_sdk/types/converted_format.py +12 -22
- label_studio_sdk/types/data_manager_task_serializer.py +31 -40
- label_studio_sdk/types/data_manager_task_serializer_annotators_item.py +1 -1
- label_studio_sdk/types/data_manager_task_serializer_drafts_item.py +13 -22
- label_studio_sdk/types/data_manager_task_serializer_predictions_item.py +15 -24
- label_studio_sdk/types/export.py +17 -26
- label_studio_sdk/types/export_format.py +25 -0
- label_studio_sdk/types/export_snapshot.py +45 -0
- label_studio_sdk/types/export_snapshot_status.py +5 -0
- label_studio_sdk/types/file_upload.py +11 -21
- label_studio_sdk/types/filter.py +16 -26
- label_studio_sdk/types/filter_group.py +12 -22
- label_studio_sdk/types/gcs_export_storage.py +28 -37
- label_studio_sdk/types/gcs_import_storage.py +28 -37
- label_studio_sdk/types/inference_run.py +14 -23
- label_studio_sdk/types/inference_run_cost_estimate.py +47 -0
- label_studio_sdk/types/inference_run_created_by.py +1 -1
- label_studio_sdk/types/inference_run_organization.py +1 -1
- label_studio_sdk/types/key_indicator_value.py +12 -22
- label_studio_sdk/types/key_indicators.py +0 -1
- label_studio_sdk/types/key_indicators_item.py +15 -25
- label_studio_sdk/types/key_indicators_item_additional_kpis_item.py +13 -23
- label_studio_sdk/types/key_indicators_item_extra_kpis_item.py +13 -23
- label_studio_sdk/types/local_files_export_storage.py +25 -34
- label_studio_sdk/types/local_files_import_storage.py +24 -33
- label_studio_sdk/types/ml_backend.py +23 -32
- label_studio_sdk/types/model_provider_connection.py +47 -26
- label_studio_sdk/types/model_provider_connection_budget_reset_period.py +5 -0
- label_studio_sdk/types/model_provider_connection_created_by.py +1 -1
- label_studio_sdk/types/model_provider_connection_organization.py +1 -1
- label_studio_sdk/types/model_provider_connection_provider.py +3 -1
- label_studio_sdk/types/prediction.py +21 -30
- label_studio_sdk/types/project.py +48 -55
- label_studio_sdk/types/project_import.py +21 -30
- label_studio_sdk/types/project_label_config.py +12 -22
- label_studio_sdk/types/prompt.py +24 -32
- label_studio_sdk/types/prompt_associated_projects_item.py +6 -0
- label_studio_sdk/types/prompt_associated_projects_item_id.py +20 -0
- label_studio_sdk/types/prompt_created_by.py +1 -1
- label_studio_sdk/types/prompt_organization.py +1 -1
- label_studio_sdk/types/prompt_version.py +13 -22
- label_studio_sdk/types/prompt_version_created_by.py +1 -1
- label_studio_sdk/types/prompt_version_organization.py +1 -1
- label_studio_sdk/types/prompt_version_provider.py +3 -1
- label_studio_sdk/types/redis_export_storage.py +29 -38
- label_studio_sdk/types/redis_import_storage.py +28 -37
- label_studio_sdk/types/refined_prompt_response.py +19 -29
- label_studio_sdk/types/s3export_storage.py +36 -43
- label_studio_sdk/types/s3import_storage.py +37 -44
- label_studio_sdk/types/s3s_export_storage.py +26 -33
- label_studio_sdk/types/s3s_import_storage.py +35 -42
- label_studio_sdk/types/serialization_option.py +12 -22
- label_studio_sdk/types/serialization_options.py +18 -28
- label_studio_sdk/types/task.py +46 -48
- label_studio_sdk/types/task_annotators_item.py +1 -1
- label_studio_sdk/types/task_comment_authors_item.py +5 -0
- label_studio_sdk/types/task_filter_options.py +15 -25
- label_studio_sdk/types/user_simple.py +11 -21
- label_studio_sdk/types/view.py +16 -26
- label_studio_sdk/types/webhook.py +19 -28
- label_studio_sdk/types/webhook_serializer_for_update.py +19 -28
- label_studio_sdk/types/workspace.py +22 -31
- label_studio_sdk/users/client.py +257 -63
- label_studio_sdk/users/types/users_get_token_response.py +12 -22
- label_studio_sdk/users/types/users_reset_token_response.py +12 -22
- label_studio_sdk/version.py +0 -1
- label_studio_sdk/versions/__init__.py +5 -0
- label_studio_sdk/versions/client.py +112 -0
- label_studio_sdk/versions/types/__init__.py +6 -0
- label_studio_sdk/versions/types/versions_get_response.py +73 -0
- label_studio_sdk/versions/types/versions_get_response_edition.py +5 -0
- label_studio_sdk/views/client.py +219 -52
- label_studio_sdk/views/types/views_create_request_data.py +13 -23
- label_studio_sdk/views/types/views_create_request_data_filters.py +14 -24
- label_studio_sdk/views/types/views_create_request_data_filters_items_item.py +16 -26
- label_studio_sdk/views/types/views_create_request_data_filters_items_item_value.py +3 -1
- label_studio_sdk/views/types/views_update_request_data.py +13 -23
- label_studio_sdk/views/types/views_update_request_data_filters.py +14 -24
- label_studio_sdk/views/types/views_update_request_data_filters_items_item.py +16 -26
- label_studio_sdk/views/types/views_update_request_data_filters_items_item_value.py +3 -1
- label_studio_sdk/webhooks/client.py +191 -61
- label_studio_sdk/workspaces/client.py +164 -41
- label_studio_sdk/workspaces/members/client.py +109 -31
- label_studio_sdk/workspaces/members/types/members_create_response.py +12 -22
- label_studio_sdk/workspaces/members/types/members_list_response_item.py +12 -22
- {label_studio_sdk-1.0.7.dist-info → label_studio_sdk-1.0.10.dist-info}/METADATA +9 -5
- {label_studio_sdk-1.0.7.dist-info → label_studio_sdk-1.0.10.dist-info}/RECORD +203 -186
- {label_studio_sdk-1.0.7.dist-info → label_studio_sdk-1.0.10.dist-info}/WHEEL +1 -1
- label_studio_sdk/types/export_convert.py +0 -32
- label_studio_sdk/types/export_create.py +0 -54
- label_studio_sdk/types/export_create_status.py +0 -5
- {label_studio_sdk-1.0.7.dist-info → label_studio_sdk-1.0.10.dist-info}/LICENSE +0 -0
|
@@ -93,6 +93,15 @@ class ControlTag(LabelStudioTag):
|
|
|
93
93
|
and tag.tag not in _NOT_CONTROL_TAGS
|
|
94
94
|
)
|
|
95
95
|
|
|
96
|
+
def to_json_schema(self):
|
|
97
|
+
"""
|
|
98
|
+
Converts the current ControlTag instance into a JSON Schema.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
dict: A dictionary representing the JSON Schema.
|
|
102
|
+
"""
|
|
103
|
+
return {"type": "string"}
|
|
104
|
+
|
|
96
105
|
@classmethod
|
|
97
106
|
def parse_node(cls, tag: xml.etree.ElementTree.Element, tags_mapping=None) -> "ControlTag":
|
|
98
107
|
"""
|
|
@@ -261,11 +270,11 @@ class ControlTag(LabelStudioTag):
|
|
|
261
270
|
|
|
262
271
|
def _validate_labels(self, labels):
|
|
263
272
|
"""Check that labels is a subset of self.labels, used for
|
|
264
|
-
example when you're validate the
|
|
273
|
+
example when you're validate the annotation or prediction to
|
|
265
274
|
make sure there no undefined labels used.
|
|
266
275
|
|
|
267
276
|
"""
|
|
268
|
-
if not self.labels:
|
|
277
|
+
if not self.labels or not labels:
|
|
269
278
|
return True
|
|
270
279
|
|
|
271
280
|
return set(labels).issubset(set(self.labels))
|
|
@@ -335,10 +344,11 @@ class ControlTag(LabelStudioTag):
|
|
|
335
344
|
|
|
336
345
|
return to_name
|
|
337
346
|
else:
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
347
|
+
# TODO: "Pairwise" tag has multiple to_name
|
|
348
|
+
# if len(self.to_name) > 1:
|
|
349
|
+
# raise Exception(
|
|
350
|
+
# "Multiple to_name in control tag, specify to_name in function"
|
|
351
|
+
# )
|
|
342
352
|
|
|
343
353
|
return self.to_name[0]
|
|
344
354
|
|
|
@@ -415,7 +425,7 @@ class ControlTag(LabelStudioTag):
|
|
|
415
425
|
)
|
|
416
426
|
|
|
417
427
|
kwargs[self._label_attr_name] = label
|
|
418
|
-
|
|
428
|
+
|
|
419
429
|
return self._label_simple(to_name=to_name, **kwargs)
|
|
420
430
|
|
|
421
431
|
def label(
|
|
@@ -446,12 +456,29 @@ class ControlTag(LabelStudioTag):
|
|
|
446
456
|
Region
|
|
447
457
|
A new Region object with the specified label applied.
|
|
448
458
|
"""
|
|
449
|
-
if hasattr(self, "_label_attr_name"):
|
|
459
|
+
if hasattr(self, "_label_attr_name") and label is not None:
|
|
450
460
|
return self._label_with_labels(
|
|
451
461
|
label=label, to_name=to_name, *args, **kwargs
|
|
452
462
|
)
|
|
453
463
|
else:
|
|
454
464
|
return self._label_simple(to_name=to_name, *args, **kwargs)
|
|
465
|
+
|
|
466
|
+
def get_labels(self, regions: List[Dict]):
|
|
467
|
+
"""
|
|
468
|
+
Returns the simplified representation of the label. Sort of a reverse to label() method to retrieve an input `label` from an output regions
|
|
469
|
+
"""
|
|
470
|
+
values = [region.get('value') for region in regions if region.get('from_name') == self.name]
|
|
471
|
+
values = list(filter(lambda x: x is not None, values))
|
|
472
|
+
if not hasattr(self, "_label_attr_name"):
|
|
473
|
+
return values
|
|
474
|
+
labels = []
|
|
475
|
+
for value in values:
|
|
476
|
+
if len(value) == 1 and self._label_attr_name in value:
|
|
477
|
+
v = value[self._label_attr_name]
|
|
478
|
+
labels.append(v[0] if type(v) == list and len(v) == 1 else v)
|
|
479
|
+
else:
|
|
480
|
+
labels.append(value)
|
|
481
|
+
return labels[0] if len(labels) == 1 else labels
|
|
455
482
|
|
|
456
483
|
def as_tuple(self):
|
|
457
484
|
""" """
|
|
@@ -485,6 +512,34 @@ class ChoicesTag(ControlTag):
|
|
|
485
512
|
_label_attr_name: str = "choices"
|
|
486
513
|
_value_class: Type[ChoicesValue] = ChoicesValue
|
|
487
514
|
|
|
515
|
+
@property
|
|
516
|
+
def is_multiple_choice(self):
|
|
517
|
+
return self.attr.get("choice") == "multiple"
|
|
518
|
+
|
|
519
|
+
def to_json_schema(self):
|
|
520
|
+
"""
|
|
521
|
+
Converts the current ChoicesTag instance into a JSON Schema.
|
|
522
|
+
|
|
523
|
+
Returns:
|
|
524
|
+
dict: A dictionary representing the JSON Schema compatible with OpenAPI 3.
|
|
525
|
+
"""
|
|
526
|
+
if self.is_multiple_choice:
|
|
527
|
+
return {
|
|
528
|
+
"type": "array",
|
|
529
|
+
"items": {
|
|
530
|
+
"type": "string",
|
|
531
|
+
"enum": self.labels,
|
|
532
|
+
},
|
|
533
|
+
"uniqueItems": True,
|
|
534
|
+
"description": f"Choices for {self.to_name[0]}",
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return {
|
|
538
|
+
"type": "string",
|
|
539
|
+
"enum": self.labels,
|
|
540
|
+
"description": f"Choices for {self.to_name[0]}"
|
|
541
|
+
}
|
|
542
|
+
|
|
488
543
|
|
|
489
544
|
class LabelsValue(SpanSelection):
|
|
490
545
|
labels: List[str]
|
|
@@ -496,6 +551,41 @@ class LabelsTag(ControlTag):
|
|
|
496
551
|
_label_attr_name: str = "labels"
|
|
497
552
|
_value_class: Type[LabelsValue] = LabelsValue
|
|
498
553
|
|
|
554
|
+
def to_json_schema(self):
|
|
555
|
+
"""
|
|
556
|
+
Converts the current LabelsTag instance into a JSON Schema.
|
|
557
|
+
|
|
558
|
+
Returns:
|
|
559
|
+
dict: A dictionary representing the JSON Schema compatible with OpenAPI 3.
|
|
560
|
+
"""
|
|
561
|
+
return {
|
|
562
|
+
"type": "array",
|
|
563
|
+
"items": {
|
|
564
|
+
"type": "object",
|
|
565
|
+
"required": ["start", "end", "labels"],
|
|
566
|
+
"properties": {
|
|
567
|
+
"start": {
|
|
568
|
+
"type": "integer",
|
|
569
|
+
"minimum": 0
|
|
570
|
+
},
|
|
571
|
+
"end": {
|
|
572
|
+
"type": "integer",
|
|
573
|
+
"minimum": 0
|
|
574
|
+
},
|
|
575
|
+
"labels": {
|
|
576
|
+
"type": "array",
|
|
577
|
+
"items": {
|
|
578
|
+
"type": "string",
|
|
579
|
+
"enum": self.labels
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
"text": {
|
|
583
|
+
"type": "string"
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
"description": f"Labels and span indices for {self.to_name[0]}"
|
|
588
|
+
}
|
|
499
589
|
|
|
500
590
|
## Image tags
|
|
501
591
|
|
|
@@ -684,6 +774,26 @@ class NumberTag(ControlTag):
|
|
|
684
774
|
""" """
|
|
685
775
|
tag: str = "Number"
|
|
686
776
|
_value_class: Type[NumberValue] = NumberValue
|
|
777
|
+
_label_attr_name: str = "number"
|
|
778
|
+
|
|
779
|
+
def to_json_schema(self):
|
|
780
|
+
"""
|
|
781
|
+
Converts the current NumberTag instance into a JSON Schema.
|
|
782
|
+
|
|
783
|
+
Returns:
|
|
784
|
+
dict: A dictionary representing the JSON Schema compatible with OpenAPI 3.
|
|
785
|
+
"""
|
|
786
|
+
schema = {
|
|
787
|
+
"type": "number",
|
|
788
|
+
"description": f"Number for {self.to_name[0]}"
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
if 'min' in self.attr:
|
|
792
|
+
schema["minimum"] = float(self.attr['min'])
|
|
793
|
+
if 'max' in self.attr:
|
|
794
|
+
schema["maximum"] = float(self.attr['max'])
|
|
795
|
+
|
|
796
|
+
return schema
|
|
687
797
|
|
|
688
798
|
|
|
689
799
|
class DateTimeValue(BaseModel):
|
|
@@ -694,6 +804,25 @@ class DateTimeTag(ControlTag):
|
|
|
694
804
|
""" """
|
|
695
805
|
tag: str = "DateTime"
|
|
696
806
|
_value_class: Type[DateTimeValue] = DateTimeValue
|
|
807
|
+
_label_attr_name: str = "datetime"
|
|
808
|
+
|
|
809
|
+
def _label_simple(self, to_name: Optional[str] = None, *args, **kwargs) -> Region:
|
|
810
|
+
# TODO: temporary fix to force datetime to be a string
|
|
811
|
+
kwargs['datetime'] = kwargs['datetime'][0]
|
|
812
|
+
return super()._label_simple(to_name, *args, **kwargs)
|
|
813
|
+
|
|
814
|
+
def to_json_schema(self):
|
|
815
|
+
"""
|
|
816
|
+
Converts the current DateTimeTag instance into a JSON Schema.
|
|
817
|
+
|
|
818
|
+
Returns:
|
|
819
|
+
dict: A dictionary representing the JSON Schema compatible with OpenAPI 3.
|
|
820
|
+
"""
|
|
821
|
+
return {
|
|
822
|
+
"type": "string",
|
|
823
|
+
"format": "date-time",
|
|
824
|
+
"description": f"Date and time for {self.to_name[0]}"
|
|
825
|
+
}
|
|
697
826
|
|
|
698
827
|
|
|
699
828
|
class HyperTextLabelsValue(SpanSelectionOffsets):
|
|
@@ -715,12 +844,27 @@ class PairwiseTag(ControlTag):
|
|
|
715
844
|
""" """
|
|
716
845
|
tag: str = "Pairwise"
|
|
717
846
|
_value_class: Type[PairwiseValue] = PairwiseValue
|
|
847
|
+
_label_attr_name: str = "selected"
|
|
718
848
|
|
|
719
|
-
def label(self,
|
|
849
|
+
def label(self, label):
|
|
720
850
|
""" """
|
|
721
|
-
value = PairwiseValue(selected=
|
|
851
|
+
value = PairwiseValue(selected=label)
|
|
852
|
+
# <Pairwise> tag has equal from_name and to_name, and string label that's not a list of strings
|
|
722
853
|
return Region(from_tag=self, to_tag=self, value=value)
|
|
723
854
|
|
|
855
|
+
def to_json_schema(self):
|
|
856
|
+
"""
|
|
857
|
+
Converts the current PairwiseTag instance into a JSON Schema.
|
|
858
|
+
|
|
859
|
+
Returns:
|
|
860
|
+
dict: A dictionary representing the JSON Schema compatible with OpenAPI 3.
|
|
861
|
+
"""
|
|
862
|
+
return {
|
|
863
|
+
"type": "string",
|
|
864
|
+
"enum": ["left", "right"],
|
|
865
|
+
"description": f"Pairwise selection between {self.to_name[0]} (left) and {self.to_name[1]} (right)"
|
|
866
|
+
}
|
|
867
|
+
|
|
724
868
|
|
|
725
869
|
class ParagraphLabelsValue(SpanSelectionOffsets):
|
|
726
870
|
paragraphlabels: List[str]
|
|
@@ -759,6 +903,22 @@ class RatingTag(ControlTag):
|
|
|
759
903
|
""" """
|
|
760
904
|
tag: str = "Rating"
|
|
761
905
|
_value_class: Type[RatingValue] = RatingValue
|
|
906
|
+
_label_attr_name: str = "rating"
|
|
907
|
+
|
|
908
|
+
def to_json_schema(self):
|
|
909
|
+
"""
|
|
910
|
+
Converts the current RatingTag instance into a JSON Schema.
|
|
911
|
+
|
|
912
|
+
Returns:
|
|
913
|
+
dict: A dictionary representing the JSON Schema compatible with OpenAPI 3.
|
|
914
|
+
"""
|
|
915
|
+
max_rating = int(self.attr.get('maxRating', 5)) # Default to 5 if not specified
|
|
916
|
+
return {
|
|
917
|
+
"type": "integer",
|
|
918
|
+
"minimum": 0,
|
|
919
|
+
"maximum": max_rating,
|
|
920
|
+
"description": f"Rating for {self.to_name[0]} (0 to {max_rating})"
|
|
921
|
+
}
|
|
762
922
|
|
|
763
923
|
|
|
764
924
|
class RelationsTag(ControlTag):
|
|
@@ -784,6 +944,27 @@ class TaxonomyTag(ControlTag):
|
|
|
784
944
|
""" """
|
|
785
945
|
tag: str = "Taxonomy"
|
|
786
946
|
_value_class: Type[TaxonomyValue] = TaxonomyValue
|
|
947
|
+
_label_attr_name: str = "taxonomy"
|
|
948
|
+
|
|
949
|
+
def to_json_schema(self):
|
|
950
|
+
"""
|
|
951
|
+
Converts the current TaxonomyTag instance into a JSON Schema.
|
|
952
|
+
|
|
953
|
+
Returns:
|
|
954
|
+
dict: A dictionary representing the JSON Schema compatible with OpenAPI 3.
|
|
955
|
+
"""
|
|
956
|
+
return {
|
|
957
|
+
"type": "array",
|
|
958
|
+
"items": {
|
|
959
|
+
"type": "array",
|
|
960
|
+
"items": {
|
|
961
|
+
"type": "string",
|
|
962
|
+
# TODO: enforce the order of the enums according to the taxonomy tree
|
|
963
|
+
"enum": self.labels
|
|
964
|
+
}
|
|
965
|
+
},
|
|
966
|
+
"description": f"Taxonomy for {self.to_name[0]}. Each item is a path from root to selected node."
|
|
967
|
+
}
|
|
787
968
|
|
|
788
969
|
|
|
789
970
|
class TextAreaValue(BaseModel):
|
|
@@ -794,6 +975,20 @@ class TextAreaTag(ControlTag):
|
|
|
794
975
|
""" """
|
|
795
976
|
tag: str = "TextArea"
|
|
796
977
|
_value_class: Type[TextAreaValue] = TextAreaValue
|
|
978
|
+
_label_attr_name: str = "text"
|
|
979
|
+
|
|
980
|
+
def to_json_schema(self):
|
|
981
|
+
"""
|
|
982
|
+
Converts the current TextAreaTag instance into a JSON Schema.
|
|
983
|
+
|
|
984
|
+
Returns:
|
|
985
|
+
dict: A dictionary representing the JSON Schema compatible with OpenAPI 3.
|
|
986
|
+
"""
|
|
987
|
+
return {
|
|
988
|
+
"type": "string",
|
|
989
|
+
"description": f"Text for {self.to_name[0]}"
|
|
990
|
+
}
|
|
991
|
+
|
|
797
992
|
|
|
798
993
|
|
|
799
994
|
class TimeSeriesValue(SpanSelection):
|
|
@@ -15,6 +15,7 @@ from pydantic import BaseModel
|
|
|
15
15
|
from collections import defaultdict, OrderedDict
|
|
16
16
|
from lxml import etree
|
|
17
17
|
import xmljson
|
|
18
|
+
from jsf import JSF
|
|
18
19
|
|
|
19
20
|
from label_studio_sdk._legacy.exceptions import (
|
|
20
21
|
LSConfigParseException,
|
|
@@ -320,7 +321,7 @@ class LabelInterface:
|
|
|
320
321
|
# 1. we should allow control.label to process custom payload outside of those strictly containing "label"
|
|
321
322
|
# 2. we should be less open regarding the payload type and defining the strict typing elsewhere,
|
|
322
323
|
# but likely that requires rewriting of how ControlTag.label() is working now
|
|
323
|
-
if isinstance(payload, str):
|
|
324
|
+
if isinstance(payload, (str, int, float)):
|
|
324
325
|
payload = {'label': payload}
|
|
325
326
|
elif isinstance(payload, list):
|
|
326
327
|
if len(payload) > 0:
|
|
@@ -331,6 +332,7 @@ class LabelInterface:
|
|
|
331
332
|
|
|
332
333
|
if isinstance(payload, Dict):
|
|
333
334
|
payload = [payload]
|
|
335
|
+
|
|
334
336
|
for item in payload:
|
|
335
337
|
regions.append(control.label(**item))
|
|
336
338
|
|
|
@@ -531,12 +533,26 @@ class LabelInterface:
|
|
|
531
533
|
tree.task_loaded = True
|
|
532
534
|
|
|
533
535
|
for obj in tree.objects:
|
|
534
|
-
print(obj.value_is_variable, obj.value_name)
|
|
535
536
|
if obj.value_is_variable and obj.value_name in task:
|
|
536
537
|
obj.value = task.get(obj.value_name)
|
|
537
538
|
|
|
538
539
|
return tree
|
|
539
540
|
|
|
541
|
+
def to_json_schema(self):
|
|
542
|
+
"""
|
|
543
|
+
Converts the current LabelInterface instance into a JSON Schema.
|
|
544
|
+
|
|
545
|
+
Returns:
|
|
546
|
+
dict: A dictionary representing the JSON Schema.
|
|
547
|
+
"""
|
|
548
|
+
return {
|
|
549
|
+
"type": "object",
|
|
550
|
+
"properties": {
|
|
551
|
+
name: control.to_json_schema() for name, control in self._controls.items()
|
|
552
|
+
},
|
|
553
|
+
"required": list(self._controls.keys())
|
|
554
|
+
}
|
|
555
|
+
|
|
540
556
|
def parse(self, config_string: str) -> Tuple[Dict, Dict, Dict, etree._Element]:
|
|
541
557
|
"""Parses the received configuration string into dictionaries
|
|
542
558
|
of ControlTags, ObjectTags, and Labels, along with an XML tree
|
|
@@ -755,7 +771,7 @@ class LabelInterface:
|
|
|
755
771
|
return False
|
|
756
772
|
|
|
757
773
|
# type of the region should match the tag name
|
|
758
|
-
if control.tag.lower() != region["type"]:
|
|
774
|
+
if control.tag.lower() != region["type"].lower():
|
|
759
775
|
return False
|
|
760
776
|
|
|
761
777
|
# make sure that in config it connects to the same tag as
|
|
@@ -824,9 +840,67 @@ class LabelInterface:
|
|
|
824
840
|
|
|
825
841
|
return task
|
|
826
842
|
|
|
827
|
-
def
|
|
828
|
-
""" """
|
|
829
|
-
|
|
843
|
+
def _generate_sample_regions(self):
|
|
844
|
+
""" Generate an example of each control tag's JSON schema and validate it as a region"""
|
|
845
|
+
return self.create_regions({
|
|
846
|
+
control.name: JSF(control.to_json_schema()).generate()
|
|
847
|
+
for control in self.controls
|
|
848
|
+
})
|
|
849
|
+
|
|
850
|
+
def generate_sample_prediction(self) -> Optional[dict]:
|
|
851
|
+
"""Generates a sample prediction that is valid for this label config.
|
|
852
|
+
|
|
853
|
+
Example:
|
|
854
|
+
{'model_version': 'sample model version',
|
|
855
|
+
'score': 0.0,
|
|
856
|
+
'result': [{'id': 'e7bd76e6-4e88-4eb3-b433-55e03661bf5d',
|
|
857
|
+
'from_name': 'sentiment',
|
|
858
|
+
'to_name': 'text',
|
|
859
|
+
'type': 'choices',
|
|
860
|
+
'value': {'choices': ['Neutral']}}]}
|
|
861
|
+
|
|
862
|
+
NOTE: `id` field in result is not required when importing predictions; it will be generated automatically.
|
|
863
|
+
NOTE: for each control tag, depends on tag.to_json_schema() being implemented correctly
|
|
864
|
+
"""
|
|
865
|
+
prediction = PredictionValue(
|
|
866
|
+
model_version='sample model version',
|
|
867
|
+
result=self._generate_sample_regions()
|
|
868
|
+
)
|
|
869
|
+
prediction_dct = prediction.model_dump()
|
|
870
|
+
if self.validate_prediction(prediction_dct):
|
|
871
|
+
return prediction_dct
|
|
872
|
+
else:
|
|
873
|
+
logger.debug(f'Sample prediction {prediction_dct} failed validation for label config {self.config}')
|
|
874
|
+
return None
|
|
875
|
+
|
|
876
|
+
def generate_sample_annotation(self) -> Optional[dict]:
|
|
877
|
+
"""Generates a sample annotation that is valid for this label config.
|
|
878
|
+
|
|
879
|
+
Example:
|
|
880
|
+
{'was_cancelled': False,
|
|
881
|
+
'ground_truth': False,
|
|
882
|
+
'lead_time': 0.0,
|
|
883
|
+
'result_count': 0,
|
|
884
|
+
'completed_by': -1,
|
|
885
|
+
'result': [{'id': 'b05da11d-3ffc-4657-8b8d-f5bc37cd59ac',
|
|
886
|
+
'from_name': 'sentiment',
|
|
887
|
+
'to_name': 'text',
|
|
888
|
+
'type': 'choices',
|
|
889
|
+
'value': {'choices': ['Negative']}}]}
|
|
890
|
+
|
|
891
|
+
NOTE: `id` field in result is not required when importing predictions; it will be generated automatically.
|
|
892
|
+
NOTE: for each control tag, depends on tag.to_json_schema() being implemented correctly
|
|
893
|
+
"""
|
|
894
|
+
annotation = AnnotationValue(
|
|
895
|
+
completed_by=-1, # annotator's user id
|
|
896
|
+
result=self._generate_sample_regions()
|
|
897
|
+
)
|
|
898
|
+
annotation_dct = annotation.model_dump()
|
|
899
|
+
if self.validate_annotation(annotation_dct):
|
|
900
|
+
return annotation_dct
|
|
901
|
+
else:
|
|
902
|
+
logger.debug(f'Sample annotation {annotation_dct} failed validation for label config {self.config}')
|
|
903
|
+
return None
|
|
830
904
|
|
|
831
905
|
#####
|
|
832
906
|
##### COMPATIBILITY LAYER
|
|
@@ -10,16 +10,7 @@ from pydantic import BaseModel, Field
|
|
|
10
10
|
|
|
11
11
|
class Region(BaseModel):
|
|
12
12
|
"""
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Attributes:
|
|
16
|
-
-----------
|
|
17
|
-
id: str
|
|
18
|
-
The unique identifier of the region
|
|
19
|
-
x: int
|
|
20
|
-
The x coordinate of the region
|
|
21
|
-
y: int
|
|
22
|
-
|
|
13
|
+
A Region is an item in the `result` list of a PredictionValue or AnnotationValue.
|
|
23
14
|
"""
|
|
24
15
|
|
|
25
16
|
id: str = Field(default_factory=lambda: str(uuid4()))
|