o
    .if%                     @   s   d Z ddlZddlmZmZmZmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZmZ ddlmZ dd	lmZmZ dd
lmZmZ ddlmZmZ G dd deZdS )zp
Ensemble retriever that ensemble the results of 
multiple retrievers by using weighted  Reciprocal Rank Fusion
    N)AnyDictListOptional)Document)dumpd)root_validator)BaseRetrieverRetrieverLike)RunnableConfig)ensure_configpatch_config)ConfigurableFieldSpecget_unique_config_specs)#AsyncCallbackManagerForRetrieverRunCallbackManagerForRetrieverRunc                
   @   sf  e Zd ZU dZee ed< ee ed< dZe	ed< e
dee fddZed	d
deeef deeef fddZ	d$dedee dedee fddZ	d$dedee dedee fddZdededee fddZdededee fddZdddededee dee fddZdddededee dee fdd Zd!eee  dee fd"d#ZdS )%EnsembleRetrievera  Retriever that ensembles the multiple retrievers.

    It uses a rank fusion.

    Args:
        retrievers: A list of retrievers to ensemble.
        weights: A list of weights corresponding to the retrievers. Defaults to equal
            weighting for all retrievers.
        c: A constant added to the rank, controlling the balance between the importance
            of high-ranked items and the consideration given to lower-ranked items.
            Default is 60.
    
retrieversweights<   creturnc                 C   s   t dd | jD S )z+List configurable fields for this runnable.c                 s   s     | ]}|j D ]}|V  qqd S N)config_specs).0	retrieverspec r   V/var/www/html/corbot_env/lib/python3.10/site-packages/langchain/retrievers/ensemble.py	<genexpr>.   s    z1EnsembleRetriever.config_specs.<locals>.<genexpr>)r   r   )selfr   r   r   r   +   s   zEnsembleRetriever.config_specsT)prevaluesc                 C   s,   | dst|d }d| g| |d< |S )Nr   r      )getlen)clsr"   n_retrieversr   r   r   set_weights2   s   
zEnsembleRetriever.set_weightsNinputconfigkwargsc           	   
   K   s   ddl m} t|}|j|dd |dd|dg | j|di | jd}|jt| |fd	|d
i|}z
| j	|||d}W n t
yU } z|| |d }~ww |j|fi | |S )Nr   )CallbackManager	callbacksverboseFtagsmetadatar.   inheritable_tags
local_tagsinheritable_metadatalocal_metadatanamerun_namerun_managerr*   ) langchain_core.callbacks.managerr,   r   	configurer$   r/   r0   on_retriever_startr   rank_fusion	Exceptionon_retriever_erroron_retriever_end)	r    r)   r*   r+   r,   callback_managerr9   resulter   r   r   invoke9   s@   


	
zEnsembleRetriever.invokec           	   
      s   ddl m} t|}|j|dd |dd|dg | j|di | jd}|jt| |fd	|d
i|I d H }z| j	|||dI d H }W n t
y_ } z
||I d H  |d }~ww |j|fi |I d H  |S )Nr   )AsyncCallbackManagerr-   r.   Fr/   r0   r1   r6   r7   r8   )r:   rE   r   r;   r$   r/   r0   r<   r   arank_fusionr>   r?   r@   )	r    r)   r*   r+   rE   rA   r9   rB   rC   r   r   r   ainvokeZ   sF   


	zEnsembleRetriever.ainvokequeryr9   c                C   s   |  ||}|S )z
        Get the relevant documents for a given query.

        Args:
            query: The query to search for.

        Returns:
            A list of reranked documents.
        )r=   r    rH   r9   fused_documentsr   r   r   _get_relevant_documents}   s   z)EnsembleRetriever._get_relevant_documentsc                   s   |  ||I dH }|S )z
        Asynchronously get the relevant documents for a given query.

        Args:
            query: The query to search for.

        Returns:
            A list of reranked documents.
        N)rF   rI   r   r   r   _aget_relevant_documents   s   z*EnsembleRetriever._aget_relevant_documents)r*   c                   sR    fddt | jD }tt|D ]}dd || D ||< q| |}|S )z
        Retrieve the results of the retrievers and use rank_fusion_func to get
        the final result.

        Args:
            query: The query to search for.

        Returns:
            A list of reranked documents.
        c                    6   g | ]\}}| t jd |d  ddqS 
retriever_r#   )tag)r-   )rD   r   	get_childr   ir   r*   rH   r9   r   r   
<listcomp>       z1EnsembleRetriever.rank_fusion.<locals>.<listcomp>c                 S   $   g | ]}t |tst|d n|qS page_content
isinstancer   r   docr   r   r   rU          )	enumerater   ranger%   weighted_reciprocal_rankr    rH   r9   r*   retriever_docsrS   rJ   r   rT   r   r=      s   
zEnsembleRetriever.rank_fusionc                   s`   t j fddt| jD  I dH }tt|D ]}dd || D ||< q| |}|S )z
        Asynchronously retrieve the results of the retrievers
        and use rank_fusion_func to get the final result.

        Args:
            query: The query to search for.

        Returns:
            A list of reranked documents.
        c                    rM   rN   )rG   r   rQ   rR   rT   r   r   rU      rV   z2EnsembleRetriever.arank_fusion.<locals>.<listcomp>Nc                 S   rW   rX   r[   r]   r   r   r   rU      r_   )asynciogatherr`   r   ra   r%   rb   rc   r   rT   r   rF      s   

zEnsembleRetriever.arank_fusion	doc_listsc           
         s   t |t | jkrtdt }|D ]}|D ]}||j qqdd |D t|| jD ]!\}}t|ddD ]\}}|d|| j   }|j  |7  < q7q-t	
 fdddd	}d
d |D   fdd|D }	|	S )a  
        Perform weighted Reciprocal Rank Fusion on multiple rank lists.
        You can find more details about RRF here:
        https://plg.uwaterloo.ca/~gvcormac/cormacksigir09-rrf.pdf

        Args:
            doc_lists: A list of rank lists, where each rank list contains unique items.

        Returns:
            list: The final aggregated list of items sorted by their weighted RRF
                    scores in descending order.
        z<Number of rank lists must be equal to the number of weights.c                 S   s   i | ]}|d qS )g        r   r]   r   r   r   
<dictcomp>  s    z>EnsembleRetriever.weighted_reciprocal_rank.<locals>.<dictcomp>r#   )startc                    s    |  S r   r   )x)rrf_score_dicr   r   <lambda>   s    z<EnsembleRetriever.weighted_reciprocal_rank.<locals>.<lambda>T)keyreversec                 S   s   i | ]}|D ]}|j |qqS r   rY   )r   doc_listr^   r   r   r   rh   $  s
    c                    s   g | ]} | qS r   r   )r   rZ   )page_content_to_doc_mapr   r   rU   '  s    z>EnsembleRetriever.weighted_reciprocal_rank.<locals>.<listcomp>)r%   r   
ValueErrorsetaddrZ   zipr`   r   sortedkeys)
r    rg   all_documentsro   r^   weightrank	rrf_scoresorted_documentssorted_docsr   )rp   rk   r   rb      s2   
z*EnsembleRetriever.weighted_reciprocal_rankr   )__name__
__module____qualname____doc__r   r
   __annotations__floatr   intpropertyr   r   r   r   strr   r(   r   r   r   rD   rG   r   rK   r   rL   r=   rF   rb   r   r   r   r   r      s   
 $
"
#


.
+
r   )r   re   typingr   r   r   r   langchain_core.documentsr   langchain_core.load.dumpr   langchain_core.pydantic_v1r   langchain_core.retrieversr	   r
   langchain_core.runnablesr   langchain_core.runnables.configr   r   langchain_core.runnables.utilsr   r   langchain.callbacks.managerr   r   r   r   r   r   r   <module>   s    