§
    ™Štj¥  ã                  ó¸  — d Z ddlm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 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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 e!f$ r dZdZY nw xY w ej"        e#¦  «        Z$d
d
d
d
dœZ%dZ&dZ'd<d„Z(d=d„Z)d<d„Z*d<d„Z+d<d„Z,d>d„Z-d?d!„Z.d@d$„Z/dAd'„Z0dBd*„Z1 G d+„ d,¦  «        Z2	 dCdDd1„Z3	 dCdEd4„Z4dFd6„Z5dGd;„Z6dS )HzAModality detection, input parsing, and message format conversion.é    )ÚannotationsN)Údefaultdict)ÚAnyÚLiteralÚNoReturn)Úurlparse)ÚMULTIMODAL_DICT_KEYSÚ
AudioInputÚMessageFormatÚModalityÚ	PairInputÚSingleInputÚ
VideoInput)ÚImage)ÚAudioDecoderÚVideoDecoderÚflat)ÚapertusÚdeepseek_v3Úgpt_ossÚseed_oss)ÚqueryÚdocument))ÚalphaÚbravo)Úcharlier   )r   ÚfoxtrotÚ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    úa/var/www/html/CA-Chatbot/venv/lib/python3.11/site-packages/sentence_transformers/base/modality.pyÚ_looks_like_urlr'   7   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_pathr2   <   s˜   € å�tÑÔð )ð	Ý˜D‘>”>Ô&×,Ò,Ñ.Ô.ˆDˆDøÝð 	ð 	ð 	à�5�5ð	øøøð �}Š}˜ZÑ(Ô(Ð(Ø�:Š:‰<Œ<× Ò  Ñ,Ô,ÐEµ´·²ÀÑ1EÔ1EÐ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$   r2   r%   s    r&   Úis_image_url_or_pathr4   H   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)r2   r'   r   Únetlocr.   )r   r6   s     r&   Úis_video_url_or_pathr7   O   sx   € å˜TÐ#SÑTÔTð ØˆtÝ˜4Ñ Ô ð ØˆuðÝ˜$‘”Ô&ˆˆøÝð ð ð Øˆuˆuðøøøàð ð ð 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)r2   r%   s    r&   Úis_audio_url_or_pathr9   a   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)r:   Úelems     r&   Ú_is_non_text_pairrF   f   sÔ   € õ �f�u¥d˜mÑ,Ô,ð µ°F±´¸qÒ0@Ð0@Øˆuå�&˜”)�SÑ!Ô!ð ¥j°¸´½CÑ&@Ô&@ð Øˆuàð ð ˆÝ�d�DÑ!Ô!ð 	 f° n n¸ÀdÐ9JÐ9JØ�5�5Ý�d�DÑ!Ô!ð 	 dð 	­z¸$¸q¼'Å4Ñ/HÔ/Hð 	Ø�5�5øØˆ4r(   Úsampling_rateÚintÚextra_modality_kwargsúdict[str, dict[str, Any]]ÚNonec                óŽ   — |d                               d¦  «        }|�|| k    rt          d|› d| › d�¦  «        ‚| |d         d<   dS )a	  Record the batch-level ``sampling_rate``, raising if samples disagree.

    Feature extractors accept a single ``sampling_rate`` for the whole batch, so conflicting
    per-sample rates cannot be honored and would silently process some audio at the wrong rate.
    ÚaudiorG   Nz6This batch mixes audio with different sampling rates (ú and z”), but the processor accepts a single sampling rate per batch. Resample the audio to a common rate, or encode each sampling rate in a separate call.)Úgetr.   )rG   rI   Úexistings      r&   Ú_record_sampling_raterQ   {   sz   € ð % WÔ-×1Ò1°/ÑBÔB€HØÐ ¨MÒ 9Ð 9Ýð<ÀXð <ð <ÐTað <ð <ð <ñ
ô 
ð 	
ð
 7DÐ˜'Ô" ?Ñ3Ð3Ð3r(   Úaudio_valuer
   c                óX  — t          | t          ¦  «        r"d| v rt          | d         |¦  «         | d         S t          �kt          | t          ¦  «        rV|                      ¦   «         }t          |j        |¦  «         |j                             d¬¦  «                             ¦   «         S | S )z¾Unwrap 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.
    rG   ÚarrayNr   )Údim)	r@   rD   rQ   r   Úget_all_samplesÚsample_rateÚdataÚmeanÚnumpy)rR   rI   Úsampless      r&   Ú_unwrap_audior\   ‹   s§   € õ
 �+�tÑ$Ô$ð $Ø˜kÐ)Ð)Ý! +¨oÔ">Ð@UÑVÔVÐVØ˜7Ô#Ð#ÝÐ¥J¨{½LÑ$IÔ$IÐØ×-Ò-Ñ/Ô/ˆå˜gÔ1Ð3HÑIÔIÐIØŒ|× Ò  QÐ Ñ'Ô'×-Ò-Ñ/Ô/Ð/ØÐr(   Úvideo_valuer   c                óB  — |d                               dg ¦  «        }t          | t          ¦  «        r0|                     |                      d¦  «        ¦  «         | d         S t
          �¡t          | t
          ¦  «        rŒ|                      dt          | ¦  «        ¦  «        }|                     | j        j	        | j        j
        | j        j        t          t          |j        j        d         ¦  «        ¦  «        dœ¦  «         |j        S |                     d¦  «         | S )aº  Unwrap 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. Appends one
    metadata entry per video (``None`` when the sample carries none) so the batch-level list stays
    index-aligned with the videos. :func:`_reconcile_video_metadata` resolves the ``None`` entries
    once the whole batch has been parsed.
    ÚvideoÚvideo_metadatarT   Nr   )ÚfpsÚtotal_num_framesÚdurationÚframes_indices)Ú
setdefaultr@   rD   ÚappendrO   r   Úget_frames_in_rangerC   ÚmetadataÚaverage_fpsÚ
num_framesÚduration_secondsrB   ÚrangerX   Úshape)r]   rI   Úmetadata_listÚframe_batchs       r&   Ú_unwrap_videorp   œ   s  € ð *¨'Ô2×=Ò=Ð>NÐPRÑSÔS€MÝ�+�tÑ$Ô$ð $Ø×Ò˜[Ÿ_š_Ð-=Ñ>Ô>Ñ?Ô?Ð?Ø˜7Ô#Ð#ÝÐ¥J¨{½LÑ$IÔ$IÐØ!×5Ò5°a½¸[Ñ9IÔ9IÑJÔJˆØ×Òà"Ô+Ô7Ø$/Ô$8Ô$CØ'Ô0ÔAÝ"&¥u¨[Ô-=Ô-CÀAÔ-FÑ'GÔ'GÑ"HÔ"Hð	ð ñ	
ô 	
ð 	
ð ÔÐØ×Ò˜ÑÔÐØÐr(   Útyped_inputsú,list[tuple[Modality | Literal['pair'], Any]]c           	     óÒ  — |                      d¦  «        }|rd|vrdS |d         }t          d„ |D ¦   «         ¦  «        r
|d= |s|d= dS d„ | D ¦   «         }t          t          ||d¬¦  «        ¦  «        D ]r\  }\  }}|�Œt	          |t
          ¦  «        st          |d¦  «        st          d	¦  «        ‚t          |¦  «        }|ddt          t          |¦  «        ¦  «        d
œ||<   ŒsdS )aý  Resolve the per-sample video metadata entries collected by :func:`_unwrap_video`.

    If no video in the batch carried metadata, the key is dropped so the processor infers defaults
    itself. Otherwise every ``None`` entry is filled with the frame count of that video, matching what
    transformers infers for a metadata-less video. This requires the video to be in memory, so
    path/URL videos without metadata raise instead, as passing a partial list would attach metadata
    to the wrong videos.
    r_   r`   Nc              3  ó   K  — | ]}|d u V — Œ	d S ©N© )Ú.0Úentrys     r&   ú	<genexpr>z,_reconcile_video_metadata.<locals>.<genexpr>Ç   s&   è è € Ð
4Ð
4˜Uˆ5�Dˆ=Ð
4Ð
4Ð
4Ð
4Ð
4Ð
4r(   c                ó�   — g | ]C\  }}|d k    st          |t          ¦  «        ¯ d |v ¯$t          |t          ¦  «        r|d          n|‘ŒDS )r_   ©r@   rA   )rw   ÚmodÚvalues      r&   ú
<listcomp>z-_reconcile_video_metadata.<locals>.<listcomp>Ì   sZ   € ð ð ð áˆC�Ø�'Š>ˆ>�j¨­eÑ4Ô4ˆ>¸ÀC¸¸õ % S­%Ñ0Ô0Ð;ˆˆgŒˆ°eà9G¸¸r(   T)ÚstrictÚ__len__zýThis batch mixes videos that carry per-sample 'video_metadata' with videos that do not. Default metadata can only be inferred for in-memory videos (frame arrays or lists), so either pass 'video_metadata' for every video in the batch or for none of them.)rb   ra   rc   rd   )rO   ÚallÚ	enumerateÚzipr@   r   Úhasattrr.   rC   rB   rl   )	rq   rI   Úvideo_kwargsrn   ÚvideosÚindexrx   r_   rj   s	            r&   Ú_reconcile_video_metadatarˆ   ·   sQ  € ð )×,Ò,¨WÑ5Ô5€LØð Ð+°<Ð?Ð?ØˆØ Ð!1Ô2€MÝ
Ð
4Ð
4 mÐ
4Ñ
4Ô
4Ñ4Ô4ð ØÐ)Ð*Øð 	/Ø% gÐ.Øˆðð à&ðñ ô €Fõ
 "+­3¨}¸fÈTÐ+RÑ+RÔ+RÑ!SÔ!Sð 
ð 
Ñˆ‰~��uØÐØÝ�e�SÑ!Ô!ð 	­°¸	Ñ)BÔ)Bð 	Ýðañô ð õ
 ˜‘Z”Zˆ
à *ØØÝ"¥5¨Ñ#4Ô#4Ñ5Ô5ð	 
ð  
ˆ�eÑÐð
ð 
r(   c                  ó¦   — e Zd ZdZ	 	 	 d6d7d„Zd8d„Zd9d„Zd:d;d„Zd<d„Zd=d„Z	d>d?d#„Z
d@d)„ZedAd,„¦   «         Zed<d-„¦   «         ZdBd/„ZdCd1„ZdDd5„ZdS )EÚ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    rK   c                ó˜   — || _         || _        || _        d | _        |dk    r |r|                      |¦  «        nd| _        d S || _        d S )Nr‹   Ú
structured)rŒ   Ú	processorrŽ   Ú_pair_role_probeÚ_infer_formatr�   )ÚselfrŒ   r�   r’   rŽ   s        r&   Ú__init__zInputFormatter.__init__ÿ   sb   € ð %ˆŒØ"ˆŒØ$8ˆÔ!ØVZˆÔØ˜VÒ#Ð#ØCLÐ"^ $×"4Ò"4°YÑ"?Ô"?Ð"?ÐR^ˆDÔÐÐà"0ˆDÔÐÐ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_templateNr‘   )z
content[0]z.typez'type'z"type"z	item.typezmessage.content[c              3  ó    •K  — | ]}|‰v V — Œ	d S ru   rv   )rw   ÚpatternÚtemplates     €r&   ry   z/InputFormatter._infer_format.<locals>.<genexpr>,  s(   øè è € ÐFÐF wˆw˜(Ð"ÐFÐFÐFÐFÐFÐFr(   r   )rŒ   Ú!KNOWN_MODEL_TYPES_MESSAGE_FORMATSÚgetattrr@   r   Úany)r•   r’   Ústructured_patternsrœ   s      @r&   r”   zInputFormatter._infer_format  s“   ø€ ð Œ?Õ?Ð?Ð?Ý4°T´_ÔEÐEå˜9 o°tÑ<Ô<ˆÝ˜(¥CÑ(Ô(ð 	 °ð 	 Ø�<ð
ð 
ð 
Ðõ ÐFÐFÐFÐFÐ2EÐ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 �]F}t          |¦  «        r|                     d|f¦  «         d}Œ,t	          |‰ j        ¬¦  «        }t          |t          ¦  «        r*|t          v r!|                     ¦   «         |hk    r||         }|dk    rt          ||¦  «        }n—|dk    rt          ||¦  «        }n€t          |t          ¦  «        rJt          |¦  «        }d|v rt          |d         |¦  «        |d<   d|v rt          |d         |¦  «        |d<   n!|dk    rt          |t          ¦  «        r|g}n|}|                     ||f¦  «         �ŒHt          ||¦  «         |rãg }|D ]×\  }	}|	dk    r)|                     ‰                      |¦  «        ¦  «         Œ4|	dk    r>‰                      |¦  «        r)|                     ‰                      |¦  «        ¦  «         Œx|	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©rŽ   rM   r_   Úmessager=   r   c                ó0   •‡— i | ]Š‰ˆfd „‰D ¦   «         “ŒS )c                ó    •— g | ]
}|‰         ‘ŒS rv   rv   )rw   rx   r|   s     €r&   r~   z:InputFormatter.parse_inputs.<locals>.<dictcomp>.<listcomp>•  s   ø€ Ð)SÐ)SÐ)S¸¨%°¬*Ð)SÐ)SÐ)Sr(   rv   )rw   r|   Úprocessed_inputss    @€r&   ú
<dictcomp>z/InputFormatter.parse_inputs.<locals>.<dictcomp>•  s3   øø€ Ð#lÐ#lÐ#lÐX[ CÐ)SÐ)SÐ)SÐ)SÐBRÐ)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 rv   )Ú
to_messager@   rA   )rw   Úmodalityr}   r•   s      €r&   r~   z/InputFormatter.parse_inputs.<locals>.<listcomp>™  sR   ø€ ð ð ð á'˜ %ð —O’O­Z¸Å%Ñ-HÔ-HÐ$_ E EÈxÐY^ÐN_Ñ`Ô`ðð ð r(   )r   rD   rF   rf   Úinfer_modalityrŽ   r@   r	   Úkeysr\   rp   rA   rˆ   Úpair_to_messagesÚis_text_pairr­   rƒ   rB   ÚsetrC   Úpopr   ÚloggerÚdebug)r•   r¡   rq   rI   Ú	has_pairsÚitemr®   r}   Úmessagesr|   ÚtypedÚ
modalitiesÚunique_modalitiesÚordered_keysrª   s   `             @r&   Úparse_inputszInputFormatter.parse_inputs1  sÓ  øø€ ð8 ð 	;Ø˜F B˜<­µTÑ):Ô):Ð:Ð:àEGˆÝ +­DÑ 1Ô 1ÐØˆ	àð !	3ñ !	3ˆDõ ! Ñ&Ô&ð Ø×#Ò# V¨T NÑ3Ô3Ð3Ø �	Øå% dÀÔAZÐ[Ñ[Ô[ˆHõ ˜$¥Ñ%Ô%ð &¨(Õ6JÐ*JÐ*JÈtÏyÊyÉ{Ì{Ð_gÐ^hÒOhÐOhØ˜H”~�ð
 ˜7Ò"Ð"Ý% dÐ,AÑBÔB��Ø˜WÒ$Ð$Ý% dÐ,AÑBÔB��Ý˜H¥eÑ,Ô,ð 	Ý˜T™
œ
�Ø˜eÐ#Ð#Ý%2°5¸´>ÐCXÑ%YÔ%Y�E˜'‘NØ˜eÐ#Ð#Ý%2°5¸´>ÐCXÑ%YÔ%Y�E˜'‘NøØ˜YÒ&Ð&­:°d½DÑ+AÔ+AÐ&Ø˜��à�à×Ò ¨5Ð 1Ñ2Ô2Ð2Ñ2å! ,Ð0EÑFÔFÐFð
 ð 	KØˆHØ*ð 	<ð 	<‘
��UØ˜&’=�=Ø—O’O D×$9Ò$9¸%Ñ$@Ô$@ÑAÔAÐAÐAØ˜F’]�] t×'8Ò'8¸Ñ'?Ô'?�]Ø—O’O D×$9Ò$9¸%Ñ$@Ô$@ÑAÔAÐAÐAØ˜IÒ%Ð%Ø—O’O EÑ*Ô*Ð*Ð*å%/°µUÑ%;Ô%;ÐM˜E˜EÀ#ÀuÀ�EØ—O’O D§O¢O°EÑ$:Ô$:Ñ;Ô;Ð;Ð;Ø˜y¨(Ð3Ð5JÐJÐJå'*¨LÐ'9Ñ$ˆ
Ð$ÝÐ 0Ñ1Ô1ÐÝ 
™OœOÐåÐ Ñ!Ô! QÒ&Ð&Ø(×,Ò,Ñ.Ô.ˆHÝ˜(¥CÑ(Ô(ð mØ$,Ð.>Ð#?Ð Ð ð  0°Ô2×7Ò7Ñ9Ô9�Ø#lÐ#lÐ#lÐ#lÐ_kÐ#lÑ#lÔ#lÐ Ð å�LŠLÐkÐ7HÐkÐkÐkÑlÔlÐlàð ð ð ð à+7ðñ ô ð Ðð !ˆHàÐ)Ð+@Ð@Ð@r(   Úchat_template_kwargsúdict[str, Any] | Noneú
str | Nonec                ó6  ‡ ‡‡	— t          ‰ j        dd¦  «        }|€dS ‰pi Š|‰f}‰ j        �‰ j        d         |k    r‰ j        d         S 	 ˆˆ fd„t          D ¦   «         ^Š	}ˆ	fd„t	          t
          |¦  «        D ¦   «         }|r&d                     d	„ |D ¦   «         ¦  «        }d
|› d�}n4d}n1# t          $ r$}dt          |¦  «        j	        › d|› �}Y d}~nd}~ww xY wt                               d|pd› �¦  «         t          j        |¦  «        |f‰ _        |S )a~  Why the chat template cannot carry a ``query``/``document`` pair, or None when it can.

        Decided by rendering probe pairs and diffing the outputs, never by reading the template source:
        templates can pass roles through without naming them (ChatML) or name them in branches a pair
        never reaches, and may transform content beyond recognition, so only a render that fails to move
        with its input proves the content goes nowhere. A template that raises is reported with the
        exception instead. The verdict is cached against a snapshot of the template and kwargs, so
        fixing either on a loaded model takes effect, which is the documented remedy.

        Args:
            chat_template_kwargs: The ``apply_chat_template`` kwargs the real render passes. These can
                select between named templates, so the probe must render with them.
        r™   Nzthe model has no chat templater   r=   c           	     óz   •— g | ]7}t           ‰j        j        ‰                     |¦  «        fd di‰¤Ž¦  «        ‘Œ8S )ÚtokenizeF)r   r’   Úapply_chat_templater±   )rw   r¥   r¿   r•   s     €€r&   r~   z5InputFormatter.pair_roles_failure.<locals>.<listcomp>¹  so   ø€ ð ð ð ð õ Ø6�D”NÔ6Ø×-Ò-¨dÑ3Ô3ðð Ø>CðØG[ðð ñô ðð ð r(   c                ó&   •— g | ]\  }}|‰k    ¯|‘ŒS rv   rv   )rw   r>   ÚrenderÚbases      €r&   r~   z5InputFormatter.pair_roles_failure.<locals>.<listcomp>Ä  s#   ø€ ÐZÐZÐZ¡  fÈ6ÐUYÊ>È>�tÈ>È>È>r(   rN   c              3  ó4   K  — | ]}t          |¦  «        V — Œd S ru   )Úrepr)rw   r>   s     r&   ry   z4InputFormatter.pair_roles_failure.<locals>.<genexpr>Æ  s(   è è € Ð$DÐ$D°D¥T¨$¡Z¤ZÐ$DÐ$DÐ$DÐ$DÐ$DÐ$Dr(   zthe z+ content does not reach the rendered promptz
it raised z: z'Pair-role probe for the chat template: zpair content survives)rž   r’   r“   ÚPAIR_ROLE_PROBESrƒ   Ú
PAIR_ROLESÚjoinÚ	ExceptionÚtypeÚ__name__rµ   r¶   ÚcopyÚdeepcopy)
r•   r¿   rœ   ÚkeyÚvariedÚdroppedÚrolesÚfailureÚexcrÈ   s
   ``       @r&   Úpair_roles_failurez!InputFormatter.pair_roles_failure¢  sŒ  øøø€ õ ˜4œ>¨?¸DÑAÔAˆØÐØ3Ð3Ø3Ð9°rÐØÐ-Ð.ˆØÔ Ð,°Ô1FÀqÔ1IÈSÒ1PÐ1PØÔ(¨Ô+Ð+ð	ðð ð ð ð õ -ðñ ô ˆMˆD�6ð [ÐZÐZÐZµµJÀÑ0GÔ0GÐZÑZÔZˆGØð ØŸšÐ$DÐ$D¸GÐ$DÑ$DÔ$DÑDÔD�ØS ÐSÐSÐS��à��øõ ð 	?ð 	?ð 	?Ø>¥4¨¡9¤9Ô#5Ð>Ð>¸Ð>Ð>ˆGˆGˆGˆGˆGˆGøøøøð	?øøøõ 	�ŠÐc¸wÐ?aÐJaÐcÐcÑdÔdÐdÝ!%¤¨sÑ!3Ô!3°WÐ =ˆÔØˆs   ÁB. Â.
CÂ8CÃCÚmessages_batchúlist[list[dict[str, Any]]]r!   c                ób   ‡— t          t          ¦  «        Št          ˆfd„|D ¦   «         ¦  «        S )a*  Whether any conversation in a batch carries both of the ``query``/``document`` pair roles.

        Anchored on produced messages so both routes into :meth:`pair_to_messages` are covered, and
        requiring both roles keeps hand-written single-role messages outside a check about pairs.
        c              3  ó8   •K  — | ]}‰d „ |D ¦   «         k    V — ŒdS )c                ó8   — h | ]}|                      d ¦  «        ’ŒS )r>   ©rO   )rw   r§   s     r&   ú	<setcomp>z:InputFormatter.has_pair_roles.<locals>.<genexpr>.<setcomp>Õ  s$   € Ð!NÐ!NÐ!N¸' '§+¢+¨fÑ"5Ô"5Ð!NÐ!NÐ!Nr(   Nrv   )rw   r¹   Ú
pair_roless     €r&   ry   z0InputFormatter.has_pair_roles.<locals>.<genexpr>Õ  s8   øè è € ÐnÐnÐS[�:Ð!NÐ!NÀXÐ!NÑ!NÔ!NÒNÐnÐnÐnÐnÐnÐnr(   )r³   rÌ   rŸ   )r•   rÚ   rá   s     @r&   Úhas_pair_roleszInputFormatter.has_pair_rolesÎ  s4   ø€ õ �‘_”_ˆ
ÝÐnÐnÐnÐnÐ_mÐnÑnÔnÑnÔnÐnr(   r¥   útuple | listúlist[dict[str, Any]]c                óÈ   — t           \  }}|\  }}t          |¦  «        }t          |¦  «        }| j        dk    r
||dœ||dœgS 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   ©r>   r?   c                ó   ‡— t          | t          ¦  «        r#t          ‰t          ¦  «        rˆfd„| D ¦   «         S t          ‰t          ¦  «        r*| t          v r!‰                     ¦   «         | hk    r‰|          Šd| | ‰igS )Nc                ó0   •— g | ]}|‰v ¯d ||‰|         i‘ŒS ©rÏ   rv   )rw   r|   r¸   s     €r&   r~   zHInputFormatter.pair_to_messages.<locals>._to_content.<locals>.<listcomp>ó  s,   ø€ ÐYÐYÐY¸#ÈSÐTXÈ[È[˜  c¨4°¬9Ð5È[È[È[r(   rÏ   )r@   rA   rD   r	   r°   )r®   r¸   s    `r&   Ú_to_contentz4InputFormatter.pair_to_messages.<locals>._to_contentï  s’   ø€ õ ˜(¥EÑ*Ô*ð Z­z¸$ÅÑ/EÔ/Eð ZØYÐYÐYÐYÀÐYÑYÔYÐYå˜$¥Ñ%Ô%ð &¨(Õ6JÐ*JÐ*JÈtÏyÊyÉ{Ì{Ð_gÐ^hÒOhÐOhØ˜H”~�Ø˜X x°Ð6Ð7Ð7r(   )rÌ   r¯   r�   )	r•   r¥   Ú
query_roleÚdoc_roleÚ
query_itemÚdoc_itemÚquery_modalityÚdoc_modalityrê   s	            r&   r±   zInputFormatter.pair_to_messages×  s©   € õ  *Ñˆ
�HØ#Ñˆ
�HÝ'¨
Ñ3Ô3ˆÝ% hÑ/Ô/ˆàÔ &Ò(Ð(à#°
Ð;Ð;Ø!¨hÐ7Ð7ðð ð
	8ð 	8ð 	8ð  ¨K¨K¸È
Ñ,SÔ,SÐTÐTØ¨+¨+°lÀHÑ*MÔ*MÐNÐNð
ð 	
r(   ÚuserÚtyped_inputúdict[Modality, Any]r>   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   r=   ræ   zbFlat message format requested but multiple modalities detected. Falling back to structured format.c                ó    — g | ]\  }}d |||i‘ŒS ré   rv   )rw   r®   r}   s      r&   r~   z-InputFormatter.to_message.<locals>.<listcomp>  s%   € ÐkÐkÐkÁOÀHÈe˜V X¨x¸Ð?ÐkÐkÐkr(   )r�   rC   ÚnextÚiterÚitemsrµ   Úwarning)r•   rò   r>   Ú_r}   s        r&   r­   zInputFormatter.to_messageþ  s­   € ð Ô &Ò(Ð(Ý�;ÑÔ 1Ò$Ð$Ý¥ [×%6Ò%6Ñ%8Ô%8Ñ 9Ô 9Ñ:Ô:‘��5Ø!%°%Ð8Ð8Ð9Ð9å—’ð9ñô ð ð ØkÐkÐWb×WhÒWhÑWjÔWjÐkÑkÔkðð ð
ð 	
r(   r®   r   Úprocessor_inputsrD   ú*tuple[Literal['message'], dict[str, list]]c                óv  ‡‡‡	— ‰sddg ifS t          |t          ¦  «        r|fn|Š	t          t          t	          ‰                     ¦   «         ¦  «        ¦  «        ¦  «        }g }t          |¦  «        D ]ÂŠˆˆ	ˆfd„‰D ¦   «         }t          |¦  «        dk    rut          t	          |                     ¦   «         ¦  «        ¦  «        \  }}|dk    r>|                      |¦  «        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 rv   rv   )rw   r|   Úir»   rû   s     €€€r&   r«   z3InputFormatter.batch_to_message.<locals>.<dictcomp>/  s2   ø€ ÐjÐjÐj¸SÐX[Ð_iÐXiÐXi˜3Ð 0°Ô 5°aÔ 8ÐXiÐXiÐXir(   r=   r   )r@   r   rC   rö   r÷   Úvaluesrl   rø   r²   rf   r±   r­   )
r•   r®   rû   Ú
batch_sizer¹   rò   r|   r}   rÿ   r»   s
     `     @@r&   Úbatch_to_messagezInputFormatter.batch_to_message  sE  øøø€ ð  ð 	.Ø˜y¨"˜oÐ-Ð-Ý$.¨x½Ñ$=Ô$=ÐK�h�[�[À8ˆ
Ý��dÐ#3×#:Ò#:Ñ#<Ô#<Ñ=Ô=Ñ>Ô>Ñ?Ô?ˆ
ØˆÝ�zÑ"Ô"ð 		:ð 		:ˆAàjÐjÐjÐjÐjÐjÐDTÐjÑjÔjˆKå�;ÑÔ 1Ò$Ð$Ý!¥$ {×'8Ò'8Ñ':Ô':Ñ";Ô";Ñ<Ô<‘
��UØ˜&’=�= T×%6Ò%6°uÑ%=Ô%=�=Ø—O’O D×$9Ò$9¸%Ñ$@Ô$@ÑAÔAÐAØØ�OŠO˜DŸOšO¨KÑ8Ô8Ñ9Ô9Ð9Ð9Ø˜9 hÐ/Ð/Ð/r(   r}   r   c                ó’   — t          | t          t          f¦  «        o+t          | ¦  «        dk    ot	          d„ | D ¦   «         ¦  «        S )zVWhether a single input is a text pair, i.e. cross-encoder ``(query, document)`` input.r<   c              3  ó@   K  — | ]}t          |t          ¦  «        V — Œd S ru   )r@   r   )rw   Úparts     r&   ry   z.InputFormatter.is_text_pair.<locals>.<genexpr><  s/   è è € ÐKtÐKtÐfjÍJÐW[Õ]`ÑLaÔLaÐKtÐKtÐKtÐKtÐKtÐKtr(   )r@   rA   rB   rC   r�   )r}   s    r&   r²   zInputFormatter.is_text_pair9  sD   € õ ˜%¥%­ Ñ/Ô/ÐtµC¸±J´JÀ!²OÐtÍÐKtÐKtÐnsÐKtÑKtÔKtÑHtÔHtÐtr(   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.
        r?   c              3  óJ   K  — | ]}|                      d d¦  «        dk    V — ŒdS )rÏ   r   Nrß   )rw   r¸   s     r&   ry   z7InputFormatter.is_text_only_messages.<locals>.<genexpr>Q  s5   è è € ÐRÐRÀ$˜4Ÿ8š8 F¨FÑ3Ô3°vÒ=ÐRÐRÐRÐRÐRÐRr(   FT)rO   r@   r   rB   rŸ   )rÚ   r¹   r§   r?   s       r&   Úis_text_only_messagesz$InputFormatter.is_text_only_messages>  sž   € ð 'ð 		!ð 		!ˆHØ#ð !ð !�Ø!Ÿ+š+ iÑ0Ô0�Ý˜g¥sÑ+Ô+ð ØÝ˜g¥tÑ,Ô,ð !ÝÐRÐRÈ'ÐRÑRÔRÑRÔRð %Ø$˜u˜u˜uð%ð !˜5˜5˜5ð!ð ˆ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ˆ|r†t          |¦  «        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.
        r>   r?   zInvalid message format: z. Skipping.r   r   r=   r   z;Cannot convert structured message to flat format: contains z# content items. Keeping structured.r‘   ©rÏ   r   )	rµ   rù   r@   rB   rD   r�   rC   rf   r   )r•   r¹   Ú
normalizedr§   r?   Úis_currently_structureds         r&   Únormalize_messagesz!InputFormatter.normalize_messagesW  sÅ  € ð ˆ
Øð 	+ñ 	+ˆGØ˜WÐ$Ð$¨	¸Ð(@Ð(@Ý—’ÐN¸'ÐNÐNÐNÑOÔOÐOØà˜iÔ(ˆGÝ&0°½$Ñ&?Ô&?Ð&lÀGÐ&lÕPZÐ[bÐcdÔ[eÕgkÑPlÔPlÐ#àÔ" fÒ,Ð,Ð1HÐ,Ý�w‘<”< 1Ò$Ð$¨°7¸1´:Ð)=Ð)=Ø×%Ò%Ð&P¨Ð&P°)¸WÀQ¼ZÈÔ=OÐ&PÐ&PÑQÔQÐQÐQå—N’NðVÝ$'¨¡L¤LðVð Vð Vñô ð ð ×%Ò% gÑ.Ô.Ð.Ð.ØÔ$¨Ò4Ð4Ð=TÐ4Ý˜g¥sÑ+Ô+ð /Ø×%Ò%Ð&a¨Ð&a°)ÀvÐW^Ð>_Ð>_Ð=`Ð&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æ   rv   ©rw   Úmessage_listr  s     €r&   r~   z=InputFormatter.prepend_prompt_to_messages.<locals>.<listcomp>‹  s)   ø€ ÐhÐhÐhÈ|˜h°6Ð:Ð:Ð;¸lÑJÐhÐhÐhr(   c                ó*   •— g | ]}d d‰dœgdœg|z   ‘ŒS )r  r   r
  ræ   rv   r  s     €r&   r~   z=InputFormatter.prepend_prompt_to_messages.<locals>.<listcomp>Œ  sE   ø€ ð 
ð 
ð 
àð °VÀVÐ,LÐ,LÐ+MÐNÐNÐOÐR^Ñ^ð
ð 
ð 
r(   )r�   )r•   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   r=   N)r@   r   rf   rB   )r•   r  r  Úresultr   s        r&   Úprepend_prompt_to_textsz&InputFormatter.prepend_prompt_to_texts‘  s   € ð ˆØð 	Cð 	CˆDÝ˜$¥Ñ$Ô$ð CØ—’˜f t™mÑ,Ô,Ð,Ð,à—’˜v¨¨Q¬Ñ/Ð0µ4¸¸Q¸R¸R¼±>´>ÑAÑBÔBÐBÐBØˆr(   )r‹   NN)rŒ   r   r�   r   rŽ   r�   r    rK   )r    r—   )r¡   r¢   r    r£   ru   )r¿   rÀ   r    rÁ   )rÚ   rÛ   r    r!   )r¥   rã   r    rä   )rñ   )rò   ró   r>   r   r    rä   )r®   r   rû   rD   r    rü   )r}   r   r    r!   )r¹   rä   r    rä   )r¹   rÛ   r  r   r    rÛ   )r  r  r  r   r    r  )rÐ   Ú
__module__Ú__qualname__Ú__doc__r–   r”   r¾   rÙ   râ   r±   r­   r  Ústaticmethodr²   r  r  r  r  rv   r(   r&   rŠ   rŠ   ã   si  € € € € € ðð ð< )/ØØ6:ð1ð 1ð 1ð 1ð 1ð  ð  ð  ð  ðDoAð oAð oAð oAðb*ð *ð *ð *ð *ðXoð oð oð oð%
ð %
ð %
ð %
ðN
ð 
ð 
ð 
ð 
ð<0ð 0ð 0ð 0ð: ðuð uð uñ „\ðuð ðð ð ñ „\ðð0%ð %ð %ð %ðN
ð 
ð 
ð 
ð&ð ð ð ð ð r(   rŠ   úSingleInput | PairInput | AnyrŽ   r�   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�?\   d| v r: t          dt          |                      ¦   «         t          ¬¦  «        › �¦  «        ‚ xt          d˜ x��\   | �r t          |                      ¦   «         ¦  «        t          z
  }|rŽg }d|v r|                     d¦  «         d|v r|                     d¦  «         |rdd                     |¦  «        z   nd}t          dt          |t          ¬¦  «        › dt          t          ¦  «        › d|› �¦  «        ‚t#          | ¦  «        dk    rt%          t'          | ¦  «        ¦  «        S 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 t5          | ¦  «        j        › d!�¦  «        ‚)"ah  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
        with 2+ keys. A 1-key dict like ``{"image": pil}`` collapses to the bare modality string.

    Raises:
        ValueError: If the input type/structure is not recognized.
    NÚimagerM   r_   rv   r   r<   r>   r?   r§   r   rT   rG   r`   zuDict input with 'array' key must also include 'sampling_rate' (for audio) or 'video_metadata' (for video). Got keys: ©rÓ   a  To attach per-sample video metadata, pass the video itself as a dict, and keep processor options in processing_kwargs, e.g.:
{"video": {"array": frames, "video_metadata": {"fps": 15, "total_num_frames": 3}}}
processing_kwargs={"video": {"do_sample_frames": False}}zzTo attach the sampling rate, pass the audio itself as a dict, e.g.:
{"audio": {"array": waveform, "sampling_rate": 16000}}r#   z

Ú z;Multimodal dict input contains unrecognized modality keys: z. Expected keys from: ú.r=   z-Empty dict input is not a valid input sample.)r=   r<   é   )é   é   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)ÚPILImager@   r   r   r   r4   r7   r9   rD   rB   r.   Úsortedr°   r³   r	   rf   rÍ   rC   rö   r÷   rA   ÚnpÚndarrayÚtorchÚTensorÚndimrÏ   rÐ   )r:   rŽ   Úinvalid_keysÚhintsÚhints        r&   r¯   r¯   ©  s!  € õ. Ð¥
¨6µ8Ñ <Ô <ÐØˆwåÐ¥J¨vµ|Ñ$DÔ$DÐØˆwåÐ¥J¨vµ|Ñ$DÔ$DÐØˆwà
Ø�SˆUˆUˆUˆU‰UÕ*¨6Ñ2Ô2ˆUˆUØ#Ð/°GÐCWÐ4WÐ4WØ�vØ�7ð ð �SˆUˆUˆUˆU‰UÕ*¨6Ñ2Ô2ˆUˆUØ#Ð/°GÐCWÐ4WÐ4WØ�vØ�7ð ð �SˆUˆUˆUˆU‰UÕ*¨6Ñ2Ô2ˆUˆUØ#Ð/°GÐCWÐ4WÐ4WØ�vØ�7ð ð 5ˆU�SˆUˆUˆUˆU‰UˆUˆU�^�^�^�^�^’^�^‘^•c�e�e�e�e‘e�S˜U˜U˜U˜U™U˜U˜U˜U n n n n n¢n n¡n¥s u u u u¡u­c¨e¨e¨e¨e©e¨e¨e¨e¨e¨e¨e¨eØ�6Ø�TˆVˆVˆVˆV‰V�v Ð'Ð'¨I¸Ð,?Ð,?Ð,?Ø�9ð à�TˆVˆVˆVˆV‰V�vˆV¥*¨V°A¬Y½Ñ"=Ô"=ˆVÀ&ÈFÐSTÌIÐBUÐBUÐZcÐgmÐnoÔgpÐZpÐZpÐZpØ�9ð à�TˆVˆVˆVˆV‰V�w &Ð(Ð(¨_ÀÐ-FÐ-FÐ-FØ�7ð à�TˆVˆVˆVˆV‰V�w &Ð(Ð(Ð-=ÀÐ-GÐ-GÐ-GØ�7ð à�TˆVˆVˆVˆV‰V�w &Ð(Ð(Ð(Ýð>å# F§K¢K¡M¤MµsÐ;Ñ;Ô;ð>ð >ñô ð ð ð �TˆVˆVˆV‰V‰V�v‰VˆVõ ˜vŸ{š{™}œ}Ñ-Ô-Õ0DÑDˆLØð ð �Ø# |Ð3Ð3Ø—L’LðSñô ð ð # lÐ2Ð2Ø—L’LðQñô ð ð 6;ÐB˜˜fŸkšk¨%Ñ0Ô0Ñ0Ð0À�Ý ðQÕRXÐYeÕknÐRoÑRoÔRoð Qð QÝ+1Õ2FÑ+GÔ+GðQð QØJNðQð Qñô ð õ �6‰{Œ{˜aÒÐÝ�D ™LœLÑ)Ô)Ð)å� §¢¡¤Ñ.Ô.Ñ/Ô/Ð/ð; ð< �TˆVˆVˆVˆV‰VˆVÝÐLÑMÔMÐMð à�RŒZˆ\ˆ\ˆ\ˆ\‰\ˆ\ˆ\˜N�EœL˜N˜N˜N˜N™N˜N˜N˜N˜N˜NØŒ{˜fÐ$Ð$Ø�wØ” Ò!Ð!Ø�wØ” Ð&Ð&Ø�wå ðQ¸&¼+ð Qð Qð Qñô ð ð ÝðY­4°©<¬<Ô+@ð Yð Yð Yñô ð r(   r[   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¯   ©rw   r:   rŽ   s     €r&   rà   z'infer_batch_modality.<locals>.<setcomp>-  s(   ø€ ÐjÐjÐjÐX^•. Ð>RÐSÑSÔSÐjÐjÐjr(   r=   r§   )rC   r´   )r[   rŽ   r»   s    ` r&   Úinfer_batch_modalityr8    sQ   ø€ ð$ ð ØˆvØjÐjÐjÐjÐbiÐjÑjÔj€JÝ" :™œ°!Ò3Ð3ˆ:�>Š>ÑÔÐ¸ÐBr(   r®   c                óZ   — t          | t          ¦  «        rd                     | ¦  «        S | S )zSFormat a modality for display, e.g. ``("text", "image")`` becomes ``"text+image"``.ú+)r@   rA   rÍ   )r®   s    r&   Úformat_modalityr;  1  s+   € å�(�EÑ"Ô"ð "Ø�xŠx˜Ñ!Ô!Ð!Ø€Or(   r¡   úlist[Modality]Úsourcer   c                ól  ‡— d                      d„ ‰D ¦   «         ¦  «        }|dk    �r	 ˆfd„| D ¦   «         }n%# t          t          f$ r t          ¦   «         }Y nw xY w|dhk    rt          d|› d|› d�¦  «        ‚d|v rt          d|› d|› d�¦  «        ‚|r¡d                      d	„ t	          |t
          ¬
¦  «        D ¦   «         ¦  «        }d„ |D ¦   «         }t	          ˆfd„|D ¦   «         ¦  «        }|r/t          d|› d|› dd                      |¦  «        › d|› d�	¦  «        ‚t          d|› d|› d�¦  «        ‚t          |t          ¦  «        rDt          ˆfd„|D ¦   «         ¦  «        r)t          d|› dd                      |¦  «        › d�¦  «        ‚t          dt          |¦  «        › d|› d|› d�¦  «        ‚)a¼  Raise a clear ``ValueError`` explaining why ``modality`` is not supported.

    Shared by :meth:`BaseModel.preprocess` and :meth:`Transformer.preprocess` so both raise the
    same, accurate guidance. ``source`` is a human-readable description of what rejected the input,
    e.g. ``"SentenceTransformer model"`` or ``"Transformer module"``.

    Args:
        inputs: The original batch of inputs, re-inspected per sample to distinguish explicit
            chat-style ``"message"`` inputs from inferred mixed-modality batches (both collapse to
            the ``"message"`` modality at the batch level).
        modality: The inferred (and unsupported) batch modality.
        supported_modalities: The modalities the source actually supports.
        source: Human-readable name of the rejecting component, used verbatim in the message.

    Raises:
        ValueError: Always, with a message tailored to the specific unsupported-modality scenario.
    z, c              3  ó4   K  — | ]}t          |¦  «        V — Œd S ru   ©r;  ©rw   Úms     r&   ry   z3raise_unsupported_modality_error.<locals>.<genexpr>O  s*   è è € ÐOÐO°Q�o¨aÑ0Ô0ÐOÐOÐOÐOÐOÐOr(   r§   c                ó2   •— h | ]}t          |‰¬ ¦  «        ’ŒS r5  r6  r7  s     €r&   rà   z3raise_unsupported_modality_error.<locals>.<setcomp>V  s4   ø€ ð 0ð 0ð 0ØV\•˜vÐ<PÐQÑQÔQð0ð 0ð 0r(   zThis zy does not support chat-style 'message' inputs (dicts or lists of dicts with 'role' and 'content'). Supported modalities: r%  z§ does not support chat-style 'message' inputs (dicts or lists of dicts with 'role' and 'content'), which this batch mixes with other modalities. Supported modalities: c              3  ó4   K  — | ]}t          |¦  «        V — Œd S ru   r@  rA  s     r&   ry   z3raise_unsupported_modality_error.<locals>.<genexpr>j  s*   è è € Ð#oÐ#o¸1¥O°AÑ$6Ô$6Ð#oÐ#oÐ#oÐ#oÐ#oÐ#or(   r#  c                óL   — h | ]!}t          |t          ¦  «        r|n|fD ]}|’ŒŒ"S rv   r{   )rw   rB  r  s      r&   rà   z3raise_unsupported_modality_error.<locals>.<setcomp>m  s?   € ÐqÐqÐq¨ÕQ[Ð\]Õ_dÑQeÔQeÐLoÈAÈAÐlmÐkoÐqÐqÀ4˜tÐqÐqÐqÐqr(   c              3  ó$   •K  — | ]
}|‰v¯|V — Œd S ru   rv   ©rw   r  rŽ   s     €r&   ry   z3raise_unsupported_modality_error.<locals>.<genexpr>n  s.   øè è € Ð fÐ f¨$ÀTÐQeÐEeÐEe ÐEeÐEeÐEeÐEeÐ fÐ fr(   z&This batch mixes multiple modalities (z), but this z does not support z. Supported modalities: z), which this zZ cannot encode in a single batch. Encode each modality separately (one call per modality).c              3  ó    •K  — | ]}|‰v V — Œ	d S ru   rv   rG  s     €r&   ry   z3raise_unsupported_modality_error.<locals>.<genexpr>{  s)   øè è € Ð*]Ð*]ÈD¨4Ð3GÐ+GÐ*]Ð*]Ð*]Ð*]Ð*]Ð*]r(   z
 supports rN   zr individually, but cannot combine them in a single input. Encode each modality separately (one call per modality).z
Modality 'z' is not supported by this )	rÍ   r.   Ú	TypeErrorr³   r*  r;  r@   rA   r�   )	r¡   r®   rŽ   r=  Úsupported_strÚsample_modalitiesÚpresent_strÚbase_modalitiesÚunsupporteds	     `      r&   Ú raise_unsupported_modality_errorrO  8  s  ø€ ð. —I’IÐOÐOÐ:NÐOÑOÔOÑOÔO€Mà�9ÒÑð	&ð0ð 0ð 0ð 0Ø`fð0ñ 0ô 0ÐÐøõ �IÐ&ð 	&ð 	&ð 	&Ý #¡¤ÐÐÐð	&øøøð   Ò+Ð+ÝðQ˜ð Qð QØ@MðQð Qð Qñô ð ð Ð)Ð)Ð)õ ðt˜ð tð tØcpðtð tð tñô ð ð ð 	ØŸ)š)Ð#oÐ#oÅÐGXÕ^mÐ@nÑ@nÔ@nÐ#oÑ#oÔ#oÑoÔoˆKð rÐqÐ->ÐqÑqÔqˆOÝ Ð fÐ fÐ fÐ f°/Ð fÑ fÔ fÑfÔfˆKØð Ý ðd¸[ð dð dÐV\ð dð dØ#'§9¢9¨[Ñ#9Ô#9ðdð dØS`ðdð dð dñô ð õ ðf¸ð fð fÐTZð fð fð fñô ð õ �(�EÑ"Ô"ð 
¥sÐ*]Ð*]Ð*]Ð*]ÐT\Ð*]Ñ*]Ô*]Ñ']Ô']ð 
Ýðh�Fð hð h g§l¢l°8Ñ&<Ô&<ð hð hð hñ
ô 
ð 	
õ
 ð	2•_ XÑ.Ô.ð 	2ð 	2È6ð 	2ð 	2Ø!.ð	2ð 	2ð 	2ñô ð s   ©8 ¸AÁA)r   r   r    r!   )r   r   r)   r*   r    r!   )r:   r   r    r!   )rG   rH   rI   rJ   r    rK   )rR   r
   rI   rJ   r    r   )r]   r   rI   rJ   r    r   )rq   rr   rI   rJ   r    rK   ru   )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   )7r  Ú
__future__r   rÑ   Úloggingr0   Úcollectionsr   Útypingr   r   r   Úurllib.parser   rZ   r+  r-  Ú)sentence_transformers.base.modality_typesr	   r
   r   r   r   r   r   Ú	PIL.Imager   r)  ÚImportErrorÚtorchcodec.decodersr   r   ÚOSErrorÚRuntimeErrorÚ	getLoggerrÐ   rµ   r�   rÌ   rË   r'   r2   r4   r7   r9   rF   rQ   r\   rp   rˆ   rŠ   r¯   r8  r;  rO  rv   r(   r&   ú<module>r\     sC  ðØ GÐ Gà "Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø #Ð #Ð #Ð #Ð #Ð #Ø )Ð )Ð )Ð )Ð )Ð )Ð )Ð )Ð )Ð )Ø !Ð !Ð !Ð !Ð !Ð !à Ð Ð Ð Ø €€€ðð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ðØ+Ð+Ð+Ð+Ð+Ð+Ð+øØð ð ð Ø€H€H€HðøøøðØ>Ð>Ð>Ð>Ð>Ð>Ð>Ð>Ð>øØ�W˜lÐ+ð ð ð Ø€LØ€L€L€Lðøøøð 
ˆÔ	˜8Ñ	$Ô	$€ð
 ØØØð	%ð %Ð !ð #€
ð TÐ ðHð Hð Hð Hð
	Fð 	Fð 	Fð 	Fðdð dð dð dðð ð ð ð$Rð Rð Rð Rð
ð ð ð ð*Dð Dð Dð Dð ð ð ð ð"ð ð ð ð6)
ð )
ð )
ð )
ðXCð Cð Cð Cð Cñ Cô Cð CðP 37ðmð mð mð mð mðd 37ðCð Cð Cð Cð Cð0ð ð ð ðLð Lð Lð Lð Lð Ls$   ÁA ÁAÁAÁA$ Á$A3Á2A3