label-studio-sdk 1.0.5__py3-none-any.whl → 1.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.
Potentially problematic release.
This version of label-studio-sdk might be problematic. Click here for more details.
- label_studio_sdk/__init__.py +76 -0
- label_studio_sdk/_extensions/eval/categorical.py +83 -0
- label_studio_sdk/_extensions/label_studio_tools/core/label_config.py +13 -4
- label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py +35 -17
- label_studio_sdk/_extensions/label_studio_tools/core/utils/json_schema.py +86 -0
- label_studio_sdk/_legacy/schema/label_config_schema.json +42 -11
- label_studio_sdk/annotations/__init__.py +3 -0
- label_studio_sdk/annotations/client.py +109 -0
- label_studio_sdk/annotations/types/__init__.py +5 -0
- label_studio_sdk/annotations/types/annotations_create_bulk_response_item.py +29 -0
- label_studio_sdk/base_client.py +9 -0
- label_studio_sdk/comments/__init__.py +2 -0
- label_studio_sdk/comments/client.py +512 -0
- label_studio_sdk/converter/converter.py +11 -4
- label_studio_sdk/converter/imports/coco.py +14 -13
- label_studio_sdk/converter/utils.py +72 -3
- label_studio_sdk/core/client_wrapper.py +1 -1
- label_studio_sdk/files/client.py +26 -16
- label_studio_sdk/label_interface/control_tags.py +205 -10
- label_studio_sdk/label_interface/interface.py +117 -10
- label_studio_sdk/label_interface/region.py +1 -10
- label_studio_sdk/model_providers/__init__.py +2 -0
- label_studio_sdk/model_providers/client.py +708 -0
- label_studio_sdk/projects/client.py +32 -16
- label_studio_sdk/projects/exports/client.py +133 -40
- label_studio_sdk/prompts/__init__.py +21 -0
- label_studio_sdk/prompts/client.py +862 -0
- label_studio_sdk/prompts/indicators/__init__.py +2 -0
- label_studio_sdk/prompts/indicators/client.py +194 -0
- label_studio_sdk/prompts/runs/__init__.py +5 -0
- label_studio_sdk/prompts/runs/client.py +354 -0
- label_studio_sdk/prompts/runs/types/__init__.py +5 -0
- label_studio_sdk/prompts/runs/types/runs_list_request_project_subset.py +5 -0
- label_studio_sdk/prompts/types/__init__.py +15 -0
- label_studio_sdk/prompts/types/prompts_batch_failed_predictions_request_failed_predictions_item.py +42 -0
- label_studio_sdk/prompts/types/prompts_batch_failed_predictions_response.py +29 -0
- label_studio_sdk/prompts/types/prompts_batch_predictions_request_results_item.py +62 -0
- label_studio_sdk/prompts/types/prompts_batch_predictions_response.py +29 -0
- label_studio_sdk/prompts/versions/__init__.py +2 -0
- label_studio_sdk/prompts/versions/client.py +1046 -0
- label_studio_sdk/types/__init__.py +58 -0
- label_studio_sdk/types/comment.py +39 -0
- label_studio_sdk/types/comment_created_by.py +5 -0
- label_studio_sdk/types/inference_run.py +43 -0
- label_studio_sdk/types/inference_run_cost_estimate.py +57 -0
- label_studio_sdk/types/inference_run_created_by.py +5 -0
- label_studio_sdk/types/inference_run_organization.py +5 -0
- label_studio_sdk/types/inference_run_project_subset.py +5 -0
- label_studio_sdk/types/inference_run_status.py +7 -0
- label_studio_sdk/types/key_indicator_value.py +30 -0
- label_studio_sdk/types/key_indicators.py +7 -0
- label_studio_sdk/types/key_indicators_item.py +51 -0
- label_studio_sdk/types/key_indicators_item_additional_kpis_item.py +37 -0
- label_studio_sdk/types/key_indicators_item_extra_kpis_item.py +37 -0
- label_studio_sdk/types/model_provider_connection.py +71 -0
- label_studio_sdk/types/model_provider_connection_budget_reset_period.py +5 -0
- label_studio_sdk/types/model_provider_connection_created_by.py +5 -0
- label_studio_sdk/types/model_provider_connection_organization.py +5 -0
- label_studio_sdk/types/model_provider_connection_provider.py +5 -0
- label_studio_sdk/types/model_provider_connection_scope.py +5 -0
- label_studio_sdk/types/prompt.py +79 -0
- label_studio_sdk/types/prompt_created_by.py +5 -0
- label_studio_sdk/types/prompt_organization.py +5 -0
- label_studio_sdk/types/prompt_version.py +41 -0
- label_studio_sdk/types/prompt_version_created_by.py +5 -0
- label_studio_sdk/types/prompt_version_organization.py +5 -0
- label_studio_sdk/types/prompt_version_provider.py +5 -0
- label_studio_sdk/types/refined_prompt_response.py +64 -0
- label_studio_sdk/types/refined_prompt_response_refinement_status.py +7 -0
- label_studio_sdk/types/task.py +3 -2
- label_studio_sdk/types/task_comment_authors_item.py +5 -0
- label_studio_sdk/webhooks/client.py +245 -36
- label_studio_sdk/workspaces/client.py +20 -20
- label_studio_sdk-1.0.8.dist-info/LICENSE +201 -0
- {label_studio_sdk-1.0.5.dist-info → label_studio_sdk-1.0.8.dist-info}/METADATA +19 -3
- {label_studio_sdk-1.0.5.dist-info → label_studio_sdk-1.0.8.dist-info}/RECORD +77 -24
- {label_studio_sdk-1.0.5.dist-info → label_studio_sdk-1.0.8.dist-info}/WHEEL +1 -1
|
@@ -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,
|
|
@@ -30,9 +31,11 @@ from .control_tags import (
|
|
|
30
31
|
)
|
|
31
32
|
from .object_tags import ObjectTag
|
|
32
33
|
from .label_tags import LabelTag
|
|
33
|
-
from .objects import AnnotationValue, TaskValue, PredictionValue
|
|
34
|
+
from .objects import AnnotationValue, TaskValue, PredictionValue, Region
|
|
34
35
|
from . import create as CE
|
|
35
36
|
|
|
37
|
+
logger = logging.getLogger(__name__)
|
|
38
|
+
|
|
36
39
|
|
|
37
40
|
dir_path = os.path.dirname(os.path.realpath(__file__))
|
|
38
41
|
file_path = os.path.join(dir_path, "..", "_legacy", "schema", "label_config_schema.json")
|
|
@@ -250,8 +253,7 @@ class LabelInterface:
|
|
|
250
253
|
"""
|
|
251
254
|
config = cls.create(*args, **kwargs)
|
|
252
255
|
return cls(config=config, **kwargs)
|
|
253
|
-
|
|
254
|
-
|
|
256
|
+
|
|
255
257
|
def __init__(self, config: str, tags_mapping=None, *args, **kwargs):
|
|
256
258
|
"""
|
|
257
259
|
Initialize a LabelInterface instance using a config string.
|
|
@@ -299,9 +301,42 @@ class LabelInterface:
|
|
|
299
301
|
self._labels = labels
|
|
300
302
|
self._tree = tree
|
|
301
303
|
|
|
302
|
-
|
|
304
|
+
def create_regions(self, data: Dict[str, Union[str, Dict, List[str], List[Dict]]]) -> List[Region]:
|
|
305
|
+
"""
|
|
306
|
+
Takes raw data representation and maps keys to control tag names.
|
|
307
|
+
If name is not found, it will be skipped
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
data (Dict): Raw data representation. Example: {"choices_name": "Positive", "labels_name": [{"start": 0, "end": 10, "label": "person"}]}
|
|
311
|
+
raise_if_control_not_found (bool): Raise an exception if control tag is not found.
|
|
312
|
+
"""
|
|
313
|
+
regions = []
|
|
314
|
+
for control_tag_name, payload in data.items():
|
|
315
|
+
if control_tag_name not in self._controls:
|
|
316
|
+
logger.info(f"Control tag '{control_tag_name}' not found in the config")
|
|
317
|
+
continue
|
|
318
|
+
|
|
319
|
+
control = self._controls[control_tag_name]
|
|
320
|
+
# TODO: I don't really like this part, looks like a workaround
|
|
321
|
+
# 1. we should allow control.label to process custom payload outside of those strictly containing "label"
|
|
322
|
+
# 2. we should be less open regarding the payload type and defining the strict typing elsewhere,
|
|
323
|
+
# but likely that requires rewriting of how ControlTag.label() is working now
|
|
324
|
+
if isinstance(payload, (str, int, float)):
|
|
325
|
+
payload = {'label': payload}
|
|
326
|
+
elif isinstance(payload, list):
|
|
327
|
+
if len(payload) > 0:
|
|
328
|
+
if isinstance(payload[0], str):
|
|
329
|
+
payload = {'label': payload}
|
|
330
|
+
else:
|
|
331
|
+
pass
|
|
303
332
|
|
|
304
|
-
|
|
333
|
+
if isinstance(payload, Dict):
|
|
334
|
+
payload = [payload]
|
|
335
|
+
|
|
336
|
+
for item in payload:
|
|
337
|
+
regions.append(control.label(**item))
|
|
338
|
+
|
|
339
|
+
return regions
|
|
305
340
|
|
|
306
341
|
@property
|
|
307
342
|
def config(self):
|
|
@@ -498,12 +533,26 @@ class LabelInterface:
|
|
|
498
533
|
tree.task_loaded = True
|
|
499
534
|
|
|
500
535
|
for obj in tree.objects:
|
|
501
|
-
print(obj.value_is_variable, obj.value_name)
|
|
502
536
|
if obj.value_is_variable and obj.value_name in task:
|
|
503
537
|
obj.value = task.get(obj.value_name)
|
|
504
538
|
|
|
505
539
|
return tree
|
|
506
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
|
+
|
|
507
556
|
def parse(self, config_string: str) -> Tuple[Dict, Dict, Dict, etree._Element]:
|
|
508
557
|
"""Parses the received configuration string into dictionaries
|
|
509
558
|
of ControlTags, ObjectTags, and Labels, along with an XML tree
|
|
@@ -722,7 +771,7 @@ class LabelInterface:
|
|
|
722
771
|
return False
|
|
723
772
|
|
|
724
773
|
# type of the region should match the tag name
|
|
725
|
-
if control.tag.lower() != region["type"]:
|
|
774
|
+
if control.tag.lower() != region["type"].lower():
|
|
726
775
|
return False
|
|
727
776
|
|
|
728
777
|
# make sure that in config it connects to the same tag as
|
|
@@ -791,9 +840,67 @@ class LabelInterface:
|
|
|
791
840
|
|
|
792
841
|
return task
|
|
793
842
|
|
|
794
|
-
def
|
|
795
|
-
""" """
|
|
796
|
-
|
|
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
|
|
797
904
|
|
|
798
905
|
#####
|
|
799
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()))
|