label-studio-sdk 1.0.7__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.

@@ -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 generate_sample_annotation(self):
828
- """ """
829
- 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
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
- 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()))