
    m
ir,                     P   d Z ddlZddlmZ ddlmZmZmZmZ ddl	m
Z
 ddlmZmZ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 ddlmZmZ ddlmZmZ ddlm Z  ddl!m"Z"  ed          Z# ede          Z$dee#         dee#ge$f         dee#         fdZ% G d de          Z&dS )zEnsemble Retriever.

Ensemble retriever that ensemble the results of
multiple retrievers by using weighted  Reciprocal Rank Fusion.
    N)defaultdict)CallableHashableIterableIterator)chain)AnyTypeVarcast)#AsyncCallbackManagerForRetrieverRunCallbackManagerForRetrieverRun)Document)BaseRetrieverRetrieverLike)RunnableConfig)ensure_configpatch_config)ConfigurableFieldSpecget_unique_config_specs)model_validator)overrideTH)bounditerablekeyreturnc              #      K   t                      }| D ]*} ||          x}|vr|                    |           |V  +dS )a  Yield unique elements of an iterable based on a key function.

    Args:
        iterable: The iterable to filter.
        key: A function that returns a hashable key for each element.

    Yields:
        Unique elements of the iterable based on the key function.
    N)setadd)r   r   seeneks        C:\Users\Dell Inspiron 16\Desktop\tws\AgrotaPowerBi\back-agrota-powerbi\mcp-client-agrota\venv\Lib\site-packages\langchain_classic/retrievers/ensemble.pyunique_by_keyr%   $   sZ       55D  QKA$$HHQKKKGGG     c                   .   e Zd ZU dZee         ed<   ee         ed<   dZe	ed<   dZ
edz  ed<   edee         fd	            Z ed
          edeeef         defd                        Ze	 ddededz  dedee         fd            Ze	 ddededz  dedee         fd            Zdededee         fdZdededee         fdZdddedededz  dee         fdZdddedededz  dee         fdZdeee                  dee         fdZdS )EnsembleRetrieveraJ  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.
        id_key: The key in the document's metadata used to determine unique documents.
            If not specified, page_content is used.
    
retrieversweights<   cNid_keyr   c                 >    t          d | j        D                       S )z+List configurable fields for this runnable.c              3   .   K   | ]}|j         D ]}|V  d S N)config_specs).0	retrieverspecs      r$   	<genexpr>z1EnsembleRetriever.config_specs.<locals>.<genexpr>L   sJ       '
 '
i>T'
 '
6:D'
 '
 '
 '
 '
 '
 '
r&   )r   r)   )selfs    r$   r1   zEnsembleRetriever.config_specsI   s4     ' '
 '
"&/'
 '
 '
 
 
 	
r&   before)modevaluesc                    |                     d          }|s#t          |d                   }d|z  g|z  |d<   |S |d         }t          |          t          |          k    r2dt          |           dt          |           d}t          |          t          d |D                       sd}t          |          |S )	Nr*   r)      z7Length of weights must match number of retrievers (got z weights for z retrievers).c              3   "   K   | ]
}|d k    V  dS )r   N )r2   ws     r$   r5   z1EnsembleRetriever._set_weights.<locals>.<genexpr>b   s&      **Q1q5******r&   z7At least one ensemble weight must be greater than zero.)getlen
ValueErrorany)clsr9   r*   n_retrieversr)   msgs         r$   _set_weightszEnsembleRetriever._set_weightsP   s     **Y'' 	vl344L!"\!1 2\ AF9ML)
w<<3z??**RGR R36z??R R R  S//!**'***** 	"KCS//!r&   inputconfigkwargsc                 (   ddl m} t          |          }|                    |                    d          d |                    dd          |                    dg           | j        |                    di           | j                  } |j        d |fd	|                    d
          p|                                 i|}	 | 	                    |||          } |j
        |fi | |S # t          $ r}|                    |            d }~ww xY w)Nr   )CallbackManager	callbacksverboseFtagsmetadatarM   inheritable_tags
local_tagsinheritable_metadatalocal_metadatanamerun_namerun_managerrH   )langchain_core.callbacksrK   r   	configurer?   rN   rO   on_retriever_startget_namerank_fusionon_retriever_end	Exceptionon_retriever_error)	r6   rG   rH   rI   rK   callback_managerrX   resultr"   s	            r$   invokezEnsembleRetriever.invokeh   sc    	=<<<<<v&&*44JJ{##JJy%00#ZZ33y!'J!;!;= 5 
 
 :&9
 
 J'':4==??
 	
 

	%%eV%TTF
 )K(    M  	 	 	**1---	s   C, ,
D6DDc                 \  K   ddl m} t          |          }|                    |                    d          d |                    dd          |                    dg           | j        |                    di           | j                  } |j        d |fd	|                    d
          p|                                 i| d {V }	 | 	                    |||           d {V } |j
        |fi | d {V  |S # t          $ r!}|                    |           d {V   d }~ww xY w)Nr   )AsyncCallbackManagerrL   rM   FrN   rO   rP   rU   rV   rW   )rY   re   r   rZ   r?   rN   rO   r[   r\   arank_fusionr^   r_   r`   )	r6   rG   rH   rI   re   ra   rX   rb   r"   s	            r$   ainvokezEnsembleRetriever.ainvoke   s      	BAAAAAv&&/99JJ{##JJy%00#ZZ33y!'J!;!;= : 
 
 @,?
 
 J'':4==??
 	
 
 
 
 
 
 
 
	,,' -        F /+.          M  	 	 	00333333333	s   D   
D+
D&&D+queryrX   c                .    |                      ||          S )zGet the relevant documents for a given query.

        Args:
            query: The query to search for.
            run_manager: The callback handler to use.

        Returns:
            A list of reranked documents.
        )r]   r6   rh   rX   s      r$   _get_relevant_documentsz)EnsembleRetriever._get_relevant_documents   s      {333r&   c                >   K   |                      ||           d{V S )zAsynchronously get the relevant documents for a given query.

        Args:
            query: The query to search for.
            run_manager: The callback handler to use.

        Returns:
            A list of reranked documents.
        N)rf   rj   s      r$   _aget_relevant_documentsz*EnsembleRetriever._aget_relevant_documents   s0        &&uk:::::::::r&   )rH   c                    fdt          | j                  D             }t          t          |                    D ]}d ||         D             ||<   |                     |          S )ak  Rank fusion.

        Retrieve the results of the retrievers and use rank_fusion_func to get
        the final result.

        Args:
            query: The query to search for.
            run_manager: The callback handler to use.
            config: Optional configuration for the retrievers.

        Returns:
            A list of reranked documents.
        c                     g | ]D\  }}|                     t                              d |dz                                  ES 
retriever_r;   )tag)rL   )rc   r   	get_childr2   ir3   rH   rh   rX   s      r$   
<listcomp>z1EnsembleRetriever.rank_fusion.<locals>.<listcomp>   sx     	
 	
 	
 9 )338LQU8L8L3MM   	
 	
 	
r&   c                 x    g | ]7}t          |t                    rt          t          d |                    n|8S )strpage_content)
isinstancerx   r   r   r2   docs     r$   rv   z1EnsembleRetriever.rank_fusion.<locals>.<listcomp>   sS     ! ! ! <Fc3;O;OXd5#&6&67777UX! ! !r&   )	enumerater)   ranger@   weighted_reciprocal_rankr6   rh   rX   rH   retriever_docsru   s    ```  r$   r]   zEnsembleRetriever.rank_fusion   s    *	
 	
 	
 	
 	
 	
 !*$/ : :	
 	
 	
 s>**++ 	 	A! !)!,! ! !N1 ,,^<<<r&   c                  K   t          j        fdt          | j                  D               d{V }t	          t          |                    D ]}d ||         D             ||<   |                     |          S )az  Rank fusion.

        Asynchronously retrieve the results of the retrievers
        and use rank_fusion_func to get the final result.

        Args:
            query: The query to search for.
            run_manager: The callback handler to use.
            config: Optional configuration for the retrievers.

        Returns:
            A list of reranked documents.
        c                     g | ]D\  }}|                     t                              d |dz                                  ES rp   )rg   r   rs   rt   s      r$   rv   z2EnsembleRetriever.arank_fusion.<locals>.<listcomp>  sx     	 	 	 !Ay !! "-"7"7<PQ<P<P"7"Q"Q   	 	 	r&   Nc                 \    g | ])}t          |t                    st          |           n|*S )ry   )r{   r   r|   s     r$   rv   z2EnsembleRetriever.arank_fusion.<locals>.<listcomp>(  sH     ! ! ! 3=S(2K2KTc****QT! ! !r&   )asynciogatherr~   r)   r   r@   r   r   s    ```  r$   rf   zEnsembleRetriever.arank_fusion  s      *  '~	 	 	 	 	 	 %.do$>$>	 	 	 
 
 
 
 
 
 
 s>**++ 	 	A! !)!,! ! !N1 ,,^<<<r&   	doc_listsc                     t          |          t           j                  k    rd}t          |          t          t                    t          | j        d          D ]U\  }}t          |d          D ]>\  }} j        |j        n|j	         j                 xx         || j
        z   z  z  cc<   ?Vt          j        |          }t          t          | fd          d f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:
            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.F)strictr;   )startNc                 D    j         | j        n| j        j                  S r0   r-   rz   rO   )r}   r6   s    r$   <lambda>z<EnsembleRetriever.weighted_reciprocal_rank.<locals>.<lambda>V  s'    {* $$dk2 r&   Tc                 P    j         | j        n| j        j                           S r0   r   )r}   	rrf_scorer6   s    r$   r   z<EnsembleRetriever.weighted_reciprocal_rank.<locals>.<lambda>]  s'    I$(K$7  S\$+=V r&   )reverser   )r@   r*   rA   r   floatzipr~   r-   rz   rO   r,   r   from_iterablesortedr%   )	r6   r   rE   doc_listweightrankr}   all_docsr   s	   `       @r$   r   z*EnsembleRetriever.weighted_reciprocal_rank0  sR     y>>S....PCS//! '2%&8&8	 #It|E J J J 	. 	.Hf&xq999 . .	c  ;. (( \$+6	   tdf}-.    . &y11         
 
 
 	
r&   r0   ) __name__
__module____qualname____doc__listr   __annotations__r   r,   intr-   rx   propertyr   r1   r   classmethoddictr	   rF   r   r   r   rc   rg   r   rk   r   rm   r]   rf   r   r=   r&   r$   r(   r(   5   s          ]####%[AsKKKFC$J
d#89 
 
 
 X
 _(###$sCx. S    [ $#,  )-" "" %" 	"
 
h" " " X"H  )-& && %& 	&
 
h& & & X&P44 4	4
 
h4 4 4 4$;; 9	;
 
h; ; ; ;. )-(= (= (=(= 4(=
 %(= 
h(= (= (= (=^ )-*= *= *=*= 9*=
 %*= 
h*= *= *= *=X0
X'0
 
h0
 0
 0
 0
 0
 0
r&   r(   )'r   r   collectionsr   collections.abcr   r   r   r   	itertoolsr   typingr	   r
   r   rY   r   r   langchain_core.documentsr   langchain_core.retrieversr   r   langchain_core.runnablesr   langchain_core.runnables.configr   r   langchain_core.runnables.utilsr   r   pydanticr   typing_extensionsr   r   r   r%   r(   r=   r&   r$   <module>r      s     # # # # # # B B B B B B B B B B B B                       . - - - - - B B B B B B B B 3 3 3 3 3 3 G G G G G G G G        % $ $ $ $ $ & & & & & &GCLLGCx   HQK hsAv.> 8A;    "k
 k
 k
 k
 k
 k
 k
 k
 k
 k
r&   