
    ]j                        d Z ddlZddlZddlZddlZddlZddlZddlmZ ddl	m
Z
mZmZmZmZmZmZ ddlmZ ddlmZmZ ddlmZ ddlZddlmZ dd	lmZmZmZ d
dlm Z  d
dl!m"Z"m#Z#m$Z$m%Z%m&Z& d
dl'm(Z( d
dl)m*Z* d
dl+m,Z,m-Z-m.Z.m/Z/ d
dl0m1Z2  ejf                  e4      Z5ejl                  jo                  ejl                  jq                  e9            Z:ejl                  jw                  e:dddd      Z< e=e<      5 Z> ej~                  e>      Z@ddd       h dZAdZBdhZCdZDd ZEd ZFd ZGd ZHd ZIdeJdeKd eeK   fd!ZL G d" d#      ZMy# 1 sw Y   ;xY w)$
    N)cached_property)DictOptionalListTupleAnyCallableUnion)	BaseModel)defaultdictOrderedDict)etree)JSF)LSConfigParseException&LabelStudioXMLSyntaxErrorSentryIgnored'LabelStudioValidationErrorSentryIgnored   )LabelStudioTag)ChatMessageTagReactCodeTag
ControlTag
ChoicesTag	LabelsTag)	ObjectTag)LabelTag)AnnotationValue	TaskValuePredictionValueRegioncreatez.._legacyschemazlabel_config_schema.json>   LabelChoiceRelationzlabel-studiovideorectangleresultc                    i }t        | j                               t        |j                               z  D ]M  }i }|| v r|j                  | |          ||v r(||   D ]   }|j                  |d      ||   |   z   ||<   " |||<   O |S )a&  
    Merge two dictionaries with nested dictionary values into a single dictionary.

    Args:
        dict1 (dict): The first dictionary to merge.
        dict2 (dict): The second dictionary to merge.

    Returns:
        dict: A new dictionary with the merged nested dictionaries.

    Example:
        dict1 = {'sentiment': {'Negative': 1, 'Positive': 1}}
        dict2 = {'sentiment': {'Positive': 2, 'Neutral': 1}}
        result_dict = merge_nested_dicts(dict1, dict2)
        # {'sentiment': {'Negative': 1, 'Positive': 3, 'Neutral': 1}}
    r   )setkeysupdateget)dict1dict2result_dictkeyvaluesubkeys         T/root/env/lib/python3.12/site-packages/label_studio_sdk/label_interface/interface.pymerge_labels_countersr6   <   s    " K 5::< 3uzz|#44 	!%<LLs$%<* J %		&! 4uSz&7I IfJ !C	!     c                    d| v rd| d   v r&t        | d   d   t              s| d   d   g| d   d<   nst        | d   t              r`t        d | d   D              rKt        t	        | d               D ]1  }t        | d   |   d   t              r| d   |   d   g| d   |   d<   3 d| v rEt        | d   t
              rt        | d         | d<   | S | d   D cg c]  }t        |       c}| d<   | S c c}w )zb
    workaround for single choice
    https://github.com/heartexlabs/label-studio/issues/1259
    Choicesr&   c              3   $   K   | ]  }d |v  
 yw)r&   N ).0tag_choicess     r5   	<genexpr>z_fix_choices.<locals>.<genexpr>j   s      9
(3H#9
s   View)
isinstancelistallrangelenr   _fix_choices)confignviews      r5   rE   rE   ^   s2   
 Fvi((9h'2
 ,2)+<X+F*GF9h'y)40S 9
7=i7H9
 6
 3vi012 V!&"3A"6x"@$G6<Y6G6J86T5UF9%a(2V fVnk2)&.9F6N M >DF^LTl40LF6NM Ms   C0c                     t        |t              rdj                  |      }dj                  | ||j                         g      S )N,|)r@   rA   joinlower)	from_nameto_nametypes      r5   get_annotation_tuplerQ   y   s6    '4 ((7#88Y677r7   c           	          t        |       }g }|j                         D ]'  \  }}|j                  t        ||d   |d                ) |S )NrO   rP   )parse_configitemsappendrQ   label_configoutputsoutcontrol_nameinfos        r5   get_all_control_tag_tuplesr\      sP    <(G
C%mmo Vd

'd9otF|TUVJr7   c                     t        |       }g }|j                         D ]'  \  }}|j                  |d   j                                ) |S )z)
    Get all types from label_config
    rP   )rS   rT   rU   rM   rV   s        r5   get_all_typesr^      sK     <(G
C%mmo )d

4<%%'()Jr7   countrP   returnc                 ,    | sy|  d| | dkD  rd S d S )zgHelper for displaying pluralized sources of validation errors,
    eg "1 draft" or "3 annotations"
    N r   s r;   )r_   rP   s     r5   display_countre      s1     WAdV519C566"566r7   c                      e Zd ZdZedMd       Zed        ZdNdefdZde	ee
ee	ee   ee	   f   f   dee   fd	Zed
        Zed        Zed        Zed        Zde	de	de	de	fdZd Zd ZdNdZdNdZdNdZdefdZ	 dOdee   dee   defdZed        Zed        Zed        Z d Z!d Z"d ede#e	e	e	e$jJ                  f   fd!Z&ed"        Z'd# Z(d$ Z)d% Z*d& Z+ed'        Z,d( Z-ed)        Z.dPdQd*Z/dPde
e0ee   f   fd+Z1dee   fd,Z2d- Z3dPd.Z4dRde#e0ee   f   fd/Z5d0 Z6dSd1Z7dTde#e0ee   f   fd2Z8dUd3Z9dPd4Z:dVd5Z;d6 Z<dee=   fd7Z>dee=   fd8Z?dPd9e0dee=   fd:Z@d; ZA	 dVd<ZBed=        ZCed>        ZDd? ZE	 	 dOd@e
ee#f   dAe
ee#f   dBee   dCee   de#eeef   f
dDZFdE ZGdF ZHdG ZIdH ZJdNdIZKdPdJZLdK ZMdL ZNy)WLabelInterfaceaY  The LabelInterface class serves as an interface to parse and
    validate labeling configurations, annotations, and predictions
    within the Label Studio ecosystem.

    It is designed to be compatible at the data structure level with
    an existing parser widely used within the Label Studio ecosystem.
    This ensures that it works seamlessly with most of the existing functions,
    either by directly supporting them or by offering re-implemented versions
    through the new interface.

    Moreover, the parser adds value by offering functionality to
    validate predictions and annotations against the specified
    labeling configuration. Below is a simple example of how to use
    the new API:

    ```python
    from label_studio_sdk.label_interface import LabelInterface

    config = "<View><Text name='txt' value='$val' /><Choices name='chc' toName='txt'><Choice value='one'/> <Choice value='two'/></Choices></View>"

    li = LabelInterface(config)
    region = li.get_tag("chc").label("one")

    # returns a JSON representing a Label Studio region
    region.as_json()

    # returns True
    li.validate_prediction({
      "model_version": "0.0.1",
      "score": 0.90,
      "result": [{
          "from_name": "chc",
          "to_name": "txt",
          "type": "choices",
          "value": { "choices": ["one"] }
      }]
    })
    ```
    Nc                 P   t        j                  ||      }t        |t              rdd|ii ff|z   }t        |t              st        |t              rg }	|D ]  }
|
\  }}}|j                  dd      }t        |t              r+||v r'dd|j                  |      ii f}|	j                  |       t        |t              r-||v r)dd|j                  |      i|
ff}|	j                  |       |	j                  |
        |	}t        j                  | }t        j                  ||      S )	z Simple way of create UI config, it helps you not to thing much about the name/toName mapping

        LabelInterface.create_simple({
          "txt": "Text",
          "chc": choices("positive", "negative")
        })
        )mappingHeaderr3   nameNr?   style)pretty)	CEconvert_tags_descriptionr@   strdictr.   rU   tree_from_tuplestree_to_string)clstagsri   titlerl   rm   argskwargstuples
new_tuplesttag
attributeschildrenrk   	title_tag
parent_tagtrees                     r5   r"   zLabelInterface.create   s*    ,,T7CeS!7E!3R8:VCF eT"j&=J ),-)Z!~~fd3 eT*tu}!)Weiio+G LI%%i0 eT*tu}"(GUYYt_*F!MJ%%j1%%a()"  F""F+  f55r7   c                 :     | j                   |i |} | dd|i|S )a  Create instance is a shortcut to create a config and then
        parse it right away returning the LabelInterface object

        ```
        li = LabelInterface.create_instance({ "txt": "Text", "lbl": labels(("person", "org")) })
        lbl = li.get_control("lbl")
        reg = lbl.label("person", start=0, end=10)
        ```
        
        The above returns a region that could be serialized to Label
        Studio JSON format and uploaded to Label Studio

        rF   r;   r!   )rt   rw   rx   rF   s       r5   create_instancezLabelInterface.create_instance   s,     T,V,+&+F++r7   rF   c                    d| _         || _        || _        t        j	                  |      \  }}}|| _        || _        || _        | j                  |      \  }}	}
}| j                  ||	|
      }t        |j                               | _        t        |	j                               | _        || _        |	| _        |
| _        || _        y)a>  
        Initialize a LabelInterface instance using a config string.

        Args:
          config (str): Configuration string.
          tags_mapping: Provide your own implementation of any tag, this is helpful in cases where you want to override one of the control tags, and have your custom .label() method implemented.

        The configuration string should be formatted as follows:

        ```
        <View>
          <Choices name="sentiment" toName="txt">
            <Choice value="Positive" />
            <Choice value="Negative" />
            <Choice value="Neutral" />
          </Choices>
          <Text name="txt" value="$text" />
        </View>
        ```
        This method will extract the predefined task from the configuration and 
        parse the controls, objects, and labels used in it.
        FN)task_loaded_config_tags_mappingrg   get_task_from_labeling_config_sample_config_task_sample_config_ann_sample_config_predparse_link_controlsr+   r,   _control_tags_object_tags	_controls_objects_labels_tree)selfrF   tags_mappingrw   rx   
_task_data_ann_predcontrolsobjectslabelsr   s               r5   __init__zLabelInterface.__init__  s    . !) #1"N"Nv"V
D%#- "&#( *.**V*<''64&&x&A !1/ "
r7   datar`   c           	         g }|j                         D ]  \  }}|t        j                  d| d       "|| j                  vrt        j	                  d| d       J| j                  |   }t        |t        t        t        f      rd|i}n7t        |t              r't        |      dkD  rt        |d   t              rd|i}n	 t        |t              r|g}|D ]#  }|j                   |j                  di |       %  |S )a  
        Takes raw data representation and maps keys to control tag names.
        If name is not found, it will be skipped

        Args:
            data (Dict): Raw data representation. Example: {"choices_name": "Positive", "labels_name": [{"start": 0, "end": 10, "label": "person"}]}
            raise_if_control_not_found (bool): Raise an exception if control tag is not found.
        zPayload for control tag 'z' is None: it can be ok if this payload is autogenerated by LLMs - try to adjust the prompt to generate valid payloads. Otherwise, it can signify an errorzControl tag 'z' not found in the configlabelr   r;   )rT   loggerwarningr   r[   r@   rp   intfloatrA   rD   r   rU   r   )r   r   regionscontrol_tag_namepayloadcontrolitems          r5   create_regionszLabelInterface.create_regions5  s    )-  	6%g/0@/A B9 9:
 t~~5m,<+==VWXnn%56G
 'Ce#45"G,GT*w<!#!'!*c2#*G"4'4(") 6}w}}4t456? 	6D r7   c                     | j                   S )z$Returns the XML configuration string)r   r   s    r5   rF   zLabelInterface.configc  s     ||r7   c                 R    | j                   xr | j                   j                         S )zReturns list of control tags)r   valuesr   s    r5   r   zLabelInterface.controlsh  s      ~~9$.."7"7"99r7   c                 R    | j                   xr | j                   j                         S )zReturns list of object tags)r   r   r   s    r5   r   zLabelInterface.objectsm  s      }}7!5!5!77r7   c                 R    | j                   xr | j                   j                         S )zReturns list of label tags)r   r   r   s    r5   r   zLabelInterface.labelsr  s      ||5 3 3 55r7   r   r   r   c                    |j                         D ]s  \  }}g }|j                  D ]  }||vr|j                  ||           |j                  |       |j	                  t        ||                |j                  ||          u |S rb   )rT   rO   rU   set_objects
set_labelsrA   set_labels_attrs)r   r   r   r   rk   r|   inputsobject_tag_names           r5   r   zLabelInterface._link_controlsw  s    !) 	/ID#F#&;; 8"'1
 go678 OOF#NN4t-.  .	/  r7   c                     |(||vrt        d| d|j                                ||   S |r't        |j                               dkD  rt        d      t        |j	                               d   S )rb   zName z  is not found, available names: r   z7Multiple object tags connected, you should specify namer   )	Exceptionr,   rD   rA   r   )r   rk   	tag_stores      r5   _get_tagzLabelInterface._get_tag  s}    9$D6!A)..BRAST  !&Y^^-.2UVVI$$&'**r7   c                     || j                   v r| j                   |   S || j                  v r| j                  |   S t        d| d      )ay  Method to retrieve the tag object by its name from the current instance.

        The method checks if the tag with the provided name exists in
        either `_controls` or `_objects` attributes of the current
        instance.  If a match is found, it returns the tag. If the tag
        is not found an exception is raised.

        Args:
            name (str): Name of the tag to be retrieved.

        Returns:
            object: The tag object if it exists in either `_controls` or `_objects`.

        Raises:
            Exception: If the tag with the given name does not exist in both `_controls` and `_objects`.

        zTag with name z
 not found)r   r   r   r   rk   s     r5   get_tagzLabelInterface.get_tag  sN    $ 4>>!>>$''4== ==&&.j9::r7   c                 :    | j                  || j                        S )aP  Retrieves the object with the given name from `_objects`.

        This utilizes the `_get_tag` method to obtain the named object.

        Args:
            name (str, optional): The name of the object to be retrieved from `_objects`.

        Returns: object: The corresponding object if it exists in
            `_objects`.

        )r   r   r   s     r5   
get_objectzLabelInterface.get_object  s     }}T4==11r7   c                 $    | j                  |      S )z/Provides an alias for the `get_control` method.)get_controlr   s     r5   
get_outputzLabelInterface.get_output  s    %%r7   c                 :    | j                  || j                        S )a>  Retrieves the control tag that the control tag maps to.

        This uses the `_get_tag` method to obtain the named control.

        Args:
            name (str, optional): The name of the control to be retrieved.

        Returns: object: The corresponding control if it exists in
            `_controls`.

        )r   r   r   s     r5   r   zLabelInterface.get_control  s     }}T4>>22r7   c           	          t        | j                        t        | j                        z   }t        |t               s|gn|}|D cg c]  }|D ]  }t        ||      s|  c}}S c c}}w )a  Finds tags by their class type.

        The function looks into both `self.objects` and
        `self.controls` to find tags that are instances of the
        provided class(es)

        Args:
            tag_class (class or list of classes): The class type(s) of the tags to be found.

        Returns:
            list: A list of tags that are instances of the provided `tag_class`(es).

        )rA   r   r   r@   )r   	tag_classlsttag_classesr|   rt   s         r5   find_tags_by_classz!LabelInterface.find_tags_by_class  s[     4<< 4#66)3It)Dyk)"RkRsZS=QRRRRs   A'A'tag_typematch_fnc                    | j                   | j                  | j                   | j                  d}|j                  |t        | j                         t        | j                        z         }|t        t	        ||            }|S )aa  Finds tags that match the given function in the entire parsed tree.

        This function searches through both `objects` and `controls`
        based on `tag_type`, and applies the `match_fn` (if provided)
        to filter matching tags.

        Args:
            tag_type (str, optional): The type of tags to be
                searched. Categories include 'objects', 'controls',
                'inputs' (alias for 'objects'), 'outputs' (alias for
                'controls'). If not specified, searches both 'objects'
                and 'controls'.
            match_fn (Callable, optional): A function that takes a tag
                as an input and returns a boolean value indicating
                whether the tag matches the required condition.

        Returns: list: A list of tags that match the given type and
        satisfy `match_fn`.

        )r   r   r   rX   )r   r   r.   rA   filter)r   r   r   	tag_typesr   s        r5   	find_tagszLabelInterface.find_tags  sl    0 ||ll}}
	 mmHd4<<&84;N&NOvh,-C
r7   c                 (    | j                  dd       S )Nr   c                 :    | j                   j                         dv S )N)r   hypertextlabelsr|   rM   r{   s    r5   <lambda>z)LabelInterface.ner_tags.<locals>.<lambda>  s    AEEKKMEb4b r7   r   r   s    r5   ner_tagszLabelInterface.ner_tags  s    ~~j*bccr7   c                 (    | j                  dd       S )Nr   c                 <    | j                   j                         dk(  S )Nimager   r   s    r5   r   z+LabelInterface.image_tags.<locals>.<lambda>  s    155;;=G3K r7   r   r   s    r5   
image_tagszLabelInterface.image_tags  s    ~~i)KLLr7   c                 (    | j                  dd       S )Nr   c                 <    | j                   j                         dk(  S )Npdfr   r   s    r5   r   z)LabelInterface.pdf_tags.<locals>.<lambda>  s    155;;=E3I r7   r   r   s    r5   pdf_tagszLabelInterface.pdf_tags  s    ~~i)IJJr7   c                     t        j                  |       }d|_        |j                  D ]>  }|j                  s|j
                  |v s|j                  |j
                        |_        @ |S )a  Loads a task and substitutes the value in each object tag
        with actual data from the task, returning a copy of the
        LabelConfig object.

        If the `value` field in an object tag is designed to take
        variable input (i.e., `value_is_variable` is True), the
        function replaces this value with the corresponding value from
        the task dictionary.

        Args:
            task (dict): Dictionary representing the task, where
            each key-value pair denotes an attribute-value of the
            task.

        Returns:
            LabelInterface: A deep copy of the current LabelIntreface
            instance with the object tags' value fields populated with
            data from the task.

        T)copydeepcopyr   r   value_is_variable
value_namer.   r3   )r   taskr   objs       r5   	load_taskzLabelInterface.load_task  s\    * }}T"<< 	5C$$4)? HHS^^4		5 r7   c                 
   | j                   j                         D cg c]  \  }}|j                  r| }}}d| j                   j                         D ci c]  \  }}||j                          c}}|dS c c}}w c c}}w )z
        Converts the current LabelInterface instance into a JSON Schema.

        Returns:
            dict: A dictionary representing the JSON Schema.
        object)rP   
propertiesrequired)r   rT   is_output_requiredto_json_schema)r   rk   r   required_outputss       r5   r   zLabelInterface.to_json_schema8  s     '+nn&:&:&<
"T7)) 
 

 DHNNDXDXDZ3@4g,,.. )
 	
	
s   A9A?config_stringc                 2   	 t        j                  |      }i i t        t              }}}g }t        t        d}|j                         D ]  }	|	j                  r,d|	j                  v r|j                  |	j                  d          t        j                  |	      r2t        j                  |	| j                        ||	j                  d   <   t!        j                  |	      r2t!        j                  |	| j                        ||	j                  d   <   |	j                  j#                  d      r|	j$                  j'                         |v rt!        |	j$                  t        |	j                        |	j                  j#                  d      |	j                  j#                  d|	j                  j#                  d                  ||	j                  d   <   t)        j                  |	      st)        j                  |	|      }
|
s|
||
j*                     |
j,                  <    i ||}|j/                         D ]  \  }}t1        |d	d
      j'                         }||vr&||vr||   } |||g||d      ||<   ||vsFt!        |j$                  t        |j2                        ||j2                  j#                  d|j2                  j#                  d                  ||<    ||||fS # t         j                  $ r}t        t	        |            d}~ww xY w)a  Parses the received configuration string into dictionaries
        of ControlTags, ObjectTags, and Labels, along with an XML tree
        of the configuration.

        Args:
            config_string (str): the configuration string to be parsed.

        Returns:
            Tuple of:
            - Dictionary where keys are control tag names and values are ControlTag instances.
            - Dictionary where keys are object tag names and values are ObjectTag instances.
            - Dictionary of dictionaries where primary keys are label parent names
              and secondary keys are label values and values are LabelTag instances.
            - An XML tree of the configuration.
        N)chat	reactcode	indexFlag)r   rk   	valueListr3   )r|   attrrk   r3   r|   rd   )rk   toName)rk   rO   r   )r   
fromstringXMLSyntaxErrorr   rp   r   rq   r   r   iterattribrU   r   validate_node
parse_noder   r   r.   r|   rM   r   parent_namer3   rT   getattrr   )r   r   xml_treeer   r   r   	variables_SELF_REFERENCING_TAGSr|   lb
all_parsedrk   
parsed_tag	tag_lowercontrol_classs                   r5   r   zLabelInterface.parseK  s    	A''6H %'K,=6	 #%"

 ==? 	:CzzkSZZ7  K!89'',/9/D/DSW[WiWi/jF+,((-.7.B.B3UYUgUg.h

6*+'CGGMMO?U,U /8cjj)/**..cjjnnW6MN	/

6*+ '',((h7 79F2>>*28845	:> -,8,
 * 0 0 2 	D*
E26<<>I 668# 6y A!.!F"&$7"
 7" )"joo.$//--k:??;N;Nw;WX	!	& &(22K ## 	A8Q@@	As   K* *L=LLc                     	 t        j                  |      }|t        j                  d      t        j
                  j                  |      }t        |      }|S # t        $ r t        j                  d      w xY w)rb   zcan only parse stringszxml is empty or incorrect)r   r   	TypeError
ParseErrorxmljson
badgerfishr   rE   )rt   r   xmlrF   s       r5   parse_config_to_jsonz#LabelInterface.parse_config_to_json  sx    	=""=1C ;""#>??##((-f%  	=""#;<<	=s   A A9c           	      *   	 t         j                  |      }t        j                  |t               y# t
        j                  t        f$ r}t        t        |            d}~wt        j                  j                  $ r}t        |j                        r|j                  d   j                  n|j                  }dj                  dj!                  t#        t        |j$                              |j'                  dd            }t        |      d}~ww xY w)rb   NzValidation failed on {}: {}/@rd   )rg   r  
jsonschemavalidate_LABEL_CONFIG_SCHEMA_DATAr   r	  
ValueErrorr   rp   
exceptionsValidationErrorrD   contextmessageformatrL   mappathreplace)r   r   rF   excerror_messages        r5   _schema_validationz!LabelInterface._schema_validation  s    
	I#88GF(AB  *- 	D9#c(CC$$44 	I7:3;;7GCKKO33S[[M9@@S#((+,m.C.CC.LM :-HH	Is"   /2 DA D?BDDc           
          t        j                  d|      }t        |      }t        j                  d|      }|D ]6  }|j                  d      D ]   }||vst	        d| dt        |              8 y)rb   zname="([^"]*)"ztoName="([^"]*)"rJ   ztoName="z" not found in names: N)refindallr+   splitr   sorted)r   r   	all_namesnamestoNamestoName_r   s          r5   _to_name_validationz"LabelInterface._to_name_validation  s     JJ0-@	I**0-@ 	G!--, &A"6(*@P 	r7   c                     t        j                  d|      }t        t        |            t        |      k7  rt	        ddj                  |      z         y)rb   z(?:^|[^\w])name="([^"]*)"z(Label config contains non-unique names: , N)r"  r#  rD   r+   r   rL   )r   r   r&  s      r5   _unique_names_validationz'LabelInterface._unique_names_validation  sM     JJ;]K	s9~#i.09:TYYy=QQ  1r7   c                     g }| j                   rK| j                   j                         D ].  }t        |d      s|j                  |j	                                0 |rt        dj                  |            y)zCValidate tag-specific attribute values (e.g. Video playback speed).validate_configr   N)r   r   hasattrextendr/  r   rL   )r   errorsr   s      r5   _tag_attribute_validationz(LabelInterface._tag_attribute_validation  sh    ==}}++- 93 12MM#"5"5"789 9$))F:KLL r7   c                 D    	 | j                          y# t        $ r Y yw xY w)rb   TF)r  r   r   s    r5   is_validzLabelInterface.is_valid  s%    	MMO6 		s    	c                     | j                   }| j                  |       | j                  |       | j                  |       | j	                          y)a  Validates the provided configuration string against various validation criteria.

        This method applies a series of validation checks to
        `_config`, including schema validation, checking for
        uniqueness of names used in the configuration, and the
        "to_name" validation. It throws exceptions if any of these
        validations fail.

        Raises:
            Exception: If any validation fails, specific to the type of validation.

        N)r   r   r-  r*  r3  )r   r   s     r5   r  zLabelInterface.validate  sC     .%%m4  /&&(r7   c                     t               r   NotImplemented)rt   rF   s     r5   validate_with_dataz!LabelInterface.validate_with_data   s     r7   c                     | j                   D ]0  }|j                  s|d   j                  |j                  d      0 y d|v r| j	                         syd|v r| j                         syy)rb   r   NFannotationspredictionsT)r   r   r.   r   validate_annotationvalidate_prediction)r   r   validate_regions_onlyr   s       r5   validate_taskzLabelInterface.validate_task  sn     << 	C$$f)9)9#..$)O)W	 D )A)A)CD )A)A)Cr7   c                 H    | j                  |      }|r|S t        |      dk(  S )a  
        Validates an object (annotation/prediction) and returns boolean or error messages.

        Args:
            obj (dict): The object to validate
            return_errors (bool): If True, returns list of error messages. If False, returns boolean.

        Returns:
            Union[bool, List[str]]: If return_errors=False, returns True/False.
                                   If return_errors=True, returns list of error messages.
        r   )_validate_object_logicrD   )r   r   return_errorsr2  s       r5   _validate_objectzLabelInterface._validate_object  s+     ,,S1Mv;!##r7   c           	         g }	 t         |vr|j                  dt          d       |S |j                  t               }t        |t              s|j                  dt          d       |S d|v r4|d   }|-	 t        |      }d|cxk  rdk  sn |j                  d|        g }g }t        |      D ]  \  }}	t        |	t              s!|j                  d
t        |	       d|	        7|	j                  d      dk7  r>| j                  |	d|||	d      }
|j                  |
       |
rw|j                  |	       |j                  ||	f        |D ].  \  }}| j                  ||d|      }|s|j                  |       0 	 |S # t        t        f$ r |j                  d	|        Y 	w xY w# t        $ r(}|j                  dt        |              Y d}~|S d}~ww xY w)z2Core validation logic that returns error messages.zMissing required field ''z' must be a listscoreNg        g      ?z3Score must be between 0.00 and 1.00 inclusive, got z"Score must be a valid number, got z!Region must be a dictionary. Got z: rP   relationT)r)   region)rD  region_indexr  )rD  relation_indexz$Unexpected error during validation: )
RESULT_KEYrU   r.   r@   rA   r   r  r  	enumeraterq   rP   validate_regionr1  validate_relationr   rp   )r   r   r2  r)   rH  score_floatr   relations_to_validateirJ  region_errorsrI  relation_errorr   s                 r5   rC  z%LabelInterface._validate_object_logic*  s   2	K$ 8AFGWWZ(Ffd+*-=>? #~G$T&+El #{ 9c 9"MM,_`k_l*mn G$&! 'v. >	6!&$/MM$Ed6l^SUV\U]"^_::f%3$($8$8d+1V D %9 %M MM-0(v. *00!V=>$  5 28!%!7!7'Y]no!7!p!MM.12 C '	2 T(J5'&RST<  	KMM@QIJJ	KsT   "F, ?F, 'F, 3,F BF, %AF, ,F, #F)%F, (F))F, ,	G5GGc                 $    | j                  |      S )aU  Validates the given annotation against the current configuration.

        This method applies the `validate_region` method to each
        region in the annotation and returns False if any of these
        validations fail. If all the regions pass the validation, it
        returns True.

        Args:
            annotation (dict): The annotation to be validated, where
            each key-value pair denotes an attribute-value of the
            annotation.

        Returns:
            bool: True if all regions in the annotation pass the
            validation, False otherwise.

        rE  )r   
annotations     r5   r>  z"LabelInterface.validate_annotatione  s    $ $$Z00r7   c                 &    | j                  ||      S )a  
        Validates the given prediction against the current configuration.

        Args:
            prediction (dict): The prediction to be validated
            return_errors (bool): If True, returns a list of error messages instead of boolean

        Returns:
            Union[bool, List[str]]: If return_errors=False, returns True/False.
                                   If return_errors=True, returns list of error messages.
        rW  )r   
predictionrD  s      r5   r?  z"LabelInterface.validate_predictiony  s     $$Z??r7   c                    g }g d}|D ]  }||vs|j                  d| d| d       ! |rd|fS 	 | j                  |d         }	 | j                  |d
         }	|j                  j                         }
|d   j                         }||
k7  r!|j                  d| d| d|
 d|d    d	       |d
   |j                  vr-|j                  d| d|d
    d|d    d|j                          	 |j                  |d   |      st        |dd      j                         }|dv rg }|d   }dD ]9  }||v s	 t        ||         }|dk  s|dkD  r|j                  | d||           ; |r1|j                  d| d|d    ddj                  |      z   dz          nm|d   }| j                  |      }|j                  d| d|d    d | d!|        n6|d   }| j                  |      }|j                  d| d|d    d | d!|        t        |      dk(  |fS # t        $ r)}|j                  d| d|d    d       d|fcY d	}~S d	}~ww xY w# t        $ r)}|j                  d| d|d
    d       d|fcY d	}~S d	}~ww xY w# t        $ r |j                  | d||           Y {w xY w# t        $ r0}|j                  d| d"|d    dt        |              Y d	}~d	}~ww xY w)#a  Helper method to perform region validation logic.

        Args:
            region (dict): The region to be validated.
            region_index (int): Index of the region for error reporting.
            context (dict, optional): Additional context forwarded to
                ``control.validate_value()``.

        Returns:
            tuple: (is_valid, errors) where is_valid is bool and errors is list of strings.
        )rN   rO   rP   r3   zRegion : Missing required field 'rG  FrN   z: 'from_name' 'z' not found in configurationNrO   z: 'to_name' 'rP   z: Type 'z ' does not match expected type 'z' for control 'z' is not valid for control 'z'. Valid options: r3   r  r|   rd   )	rectanglerectanglelabels)xywidthheightr   d   rb   z : Invalid geometry for control 'z': r,  z out of bounds [0, 100]z: Invalid value for control 'z'. Got: z. Valid options: z&: Error validating value for control ')rU   r   r   r   r|   rM   rO   validate_valuer   r   rL   _get_valid_values_for_controlrp   rD   )r   rJ  rK  r  r2  required_fieldsfieldr   r   r   expected_typeactual_typer  out_of_bounds_fieldsr3   vinvalid_valuevalid_valuess                     r5   _validate_region_logicz%LabelInterface._validate_region_logic  s3     D$ 	ZEF"~5OPUwVWXY	Z
 &= 	!&&vk':;G	!//&"34C  ))+Vn**,-'MMGL>+Ffgtfu  vE  FL  MX  FY  EZ  Z[  \  ] )GOO3MMGL>vi?P>QQmnt  vA  oB  nC  CU  V]  Ve  Ve  Uf  g  h"	z))&/7)K#GUB7==?	 @@+-("7OE!> W E>W$)%,$7#$q5AG$8$?$?5'5QV<.@Y$ZW ,%l^3STZ[fTgShhkl"ii(<=>78 )/w'+'I'I''R%l^3PQWXcQdPeemn{m|  }N  O[  N\  ] %+7OM#'#E#Eg#NLMM!,/LVT_M`Laaijwix  yJ  KW  JX  Y 6{a''u  	!MMGL>AT@UUqrs&= 	!  	!MMGL>vi?P>QQmno&= 	!8 $- W 4 ; ;ugQuU|n<U VW(  	zMMGL>1WX^_jXkWllopstupvowxyy	zsy   H I -AJ+ 51J&B"J+ 	I
!I?I
I
	I?I:4I?:I?"J($J+ 'J((J+ +	K$4&KK$c                     	 t        |d      r|j                  r|j                   S t        |d      rd|j                  j                   S y# t        $ r Y yw xY w)zDGet valid values for a control tag to provide better error messages.r   _value_classzexpected structure: zno specific validation ruleszunknown validation rules)r0  r   rq  __name__r   r   r   s     r5   rf  z,LabelInterface._get_valid_values_for_control  s]    
	.w)gnn!..)*.1-g.B.B.K.K-LMM5 	.-	.s   $A $A 	AAc                 <    | j                  |||      \  }}|r|S |S )a  Validates a region from the annotation against the current
        configuration.

        The validation checks the following:
        - Both control and object items are present in the labeling configuration.
        - The type of the region matches the control tag name.
        - The 'to_name' in the region data connects to the same tag as in the configuration.
        - The actual value for example in <Labels /> tag is producing start, end, and labels.

        Args:
            region (dict): The region to be validated.
            return_errors (bool): If True, returns a list of error messages instead of boolean
            region_index (int): Index of the region for error reporting (used when return_errors=True)
            context (dict, optional): Additional context passed through to
                ``control.validate_value()``.  May contain ``result`` (the
                full result list) and ``region`` (the current region dict)
                so that control tags can inspect sibling regions.

        Returns:
            Union[bool, List[str]]: If return_errors=False, returns True/False.
                                   If return_errors=True, returns list of error messages.
        r]  )ro  )r   rJ  rD  rK  r  r5  r2  s          r5   rO  zLabelInterface.validate_region  s.    .  66v|U\6]&MOr7   c           
         g }	 g d}|D ]  }||vs|j                  d| d| d       ! |j                  d      dk7  r'|j                  d| d|j                  d       d       d}|j                  d	      |vr*|j                  d| d
| d|j                  d	       d       |D ci c]  }d|v s|d   | }	}|j                  d      }
|
|	vr|j                  d| d|
 d       |j                  d      }||	vr|j                  d| d| d       t	        |      dk(  |fS c c}w # t        $ r*}|j                  d| dt        |              Y d}~Cd}~ww xY w)ap  Helper method to perform relation validation logic.
        Args:
            relation (dict): The relation to validate
            regions (list): List of validated regions
            relation_index (int): Index of the relation for error reporting

        Returns:
            tuple: (is_valid, errors) where is_valid is bool and errors is list of strings.
        )rP   	directionfrom_idto_idz	Relation r\  rG  rP   rI  z : Type must be 'relation', got ')leftrightbirv  z: Direction must be one of z, got 'idrw  z: 'from_id' 'z' not found in regionsrx  z: 'to_id' 'z: Error validating relation - Nr   )rU   r.   r   rp   rD   )r   rI  r   rL  r2  rg  rh  valid_directionsrregion_mappingrw  rx  r   s                r5   _validate_relation_logicz'LabelInterface._validate_relation_logic
  s    	^GO( b(MMIn-==WX]W^^_"`ab
 ||F#z1	.)99YZbZfZfgmZnYoopqr  7||K(0@@	.)99TUeTffmnvnznz  |G  oH  nI  IJ  K  L 3:GQTQYagqjGNG ll9-Gn,	.)9wiOefg LL)EN*	.)9UGKabc
 6{a'' H  	^MMIn%55STWXYTZS[\]]	^s6   D- BD- *	D(4D(<AD- (D- -	E 6 EE c                 :    | j                  |||      \  }}|r|S |S )aR  Validates that the relation is correct and all the associated objects are provided

        Args:
            relation (dict): The relation to validate
            regions (list): List of validated regions
            return_errors (bool): If True, returns error message string instead of boolean
            relation_index (int): Index of the relation for error reporting (used when return_errors=True)

        Returns:
            Union[bool, str]: If return_errors=False, returns True/False.
                             If return_errors=True, returns error message string or None.
        )r  )r   rI  r   rD  rL  r5  r2  s          r5   rP  z LabelInterface.validate_relation8  s*      887N[&MOr7   c                     | j                  d|      }| j                  |j                  | j                         || j                  | j                  fS )rb   editor_previewmodesecure_mode)generate_sample_taskr   r-   r   r   )r   r  generated_tasks      r5   _sample_taskzLabelInterface._sample_taskN  sY     22!{ 3 
 ##/!!$":":;t668P8PPPr7   c                 z    | j                   D ci c]   }|j                  |j                  ||      " }}|S c c}w )aw  Generates a sample task based on the provided mode and
        secure_mode.

        This function generates an example value for each object in
        `self.objects` using the specified `mode` and
        `secure_mode`. The resulting task is a dictionary where each
        key-value pair denotes an object's value-name and example
        value.

        Args:
            mode (str, optional): The operation mode. Accepts any string but defaults to 'upload'.
            secure_mode (bool, optional): The security mode. Defaults to False.

        Returns:
            dict: A dictionary representing the sample task.

        r  )r   r   generate_example_value)r   r  r  r   r   s        r5   r  z#LabelInterface.generate_sample_taskZ  sS    , ||	
  NNC66{ 7  
 
 
s   %8c           
          | j                  | j                  D ci c]4  }|j                  t        |j	                               j                         6 c}      S c c}w )zR Generate an example of each control tag's JSON schema and validate it as a region)r   r   rk   r   r   generaters  s     r5   _generate_sample_regionsz'LabelInterface._generate_sample_regionsu  sT    ""==$
 LL#g4467@@BB$
  	 $
s   9Ac                     t        d| j                               }|j                         }| j                  |      r|S t        j                  d| d| j                          y)aj  Generates a sample prediction that is valid for this label config.

        Example:
            {'model_version': 'sample model version',
             'score': 0.0,
             'result': [{'id': 'e7bd76e6-4e88-4eb3-b433-55e03661bf5d',
               'from_name': 'sentiment',
               'to_name': 'text',
               'type': 'choices',
               'value': {'choices': ['Neutral']}}]}

        NOTE: `id` field in result is not required when importing predictions; it will be generated automatically.
        NOTE: for each control tag, depends on tag.to_json_schema() being implemented correctly
        zsample model version)model_versionr)   zSample prediction $ failed validation for label config N)r   r  
model_dumpr?  r   debugrF   )r   rZ  prediction_dcts      r5   generate_sample_predictionz)LabelInterface.generate_sample_prediction|  sh     %0002

 $..0##N3!!LL-n-==abfbmbmanopr7   c                     t        d| j                               }|j                         }| j                  |      r|S t        j                  d| d| j                          y)a  Generates a sample annotation that is valid for this label config.

        Example:
            {'was_cancelled': False,
             'ground_truth': False,
             'lead_time': 0.0,
             'result_count': 0,
             'completed_by': -1,
             'result': [{'id': 'b05da11d-3ffc-4657-8b8d-f5bc37cd59ac',
               'from_name': 'sentiment',
               'to_name': 'text',
               'type': 'choices',
               'value': {'choices': ['Negative']}}]}

        NOTE: `id` field in result is not required when importing predictions; it will be generated automatically.
        NOTE: for each control tag, depends on tag.to_json_schema() being implemented correctly
        r  )completed_byr)   zSample annotation r  N)r   r  r  r>  r   r  rF   )r   rX  annotation_dcts      r5   generate_sample_annotationz)LabelInterface.generate_sample_annotation  sh    $ %002

 $..0##N3!!LL-n-==abfbmbmanopr7   raise_on_failurec                     | j                         }|s|rt        d      y| j                         }|s|rt        d      | j                         }|s|rt        d      ||r|gng |r|gdS g dS )a  Generate a complete sample task with annotations and predictions.

        This method combines the generation of a sample task, sample prediction, and sample annotation
        into a single method call, returning a complete task structure.

        Args:
            raise_on_failure: If True, will raise ValueError when any step
                              (including annotation/prediction generation) fails

        Raises:
            ValueError: If raise_on_failure is True and any generation step fails.

        Example:
            {
              'data': {'text': 'Sample text for labeling'},
              'annotations': [
                {'was_cancelled': False,
                 'ground_truth': False,
                 'completed_by': -1,
                 'result': [
                   {'id': 'b05da11d-3ffc-4657-8b8d-f5bc37cd59ac',
                    'from_name': 'sentiment',
                    'to_name': 'text',
                    'type': 'choices',
                    'value': {'choices': ['Negative']}}
                 ]
                }
              ],
              'predictions': [
                {'model_version': 'sample model version',
                 'score': 0.95,
                 'result': [
                   {'id': 'e7bd76e6-4e88-4eb3-b433-55e03661bf5d',
                    'from_name': 'sentiment',
                    'to_name': 'text',
                    'type': 'choices',
                    'value': {'choices': ['Neutral']}}
                 ]
                }
              ]
            }

        NOTE: `id` field in result is not required when importing predictions; it will be generated automatically.
        NOTE: for each control tag, depends on tag.to_json_schema() being implemented correctly
        zJLabelInterface.generate_sample_task failed to generate a valid sample taskNzOLabelInterface.generate_sample_prediction failed to generate a valid predictionzOLabelInterface.generate_sample_annotation failed to generate a valid annotation)r   r<  r=  )r  r  r  r  )r   r  sample_tasksample_predictionsample_annotations        r5   generate_complete_sample_taskz,LabelInterface.generate_complete_sample_task  s    \ //1 !mnn ;;= %5noo ;;= %5noo  2C-.2C-.
 	
 JL
 	
r7   c                 j   t        |      }|j                  j                         D ]  \  }}|| j                  vr y| j                  |   }|j                  |j                  k7  r y|j                  |j                  k7  r yt        |j                        j                  |j                        r y y)z/Detect essential changes of the labeling config)rF   TF)rg   r   rT   r|   r   r+   r   issubset)r   new_config_strnew_objnew_tag_namenew_tagold_tags         r5   !config_essential_data_has_changedz0LabelInterface.config_essential_data_has_changed  s     7%,%6%6%<%<%> 	!L'4>>1nn\2G{{gkk)'//1w~~&//?	 r7   c                     t               r   r8  )rW   r  r  s      r5   "generate_sample_task_without_checkz1LabelInterface.generate_sample_task_without_check  s     r7   c                    i dd}}}|j                  d      }|dk\  r|n|j                  d      }|dz  }|dk\  r||d j                  d      nd}d|cxk  r||z   k  rNn nK	 t        j                  ||||z          }d	|v xs d
|v }d|v r|d   n|rdn|}d	|v r|d	   nd}d
|v r|d
   nd}|||fS # t        $ r Y w xY w)zGet task, annotations and predictions from labeling config comment,
        it must start from "<!-- {" and end as "} -->"
        Nz<!-- {r   z<!--{   z-->r     r=  r<  r   )findjsonloadsr   )	rt   rF   	task_datar<  r=  startendbodydont_use_roots	            r5   r   z,LabelInterface.get_task_from_labeling_config  s    /1$;	H%!W)=
,1QJfUVn!!%(Bu"us{"Uzz&"=> !. 5 N$9N ~ L"/$T 
 6Cd5Jd=1PT5Bd5Jd=1PT+{22  s   "B1 1	B=<B=c                 6   t        j                  |d      }|j                  d      }|D ]K  }|j                         }||j	                  |       t        j
                  |d      j                  d      }M |j                  dd      j                  d	d      S )
NF)
forbid_dtdz//comment()html)methodzutf-8r   rd   )r   r   xpath	getparentremovetostringdecoder  )r   cr   commentsps        r5   config_line_stippedz"LabelInterface.config_line_stipped6  s    e4::m, 	DAA}tF3::7CA		D yyr"**444r7   c                 d    t         j                  D cg c]  }|j                          c}S c c}w r   )r   r   as_tuple)rW   r|   s     r5   r\   z)LabelInterface.get_all_control_tag_tuplesC  s     *.--83888s   -control_typeobject_typename_filterto_name_filterc                    | j                   D ]a  }|j                  ||      s|j                  D ]<  }|j                  ||      s|j                  |j                  |j                  fc c S  c t        d| d| d      )a  
        Reads config and fetches the first control tag along with first object tag that matches the type.

        Args:
          control_type (str or tuple): The control type for checking tag matches.
          object_type (str or tuple): The object type for checking tag matches.
          name_filter (function, optional): If given, only tags with this name will be considered.
                                           Default is None.
          to_name_filter (function, optional): If given, only tags with this name will be considered.
                                              Default is None.

        Returns:
          tuple: (from_name, to_name, value), representing control tag, object tag and input value.
        )name_filter_fn)to_name_filter_fnzNo control tag of type z and object tag of type z found in label config)r   matchr   rk   r   r  )r   r  r  r  r  r|   
object_tags          r5   get_first_tag_occurencez&LabelInterface.get_first_tag_occurenceG  s    , == 	PCyykyB"%++ PJ!''~'V"xx*:O:OOOP	P %l^3KK=Xno
 	
r7   c                     | j                   D ci c]  }|j                  s|j                  d }}| j                  |fS c c}w )rb   T)r   dynamic_valuerk   r   )r   r  dynamic_valuess      r5   get_all_labelszLabelInterface.get_all_labelsg  s<    04Q1!&&$,QQ||^++ Rs
   A A c                 6    | j                   j                         S r   )r   r,   r   s    r5   get_all_object_tag_namesz'LabelInterface.get_all_object_tag_namesl  s    }}!!##r7   c                     | j                   S r   )r   r   s    r5   extract_data_typesz!LabelInterface.extract_data_typesp  s    }}r7   c                 B    d }| j                  |      }t        |      S )rb   c                 B    | j                   j                         t        v S N)r|   rM   _VIDEO_TRACKING_TAGS)r|   s    r5   r   z9LabelInterface.is_video_object_tracking.<locals>.<lambda>v  s    sww}}2FF r7   )r   )r   bool)r   r   ru   s      r5   is_video_object_trackingz'LabelInterface.is_video_object_trackingt  s!    F~~x~0Dzr7   c                     t         r   r8  )r   r   s     r5   is_typezLabelInterface.is_type{  s    r7   c                     | j                   sy|j                  }|j                  }|j                  }| j	                  |       | j                  ||       y)z0Validate current config using LS Project SummaryFN)r   created_labelscreated_labels_draftscreated_annotations validate_annotations_consistencyvalidate_lables_consistency)r   summarystrictr  r  annotations_summarys         r5   validate_config_using_summaryz,LabelInterface.validate_config_using_summary  sQ     }} // ' = =%99--.AB((9NOr7   c           	         t        ||      }|j                         D ]  \  }}| j                  |      }|r,|s*t        dt	        |j                         d       d| d      g }|j                         D ]9  \  }}|dkD  s|j                  j                  |d      r)|j                  |       ; t        |      st        ddj                  |       dt        |       d	       y)
rb   z
There are r   z! annotation(s) created with tag "z", you can't remove itNz3These labels still exist in annotations or drafts:
rJ   z$Please add labels to tag with name="z".)r6   rT   r   r   sumr   labels_attrsr.   rU   rD   rL   rp   )	r   r  r  control_tag_from_datalabels_from_datacontrol_from_configremoved_labels
label_namelabel_values	            r5   r  z*LabelInterface.validate_lables_consistency  s   
 /~?TU
 8F7K7K7M "	3!#3"&"2"23H"I(;= %5%<%<%>!B C D-..EG 
  N+;+A+A+C 6'
K?+>+K+K+O+O,
 #))*56$ >"=J388TbKcJd:3?T;U:VVXZ ?"	r7   c                    g }t        |      }|D ]j  }|j                  d      \  }}}|j                         dk(  r,	 | j                  |      }|r|j	                  |      s|j                  d| d| d|        l |rd	j                  |      }
t        d
|
       y# t        $ r0}	|j                  d| d| d| dt        |	              Y d}	~	d}	~	ww xY w)rb   rK   textareazwith from_name=z
, to_name=z, type=z*Error occurred while processing from_name=z	, error: Nr   zNCreated annotations are incompatible with provided labeling schema, we found:
)
r+   r$  rM   r   r   rU   r   rp   rL   r   )r   r  errannotations_from_dataannrN   rO   r   r   exdiff_strs              r5   r  z/LabelInterface.validate_annotations_consistency  s     #$7 8( 	C+.99S>(Iw ~~:-	**95g&8&8&AJJ))JwiwxjY	, yy~H9abjakl    

@:V]U^^efneooxy|}  zA  yB  C s   >B	C(&CC)NNNTr  )NN)F)r   r   )r   N)Fr   N)r   )Fr   )uploadF)Orr  
__module____qualname____doc__classmethodr"   r   rp   r   r   r   r   r    r   propertyrF   r   r   r   r   r   r   r   r   r   r   r   r
   r   r   r   r   r   r   r   r   r   _Elementr   r  r   r*  r-  r3  r5  r  r:  rA  r  rE  rC  r>  r?  ro  rf  rO  r  rP  r  r  r  rq   r  r  r  r  r  r   r  r\   r  r  r  r  r  r  r  r  r  r;   r7   r5   rg   rg      s   &P &6 &6R , ,"-s -`,4U3d3id3S-T(T#U ,Z^_eZf ,\   : : 8 8 6 6t d D T (+;42&3St S( NR$ $8@8J$	$L d d M M K K<
&W33 W35tT5>>1Q+R W3r  IM  )(  &$E$S	/<R $$8T#Y 8v1(@U(eTXZ^_bZcTcNd U(n.<,(uUY[_`c[dUdOe ,(\,
Q6HTN 4HTN :@
d @
xX\~ @
T( 27 3 3> 
5 
59 +/-1
CJ'
 3:&
 h'	

 !*
 
sC}	
@,
$P,\$r7   rg   )Nr  osr   loggingr"  r  r  	functoolsr   typingr   r   r   r   r	   r
   r   pydanticr   collectionsr   r   lxmlr   r
  jsfr   #label_studio_sdk._legacy.exceptionsr   r   r   baser   control_tagsr   r   r   r   r   object_tagsr   
label_tagsr   r   r   r   r   r    rd   r"   rn   	getLoggerrr  r   r  dirnamerealpath__file__dir_pathrL   	file_pathopenfloadr  _LABEL_TAGS_DIR_APP_NAMEr  rM  r6   rE   rQ   r\   r^   r   rp   re   rg   r;   r7   r5   <module>r     sB   
   	   % D D D  1     !  #   H H 			8	$ 77??277++H56GGLL4H>XY		)_ - )		!- .() 

D687 7C 7HSM 7F Fc- -s   :EE