
    $j)p                       d Z ddlmZ ddlZddl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ZddlmZmZmZmZmZmZ 	 ddlmZ n# e$ r dZY nw xY w	 dd	lmZmZ n# eef$ r dZdZY nw xY w ej        e          Z d
d
d
d
dZ!d.dZ"d/dZ#d.dZ$d.dZ%d.dZ&d0dZ'd1dZ(d2d!Z) G d" d#          Z*	 d3d4d(Z+	 d3d5d+Z,d6d-Z-dS )7zAModality detection, input parsing, and message format conversion.    )annotationsN)defaultdict)AnyLiteral)urlparse)
AudioInputMessageFormatModality	PairInputSingleInput
VideoInput)Image)AudioDecoderVideoDecoderflat)apertusdeepseek_v3gpt_ossseed_osstextstrreturnboolc                4    |                      d          od| vS )zQCheck if a string looks like a valid URL (starts with http(s) and has no spaces).)zhttp://zhttps:// )
startswithr   s    k/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/sentence_transformers/base/modality.py_looks_like_urlr   .   s    ??233G4G    
extensionstuple[str, ...]c                H   t          |           rN	 t          |           j                                        }n# t          $ r Y dS w xY w|                    |          S |                                                     |          ot          j                            |           S )zOCheck if a string is a URL or local file path with one of the given extensions.F)r   r   pathlower
ValueErrorendswithosisfile)r   r!   r$   s      r   _is_media_url_or_pathr*   3   s    t )	D>>&,,..DD 	 	 	55	 }}Z(((::<<  ,,E1E1EEs   &8 
AAc                P    |                      d          rdS t          | d          S )z:Check if a string is an image URL, file path, or data URI.zdata:image/T)z.jpgz.jpegz.pngz.gifz.bmpz.tiffz.webp)r   r*   r   s    r   is_image_url_or_pathr,   ?   s,    }%% t 'bcccr    c                    t          | d          rdS t          |           sdS 	 t          |           j        }n# t          $ r Y dS w xY w|dv S )z.Check if a string is a video URL or file path.)z.mp4z.aviz.movz.wmvz.flvz.mkvTF)zwww.youtube.comzyoutube.comzyoutu.bezm.youtube.com)r*   r   r   netlocr&   )r   r.   s     r   is_video_url_or_pathr/   F   sx    T#STT t4   u$&   uu   s   : 
AAc                "    t          | d          S )z/Check if a string is an audio URL or file path.)z.mp3z.wavz.oggz.flacz.aac)r*   r   s    r   is_audio_url_or_pathr1   X   s     'PQQQr    sampler   c                   t          | t          t          f          rt          |           dk    rdS t          | d         t                    rt          | d         t                    rdS | D ]W}t          |t
                    rd|v rd|v r dS t          |t                    r |rt          |d         t
                    r dS XdS )a  Check if a sample is a non-text pair (2-element tuple/list with at least one non-string element).

    Text pairs ``(str, str)`` are handled natively by tokenizers and detected as ``"text"`` modality
    by :func:`infer_modality`. This helper detects pairs that contain at least one non-string element
    (e.g. an image, audio array, or dict), which require conversion to message format.
       Fr      rolecontentT)
isinstancetuplelistlenr   dict)r2   elems     r   _is_non_text_pairr>   ]   s     fudm,, Fq0@0@u&)S!! jC&@&@ u  dD!! 	fnnd9J9J55dD!! 	d 	z$q'4/H/H 	554r    audio_valuer   extra_modality_kwargsdict[str, dict[str, Any]]c                D   t          | t                    rd| v r| d         |d         d<   | d         S t          ft          | t                    rQ|                                 }|j        |d         d<   |j                            d                                          S | S )zUnwrap dict-wrapped audio or an ``AudioDecoder`` into a raw array, collecting ``sampling_rate``.

    Passes through unchanged if ``audio_value`` is already a raw array/tensor/URL/path.
    sampling_rateaudioarrayNr   )dim)r8   r<   r   get_all_samplessample_ratedatameannumpy)r?   r@   sampless      r   _unwrap_audiorM   r   s    
 +t$$ $k))>I/>Z!'*?;7##J{L$I$I--//:A:Mg&7|  Q ''--///r    video_valuer   c           
         t          | t                    rAd| v r5|d                             dg                               | d                    | d         S t          t          | t                    r|                     dt          |                     }|d                             dg                               | j        j        | j        j	        t          t          |j        j        d                             d           |j        S | S )zUnwrap dict-wrapped video or a ``VideoDecoder`` into a raw array, collecting ``video_metadata``.

    Passes through unchanged if ``video_value`` is already a raw array/tensor/URL/path.
    video_metadatavideorE   Nr   )fpstotal_num_framesframes_indices)r8   r<   
setdefaultappendr   get_frames_in_ranger;   metadataaverage_fps
num_framesr:   rangerI   shape)rN   r@   frame_batchs      r   _unwrap_videor^      s   
 +t$$ ${**!'*556FKKRRS^_oSpqqq7##J{L$I$I!55a[9I9IJJg&112BBGGNN"+7$/$8$C"&u[-=-CA-F'G'G"H"H 	
 	
 	
 r    c                  |    e Zd ZdZ	 	 	 d.d/dZd0dZd1dZd2dZd3d4dZd5d!Z	e
d6d%            Zd7d'Zd8d)Zd9d-ZdS ):InputFormattera  Handles input parsing, modality detection, and message format conversion.

    This class manages the complete input preprocessing pipeline:
    1. Parsing raw inputs to detect their modality (text, image, audio, video, message)
    2. Converting inputs to different chat template formats
    3. Normalizing mixed-modality inputs

    Different models require different message/chat template formats:
    - **Structured format**: Content is a list of dicts with type annotations
        [{"role": "user", "content": [{"type": "text", "text": "hello"}]}]

    - **Flat format**: Content is the direct value
        [{"role": "user", "content": "hello"}]

    Args:
        model_type: The model type string (e.g. from ``config.model_type``).
        message_format: Message format to use. Options:
            - ``"structured"``: Content is a list of dicts with type/modality keys
            - ``"flat"``: Content is the direct value
            - ``"auto"``: Automatically infer from processor (default)
        processor: Optional processor to infer format from when ``message_format="auto"``.
        supported_modalities: Optional list of modalities supported by the model. When provided,
            string inputs that look like media URLs/paths are only classified as non-text if the
            model actually supports that modality. This prevents text-only models from
            misclassifying text containing media URLs.
    autoN
model_typer   message_formatr	   supported_modalitieslist[Modality] | Noner   Nonec                    || _         || _        || _        |dk    r |r|                     |          nd| _        d S || _        d S )Nra   
structured)rb   	processorrd   _infer_formatrc   )selfrb   rc   ri   rd   s        r   __init__zInputFormatter.__init__   sZ     %"$8!V##CL"^$"4"4Y"?"?"?R^D"0Dr    Literal['structured', 'flat']c                    | j         t          v rt          | j                  S t          |dd          t          t                    rsdS g d}t          fd|D                       rdS dS )a  Infer the message format expected by the processor.

        Checks known model types first, then inspects the processor's chat template
        for patterns indicating structured format. Defaults to ``"structured"`` if
        neither approach is conclusive.

        Args:
            processor: The processor/tokenizer to inspect.

        Returns:
            ``"structured"`` or ``"flat"`` message format.
        chat_templateNrh   )z
content[0]z.typez'type'z"type"z	item.typezmessage.content[c              3      K   | ]}|v V  	d S N ).0patterntemplates     r   	<genexpr>z/InputFormatter._infer_format.<locals>.<genexpr>   s(      FFww("FFFFFFr    r   )rb   !KNOWN_MODEL_TYPES_MESSAGE_FORMATSgetattrr8   r   any)rk   ri   structured_patternsru   s      @r   rj   zInputFormatter._infer_format   s     ????4T_EE9ot<<(C(( 	  	 <
 
 
 FFFF2EFFFFF 	 <vr    inputslist[SingleInput | PairInput]Btuple[Modality, dict[str, list], defaultdict[str, dict[str, Any]]]c                    |sddg it          t                    fS g }t          t                    }d}|D ]}t          |          r|                    d|f           d},t	          | j                  }|dk    rt          ||          }n|dk    rt          ||          }nt          |t                    rJt          |          }d|v rt          |d         |          |d<   d|v rt          |d         |          |d<   n!|dk    rt          |t                    r|g}n|}|                    ||f           	|rg }|D ]\  }	}|	dk    r)|                     
                    |                     4|	dk    rXt          |t          t          f          r<t          |          d	k    r)|                     
                    |                     |	dk    r|                    |           t          |	t                    r|n|	|i}
|                                         |
                     dd|i|fS t          | \  }t                    t          |          }t          |          d
k    rW|                                }t          |t"                    r|inYd                                         }fd|D             n0t&                              d| d           d fd|D             id}||fS )a-  Parse inputs and group by modality.

        Analyzes a list of inputs to detect their modality (text, image, audio, video, message)
        and groups them appropriately for the processor. Handles mixed modalities by converting
        to message format when necessary.

        Non-text pairs (e.g. ``(image, text)`` or ``(image, image)``) are detected and converted
        to message format with ``"query"``/``"document"`` roles via :meth:`pair_to_messages`.

        Args:
            inputs: List of inputs to parse. Can be:
                - str: Text inputs
                - tuple/list of str: Text pairs (for cross-encoders)
                - tuple/list of mixed types: Non-text pairs (e.g. image + text)
                - dict: Chat messages, audio data, or multimodal inputs
                - PIL.Image.Image: Image inputs
                - np.ndarray/torch.Tensor: Audio (1-2D) or video (3-5D) inputs

        Returns:
            Tuple of (modality, processor_inputs_dict, extra_modality_kwargs) where:
                - modality: Detected modality string (``"text"``, ``"image"``, etc.) or tuple of modalities
                - processor_inputs_dict: Dictionary mapping modality names to input lists
                - extra_modality_kwargs: Extra kwargs per modality (e.g. ``sampling_rate`` for audio)
        r   FpairTrd   rD   rQ   messager4   r5   r   c                0    i | ]fd D             S )c                     g | ]
}|         S rr   rr   )rs   entrymods     r   
<listcomp>z:InputFormatter.parse_inputs.<locals>.<dictcomp>.<listcomp>D  s    )S)S)S%*)S)S)Sr    rr   )rs   r   processed_inputss    @r   
<dictcomp>z/InputFormatter.parse_inputs.<locals>.<dictcomp>D  s3    #l#l#lX[C)S)S)S)SBR)S)S)S#l#l#lr    zMixed modalities detected: z!. Converting to 'message' format.c                r    g | ]3\  }}                     t          |t                    r|n||i          4S rr   )
to_messager8   r9   )rs   modalityvaluerk   s      r   r   z/InputFormatter.parse_inputs.<locals>.<listcomp>H  sR       '% OOZ%-H-H$_EExY^N_``  r    )r   r<   r>   rV   infer_modalityrd   rM   r^   r8   r9   pair_to_messagesr:   r;   r   zipsetpopr   keysloggerdebug)rk   r{   typed_inputsr@   	has_pairsitemr   r   messagesr   typed
modalitiesunique_modalitiesordered_keysr   s   `             @r   parse_inputszInputFormatter.parse_inputs   s   8  	;FB<T):):::EG +D 1 1	 	3 	3D !&& ##VTN333 	%dAZ[[[H
 7""%d,ABBW$$%d,ABBHe,, 	T

e##%25>CX%Y%YE'Ne##%25>CX%Y%YE'NY&&:dD+A+A&5 12222
  	KH* 	< 	<
U&==OOD$9$9%$@$@AAAAF]]z%%'G'G]CPUJJZ[OOOOD$9$9%$@$@AAAAI%%OOE****%/U%;%;MEE#uEOODOOE$:$:;;;;y(35JJJ'*L'9$
$ 011
OO !!Q&&(,,..H(C(( m$,.>#?    027799#l#l#l#l_k#l#l#l  LLk7Hkkklll    +7    !H)+@@@r    r   tuple | listlist[dict[str, Any]]c                    |\  }}t          |          }t          |          }| j        dk    r
d|dd|dgS d }d |||          dd |||          dgS )a  Convert a pair of inputs to query/document message format.

        Each element of the pair is wrapped in a message with role ``"query"`` (first element)
        or ``"document"`` (second element). The modality of each element is inferred individually
        via :func:`infer_modality`.

        Args:
            pair: A 2-element tuple or list of inputs (e.g. ``(image, text)``).

        Returns:
            List of two message dictionaries with ``"query"`` and ``"document"`` roles.
        r   queryr6   r7   documentc                    t          | t                    r#t          t                    rfd| D             S d| | igS )Nc                0    g | ]}|v d |||         iS typerr   )rs   r   r   s     r   r   zHInputFormatter.pair_to_messages.<locals>._to_content.<locals>.<listcomp>l  s,    YYY#STX[[c495[[[r    r   )r8   r9   r<   )r   r   s    `r   _to_contentz4InputFormatter.pair_to_messages.<locals>._to_contenth  sV     (E** Zz$/E/E ZYYYYYYYYXx677r    )r   rc   )rk   r   
query_itemdoc_itemquery_modalitydoc_modalityr   s          r   r   zInputFormatter.pair_to_messagesQ  s      $
H'
33%h//&(( Z88#99 
	8 	8 	8 ^Z)P)PQQKKh,O,OPP
 	
r    usertyped_inputdict[Modality, Any]r6   c                $   | j         dk    rdt          |          dk    r7t          t          |                                                    \  }}||dgS t
                              d           |d |                                D             dgS )a  Convert a typed input dictionary to message format.

        Produces a single message with the given ``role``. For pair/multi-value inputs,
        use :meth:`pair_to_messages` instead (which is called automatically by :meth:`parse_inputs`).

        Args:
            typed_input: Dictionary mapping modality to input value (single value per modality).
            role: Role for the message (default: ``"user"``).

        Returns:
            List of message dictionaries (single message).
        r   r5   r   zbFlat message format requested but multiple modalities detected. Falling back to structured format.c                     g | ]\  }}d |||iS r   rr   )rs   r   r   s      r   r   z-InputFormatter.to_message.<locals>.<listcomp>  s%    kkkOHeVXx?kkkr    )rc   r;   nextiteritemsr   warning)rk   r   r6   _r   s        r   r   zInputFormatter.to_messaget  s     &((;1$$[%6%6%8%8 9 9::5!%%88999   kkWbWhWhWjWjkkk 
 	
r    r   r
   processor_inputsr<   *tuple[Literal['message'], dict[str, list]]c                   sddg ifS t          |t                    r|fn|t          t          t	                                                                        }g }t          |          D ]fdD             }t          |          dk    rt          t	          |                                                    }t          |t          t          f          rUt          |          dk    rBt          d |D                       r)|
                    |                     |                     |
                    |                     |                     dd|ifS )ac  Convert a batch of modality-specific inputs into the unified message format.

        Args:
            modality: The modality key (string) or tuple of modality keys.
            processor_inputs: Dictionary mapping modality names to lists of inputs.

        Returns:
            Tuple of ``("message", {"message": [messages_per_sample, ...]})``
        r   c                6    i | ]}|v ||                  S rr   rr   )rs   r   ir   r   s     r   r   z3InputFormatter.batch_to_message.<locals>.<dictcomp>  s2    jjjSX[_iXiXi3 0 5a 8XiXiXir    r5   r4   c              3  @   K   | ]}t          |t                    V  d S rq   )r8   r   )rs   vs     r   rv   z2InputFormatter.batch_to_message.<locals>.<genexpr>  s0      OrOrghPZ[\^aPbPbOrOrOrOrOrOrr    )r8   r   r;   r   r   valuesr[   r9   r:   allrV   r   r   )	rk   r   r   
batch_sizer   r   r   r   r   s	     `    @@r   batch_to_messagezInputFormatter.batch_to_message  sf      	.y"o--$.x$=$=Kh[[8
d#3#:#:#<#<==>>??
z"" 		: 		:AjjjjjjDTjjjK;1$$T+"4"4"6"67788eeT]33 E

aCOrOrlqOrOrOrLrLrOOD$9$9%$@$@AAAOODOOK8899999h///r    messages_batchlist[list[dict[str, Any]]]r   c                    | D ]h}|D ]c}|                     d          }t          |t                    r-t          |t                    rt	          d |D                       r  dS `  dS idS )a  Check whether all messages in a batch contain only text content.

        Works with both flat format (``{"content": "hello"}``) and structured format
        (``{"content": [{"type": "text", "text": "hello"}]}``).

        Args:
            messages_batch: List of message lists, one per sample.

        Returns:
            True if every message contains only text, False if any contain non-text content.
        r7   c              3  J   K   | ]}|                     d d          dk    V  dS )r   r   N)get)rs   r   s     r   rv   z7InputFormatter.is_text_only_messages.<locals>.<genexpr>  s5      RR$488FF33v=RRRRRRr    FT)r   r8   r   r:   ry   )r   r   r   r7   s       r   is_text_only_messagesz$InputFormatter.is_text_only_messages  s     ' 		! 		!H# ! !!++i00gs++ gt,, !RR'RRRRR %$uuu% !555! tr    r   c                   g }|D ]f}d|vsd|vrt                               d| d           *|d         }t          |t                    o|ot          |d         t                    }| j        dk    r|rt          |          dk    r2d|d         v r(|                    i |d|d         d         i           t                               d	t          |           d
           |                    |           | j        dk    rO|sMt          |t                    r!|                    i |dd|dgi           :|                    |           Q|                    |           h|S )a;  Normalize messages to the target format (``self.message_format``).

        Extra keys beyond ``"role"`` and ``"content"`` are preserved during conversion.

        Args:
            messages: List of message dictionaries to normalize.

        Returns:
            Normalized list of message dictionaries.
        r6   r7   zInvalid message format: z. Skipping.r   r   r5   r   z;Cannot convert structured message to flat format: contains z# content items. Keeping structured.rh   r   r   )	r   r   r8   r:   r<   rc   r;   rV   r   )rk   r   
normalizedr   r7   is_currently_structureds         r   normalize_messagesz!InputFormatter.normalize_messages  s    
 	+ 	+GW$$	(@(@N'NNNOOOi(G&0$&?&?&lG&lPZ[bcd[egkPlPl#"f,,1H,w<<1$$71:)=)=%%&P&P)WQZ=O&P&PQQQQNNV$'LLV V V   %%g....$44=T4gs++ /%%&a&a)vW^>_>_=`&a&abbbb%%g....!!'****r    promptc                R    | j         dk    rfd|D             S fd|D             S )a'  Prepend a system prompt to message format inputs.

        Args:
            messages: List of message lists (each message list represents one input).
            prompt: System prompt to prepend.

        Returns:
            Messages with system prompt prepended to each message list.
        r   c                "    g | ]}d dg|z   S )systemr   rr   rs   message_listr   s     r   r   z=InputFormatter.prepend_prompt_to_messages.<locals>.<listcomp>  s)    hhh|h6::;lJhhhr    c                *    g | ]}d ddgdg|z   S )r   r   r   r   rr   r   s     r   r   z=InputFormatter.prepend_prompt_to_messages.<locals>.<listcomp>  sE     
 
 
 VV,L,L+MNNOR^^
 
 
r    )rc   )rk   r   r   s     `r   prepend_prompt_to_messagesz)InputFormatter.prepend_prompt_to_messages  sY     &((hhhh_ghhhh
 
 
 
 (
 
 
 	
r    texts'list[str | tuple[str, str] | list[str]]list[str | list[str]]c           	         g }|D ]g}t          |t                    r|                    ||z              0|                    ||d         z   gt          |dd                   z              h|S )ab  Prepend a prompt to text format inputs.

        For single texts, prepends the prompt directly.
        For text pairs (cross-encoder inputs), prepends only to the first text.

        Args:
            texts: List of text inputs (strings or pairs)
            prompt: Prompt to prepend

        Returns:
            Texts with prompt prepended
        r   r5   N)r8   r   rV   r:   )rk   r   r   resultr   s        r   prepend_prompt_to_textsz&InputFormatter.prepend_prompt_to_texts  s      	C 	CD$$$ Cftm,,,,vQ/04QRR>>ABBBBr    )ra   NN)rb   r   rc   r	   rd   re   r   rf   )r   rm   )r{   r|   r   r}   )r   r   r   r   )r   )r   r   r6   r   r   r   )r   r
   r   r<   r   r   )r   r   r   r   )r   r   r   r   )r   r   r   r   r   r   )r   r   r   r   r   r   )__name__
__module____qualname____doc__rl   rj   r   r   r   r   staticmethodr   r   r   r   rr   r    r   r`   r`      s        < )/6:1 1 1 1 1       DiA iA iA iAV!
 !
 !
 !
F
 
 
 
 
<0 0 0 0:    \0% % % %N
 
 
 
&     r    r`   SingleInput | PairInput | Anyrd   re   r
   c                ^   t           t          | t                     rdS t          t          | t                    rdS t          t          | t                    rdS | xt          d x\   t          |           r |d|vrdS dS  xt          d x\   t          |           r |d|vrdS dS  xt          d x\   t          |           r |d|vrdS dS  xxt          d x\   nO x  r" dk    r\  t          d x\   t          d x\   n*  x  r" dk    r\  t          d x\   t          d x\   n   n  dS xt          d x\   d| v rd	| v r d
S  xt          d x6\   | r3t          | d         t                    rd| d         v rd	| d         v r d
S  xt          d x\   d| v rd| v r dS  xt          d x\   d| v rd| v r dS  xt          d x8\   d| v r3 t          dt          |                                                       xt          d xr\   | ro h d}t          |                                           |z
  }|rt          d| d|           t          t          |                                                     S  xt          d x\    t          d           xt          j        d x\   n xt"          j        d x\   n  n< | j        dv rdS | j        dk    rdS | j        dv rdS t          d| j         d          	 t          dt)          |           j         d          )a  Infer the modality of a single input sample by inspecting its type/structure.

    Pure type-based detection, does not require a processor or tokenizer.

    Args:
        sample: A single input sample to inspect.
        supported_modalities: Optional list of modalities the model supports. When provided,
            string inputs that would be classified as image/video/audio based on URL/path
            heuristics are instead classified as ``"text"`` if that modality is not supported.
            This prevents misclassification of text that happens to contain media URLs.

    Returns:
        The detected modality string, or a tuple of modality strings for multimodal dict inputs.

    Raises:
        ValueError: If the input type/structure is not recognized.
    NimagerD   rQ   rr   r   r4   r6   r7   r   r   rE   rC   rP   zuDict input with 'array' key must also include 'sampling_rate' (for audio) or 'video_metadata' (for video). Got keys: >   r   rD   r   rQ   z;Multimodal dict input contains unrecognized modality keys: z. Expected keys from: z-Empty dict input is not a valid input sample.)r5   r4      )      z#Unsupported tensor dimensionality: z<D. Expected 1-2D for audio, 3D for image, or 4-5D for video.zUnsupported input type: zG. Expected one of: str, dict, PIL.Image.Image, np.ndarray, torch.Tensor)PILImager8   r   r   r   r,   r/   r1   r<   r:   r&   r   r   r9   sortednpndarraytorchTensorndimr   r   )r2   rd   valid_modalitiesinvalid_keyss       r   r   r     s\   , 
68 < <wJv|$D$DwJv|$D$Dw
SUUUUU*622UU#/GCW4W4Wv7  SUUUUU*622UU#/GCW4W4Wv7  SUUUUU*622UU#/GCW4W4Wv7  5USUUUUUUU^^^^^^^^ceeeeeSUUUUUUUUnnnnnnnnsuuuuuceeeeeeeeeeee6TVVVVVv''I,?,?,?9 TVVVVVvV*VAY"="=V&FSTIBUBUZcgmnogpZpZpZp9 TVVVVVw&((_-F-F-F7 TVVVVVw&((-=-G-G-G7 TVVVVVw&(((2 //2 2    TVVVVVvVVBBBv{{}}--0@@L  >R^ > >+;> >   ..///  TVVVVVVLMMM RZ\\\\\\\NELNNNNNNNNNN{f$$w!!w&&w Q&+ Q Q Q   Y4<<+@ Y Y Y  r    rL   r|   c                z    | sdS fd| D             }t          |          dk    r|                                ndS )a  Infer the modality of a batch of input samples.

    If all samples share the same modality, that modality is returned. If the batch contains
    mixed modalities, ``"message"`` is returned, consistent with how :class:`InputFormatter`
    handles mixed-modality batches in :meth:`~InputFormatter.parse_inputs`.

    Args:
        samples: List of input samples to inspect.
        supported_modalities: Optional list of modalities the model supports. Passed through
            to :func:`infer_modality` to prevent misclassification of text as media modalities.

    Returns:
        The detected modality, or ``"message"`` for mixed-modality batches.
    r   c                2    h | ]}t          |           S )r   )r   )rs   r2   rd   s     r   	<setcomp>z'infer_batch_modality.<locals>.<setcomp>  s(    jjjX^.>RSSSjjjr    r5   r   )r;   r   )rL   rd   r   s    ` r   infer_batch_modalityr   u  sQ    $  vjjjjbijjjJ":!33:>>Br    r   c                Z    t          | t                    rd                    |           S | S )zSFormat a modality for display, e.g. ``("text", "image")`` becomes ``"text+image"``.+)r8   r9   join)r   s    r   format_modalityr     s+    (E"" "xx!!!Or    )r   r   r   r   )r   r   r!   r"   r   r   )r2   r   r   r   )r?   r   r@   rA   r   r   )rN   r   r@   rA   r   r   rq   )r2   r   rd   re   r   r
   )rL   r|   rd   re   r   r
   )r   r
   r   r   ).r   
__future__r   loggingr(   collectionsr   typingr   r   urllib.parser   rK   r   r   )sentence_transformers.base.modality_typesr   r	   r
   r   r   r   	PIL.Imager   r   ImportErrortorchcodec.decodersr   r   OSError	getLoggerr   r   rw   r   r*   r,   r/   r1   r>   rM   r^   r`   r   r   r   rr   r    r   <module>r     s   G G " " " " " "  				 # # # # # #         ! ! ! ! ! !                    +++++++   HHH>>>>>>>>>W   LLLL 
	8	$	$
 	% % !H H H H
	F 	F 	F 	Fd d d d   $R R R R
   *   "   ,~ ~ ~ ~ ~ ~ ~ ~F 37X X X X Xz 37C C C C C0     s#   A AAA A*)A*