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.

Files changed (77) hide show
  1. label_studio_sdk/__init__.py +76 -0
  2. label_studio_sdk/_extensions/eval/categorical.py +83 -0
  3. label_studio_sdk/_extensions/label_studio_tools/core/label_config.py +13 -4
  4. label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py +35 -17
  5. label_studio_sdk/_extensions/label_studio_tools/core/utils/json_schema.py +86 -0
  6. label_studio_sdk/_legacy/schema/label_config_schema.json +42 -11
  7. label_studio_sdk/annotations/__init__.py +3 -0
  8. label_studio_sdk/annotations/client.py +109 -0
  9. label_studio_sdk/annotations/types/__init__.py +5 -0
  10. label_studio_sdk/annotations/types/annotations_create_bulk_response_item.py +29 -0
  11. label_studio_sdk/base_client.py +9 -0
  12. label_studio_sdk/comments/__init__.py +2 -0
  13. label_studio_sdk/comments/client.py +512 -0
  14. label_studio_sdk/converter/converter.py +11 -4
  15. label_studio_sdk/converter/imports/coco.py +14 -13
  16. label_studio_sdk/converter/utils.py +72 -3
  17. label_studio_sdk/core/client_wrapper.py +1 -1
  18. label_studio_sdk/files/client.py +26 -16
  19. label_studio_sdk/label_interface/control_tags.py +205 -10
  20. label_studio_sdk/label_interface/interface.py +117 -10
  21. label_studio_sdk/label_interface/region.py +1 -10
  22. label_studio_sdk/model_providers/__init__.py +2 -0
  23. label_studio_sdk/model_providers/client.py +708 -0
  24. label_studio_sdk/projects/client.py +32 -16
  25. label_studio_sdk/projects/exports/client.py +133 -40
  26. label_studio_sdk/prompts/__init__.py +21 -0
  27. label_studio_sdk/prompts/client.py +862 -0
  28. label_studio_sdk/prompts/indicators/__init__.py +2 -0
  29. label_studio_sdk/prompts/indicators/client.py +194 -0
  30. label_studio_sdk/prompts/runs/__init__.py +5 -0
  31. label_studio_sdk/prompts/runs/client.py +354 -0
  32. label_studio_sdk/prompts/runs/types/__init__.py +5 -0
  33. label_studio_sdk/prompts/runs/types/runs_list_request_project_subset.py +5 -0
  34. label_studio_sdk/prompts/types/__init__.py +15 -0
  35. label_studio_sdk/prompts/types/prompts_batch_failed_predictions_request_failed_predictions_item.py +42 -0
  36. label_studio_sdk/prompts/types/prompts_batch_failed_predictions_response.py +29 -0
  37. label_studio_sdk/prompts/types/prompts_batch_predictions_request_results_item.py +62 -0
  38. label_studio_sdk/prompts/types/prompts_batch_predictions_response.py +29 -0
  39. label_studio_sdk/prompts/versions/__init__.py +2 -0
  40. label_studio_sdk/prompts/versions/client.py +1046 -0
  41. label_studio_sdk/types/__init__.py +58 -0
  42. label_studio_sdk/types/comment.py +39 -0
  43. label_studio_sdk/types/comment_created_by.py +5 -0
  44. label_studio_sdk/types/inference_run.py +43 -0
  45. label_studio_sdk/types/inference_run_cost_estimate.py +57 -0
  46. label_studio_sdk/types/inference_run_created_by.py +5 -0
  47. label_studio_sdk/types/inference_run_organization.py +5 -0
  48. label_studio_sdk/types/inference_run_project_subset.py +5 -0
  49. label_studio_sdk/types/inference_run_status.py +7 -0
  50. label_studio_sdk/types/key_indicator_value.py +30 -0
  51. label_studio_sdk/types/key_indicators.py +7 -0
  52. label_studio_sdk/types/key_indicators_item.py +51 -0
  53. label_studio_sdk/types/key_indicators_item_additional_kpis_item.py +37 -0
  54. label_studio_sdk/types/key_indicators_item_extra_kpis_item.py +37 -0
  55. label_studio_sdk/types/model_provider_connection.py +71 -0
  56. label_studio_sdk/types/model_provider_connection_budget_reset_period.py +5 -0
  57. label_studio_sdk/types/model_provider_connection_created_by.py +5 -0
  58. label_studio_sdk/types/model_provider_connection_organization.py +5 -0
  59. label_studio_sdk/types/model_provider_connection_provider.py +5 -0
  60. label_studio_sdk/types/model_provider_connection_scope.py +5 -0
  61. label_studio_sdk/types/prompt.py +79 -0
  62. label_studio_sdk/types/prompt_created_by.py +5 -0
  63. label_studio_sdk/types/prompt_organization.py +5 -0
  64. label_studio_sdk/types/prompt_version.py +41 -0
  65. label_studio_sdk/types/prompt_version_created_by.py +5 -0
  66. label_studio_sdk/types/prompt_version_organization.py +5 -0
  67. label_studio_sdk/types/prompt_version_provider.py +5 -0
  68. label_studio_sdk/types/refined_prompt_response.py +64 -0
  69. label_studio_sdk/types/refined_prompt_response_refinement_status.py +7 -0
  70. label_studio_sdk/types/task.py +3 -2
  71. label_studio_sdk/types/task_comment_authors_item.py +5 -0
  72. label_studio_sdk/webhooks/client.py +245 -36
  73. label_studio_sdk/workspaces/client.py +20 -20
  74. label_studio_sdk-1.0.8.dist-info/LICENSE +201 -0
  75. {label_studio_sdk-1.0.5.dist-info → label_studio_sdk-1.0.8.dist-info}/METADATA +19 -3
  76. {label_studio_sdk-1.0.5.dist-info → label_studio_sdk-1.0.8.dist-info}/RECORD +77 -24
  77. {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
- ##### NEW API
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 generate_sample_annotation(self):
795
- """ """
796
- raise NotImplemented()
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
- Class for Region Tag
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()))
@@ -0,0 +1,2 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+