U
    DAf                     @   s   d dl Z d dlZd dlmZmZmZmZmZ d dlZ	d dl	m
Z
mZ d dlmZ d dlmZ d dlmZmZmZ d dlmZmZmZmZ G dd	 d	eZeG d
d dZdS )    N)AnyCallableDictOptionalSet)TemplateSyntaxErrormeta)SandboxedEnvironment)	TypeAlias)	componentdefault_from_dictdefault_to_dict)deserialize_callabledeserialize_typeserialize_callableserialize_typec                   @   s   e Zd ZdZdS )OutputAdaptationExceptionzAException raised when there is an error during output adaptation.N)__name__
__module____qualname____doc__ r   r   Q/tmp/pip-unpacked-wheel-z752163x/haystack/components/converters/output_adapter.pyr      s   r   c                   @   s~   e Zd ZdZdeeeeeef  dddZ	dd Z
eeef dd	d
Zeeeef d dddZeee dddZdS )OutputAdaptera  
    Adapts output of a Component using Jinja templates.

    Usage example:
    ```python
    from haystack import Document
    from haystack.components.converters import OutputAdapter

    adapter = OutputAdapter(template="{{ documents[0].content }}", output_type=str)
    documents = [Document(content="Test content"]
    result = adapter.run(documents=documents)

    assert result["output"] == "Test content"
    ```
    Ntemplateoutput_typecustom_filtersc           	   
   C   s   |pi | _ t }ttjjd| _z| j| || _W n8 t	k
rp } zt
d| d| |W 5 d}~X Y nX | j  D ]\}}|| jj|< q|| | j}|| tj| fdd |D  tj| fd|i || _dS )aK  
        Create an OutputAdapter component.

        :param template:
            A Jinja template that defines how to adapt the input data.
            The variables in the template define the input of this instance.
            e.g.
            With this template:
            ```
            {{ documents[0].content }}
            ```
            The Component input will be `documents`.
        :param output_type:
            The type of output this instance will return.
        :param custom_filters:
            A dictionary of custom Jinja filters used in the template.
        )Z	undefinedzInvalid Jinja template 'z': Nc                 S   s   i | ]
}|t qS r   )r   ).0varr   r   r   
<dictcomp>N   s      z*OutputAdapter.__init__.<locals>.<dictcomp>output)r   setr	   jinja2runtimeZStrictUndefined_envparser   r   
ValueErroritemsfilters_extract_variablesupdater   Zset_input_typesZset_output_typesr   )	selfr   r   r   Zinput_typesenamefilter_funcZroute_input_namesr   r   r   __init__(   s    
(
zOutputAdapter.__init__c              
   K   s   |st d| j D ]\}}|| jj|< qi }zj| j| j}|jf |}t|t	j
jrptd| j d| tt t|}W 5 Q R X ||d< W n@ tk
r } z"td| j d| d| |W 5 d}~X Y nX |S )	ab  
        Renders the Jinja template with the provided inputs.

        :param kwargs:
            Must contain all variables used in the `template` string.
        :returns:
            A dictionary with the following keys:
            - `output`: Rendered Jinja template.

        :raises OutputAdaptationException: If template rendering fails.
        z,No input data provided for output adaptationz#Undefined variable in the template z
; kwargs: r!   zError adapting z with z: N)r'   r   r(   r%   r)   Zfrom_stringr   render
isinstancer#   r$   	Undefinedr   
contextlibsuppress	Exceptionastliteral_eval)r,   kwargsr.   r/   Zadapted_outputsZadapted_output_templateZoutput_resultr-   r   r   r   runR   s     0zOutputAdapter.run)returnc                 C   s,   dd | j  D }t| | jt| j|dS )z{
        Serializes the component to a dictionary.

        :returns:
            Dictionary with serialized data.
        c                 S   s   i | ]\}}|t |qS r   )r   )r   r.   r/   r   r   r   r    }   s      z)OutputAdapter.to_dict.<locals>.<dictcomp>r   )r   r(   r   r   r   r   )r,   Z
se_filtersr   r   r   to_dictv   s       zOutputAdapter.to_dict)datar;   c                 C   sX   | di }t|d |d< | di  D ] \}}|r@t|nd|d |< q,t| |S )z
        Deserializes the component from a dictionary.

        :param data:
            The dictionary to deserialize from.
        :returns:
            The deserialized component.
        Zinit_parametersr   r   N)getr   r(   r   r   )clsr=   Zinit_paramsr.   r/   r   r   r   	from_dict   s
    
zOutputAdapter.from_dict)envr;   c                 C   s   | | j}t|S )z
        Extracts all variables from a list of Jinja template strings.

        :param env: A Jinja native environment.
        :return: A set of variable names extracted from the template strings.
        )r&   r   r   Zfind_undeclared_variables)r,   rA   r7   r   r   r   r*      s    z OutputAdapter._extract_variables)N)r   r   r   r   strr
   r   r   r   r0   r:   r   r<   classmethodr@   r	   r   r*   r   r   r   r   r      s    *$r   )r7   r4   typingr   r   r   r   r   Zjinja2.runtimer#   r   r   Zjinja2.sandboxr	   Ztyping_extensionsr
   Zhaystackr   r   r   Zhaystack.utilsr   r   r   r   r6   r   r   r   r   r   r   <module>   s   