
    9|h~)                     *   d Z ddlZddlmZ ddlmZ ddlmZ ddlm	Z	m
Z
mZmZmZmZ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#  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'y)zo
Ensemble retriever that ensemble the results of
multiple retrievers by using weighted  Reciprocal Rank Fusion
    N)defaultdict)Hashable)chain)	AnyCallableDictIterableIteratorListOptionalTypeVarcast)#AsyncCallbackManagerForRetrieverRunCallbackManagerForRetrieverRun)Document)BaseRetrieverRetrieverLike)RunnableConfig)ensure_configpatch_config)ConfigurableFieldSpecget_unique_config_specs)model_validatorTH)bounditerablekeyreturnc              #   r   K   t               }| D ]$  } ||      x}|vs|j                  |       | & yw)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        \/var/www/html/test/engine/venv/lib/python3.12/site-packages/langchain/retrievers/ensemble.pyunique_by_keyr'   (   s>      5D QKA$HHQKGs   77c            
          e Zd ZU dZee   ed<   ee   ed<   dZe	ed<   dZ
ee   ed<   edee   fd	       Z ed
      edeeef   defd              Z	 ddedee   dedee   fdZ	 ddedee   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e   dee   fdZdddededee   dee   fdZdeee      dee   fdZy)EnsembleRetrieverae  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.
        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   B   K   | ]  }|j                   D ]  }|   y wN)config_specs).0	retrieverspecs      r&   	<genexpr>z1EnsembleRetriever.config_specs.<locals>.<genexpr>Q   s-      '
i>T>T'
6:D'
'
s   )r   r*   )selfs    r&   r2   zEnsembleRetriever.config_specsN   s"     ' '
"&//'
 
 	
    before)modevaluesc                 \    |j                  d      st        |d         }d|z  g|z  |d<   |S )Nr+   r*      )getlen)clsr;   n_retrieverss      r&   set_weightszEnsembleRetriever.set_weightsU   s;     zz)$vl34L!"\!1 2\ AF9r8   inputconfigkwargsc                    ddl m} t        |      }|j                  |j	                  d      d |j	                  dd      |j	                  dg       | j
                  |j	                  di       | j                        } |j                  d |fd	|j	                  d
      xs | j                         i|}	 | j                  |||      } |j                  |fi | |S # t        $ r}|j                  |       |d }~ww xY w)Nr   )CallbackManager	callbacksverboseFtagsmetadatarI   inheritable_tags
local_tagsinheritable_metadatalocal_metadatanamerun_namerun_managerrD   )langchain_core.callbacksrG   r   	configurer>   rJ   rK   on_retriever_startget_namerank_fusionon_retriever_end	Exceptionon_retriever_error)	r7   rC   rD   rE   rG   callback_managerrT   resultr$   s	            r&   invokezEnsembleRetriever.invoke]   s    	=v&*44JJ{#JJy%0#ZZ3yy!'J!;== 5 
 :&99
 J':4==?
 	

	%%eV%TF
 )K(( M  	**1-G	s   5C 	C?'C::C?c                 Z  K   ddl m} t        |      }|j                  |j	                  d      d |j	                  dd      |j	                  dg       | j
                  |j	                  di       | j                        } |j                  d |fd	|j	                  d
      xs | j                         i| d {   }	 | j                  |||       d {   } |j                  |fi | d {    |S 7 >7 #7 
# t        $ r!}|j                  |       d {  7   |d }~ww xY ww)Nr   )AsyncCallbackManagerrH   rI   FrJ   rK   rL   rQ   rR   rS   )rU   ra   r   rV   r>   rJ   rK   rW   rX   arank_fusionrZ   r[   r\   )	r7   rC   rD   rE   ra   r]   rT   r^   r$   s	            r&   ainvokezEnsembleRetriever.ainvoke~   sK     	Bv&/99JJ{#JJy%0#ZZ3yy!'J!;== : 
 @,??
 J':4==?
 	
 
	,,;v -  F /+..   M%
	  	00333G	sf   B7D+9C8:D+?C> C:C> D+1C<2D+:C> <D+>	D(D#DD##D((D+queryrT   c                *    | j                  ||      }|S )z
        Get the relevant documents for a given query.

        Args:
            query: The query to search for.

        Returns:
            A list of reranked documents.
        )rY   r7   rd   rT   fused_documentss       r&   _get_relevant_documentsz)EnsembleRetriever._get_relevant_documents   s    " **5+>r8   c                F   K   | j                  ||       d{   }|S 7 w)z
        Asynchronously get the relevant documents for a given query.

        Args:
            query: The query to search for.

        Returns:
            A list of reranked documents.
        N)rb   rf   s       r&   _aget_relevant_documentsz*EnsembleRetriever._aget_relevant_documents   s)     " !% 1 1% EE Fs   !!)rD   c                   t        | j                        D cg c]8  \  }}|j                  |t        ||j	                  d|dz                      : }}}t        t        |            D ]B  }||   D cg c].  }t        |t              rt        t        t        |            n|0 c}||<   D | j                  |      }|S c c}}w c c}w )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.
        
retriever_r=   tagrH   page_content)	enumerater*   r_   r   	get_childranger?   
isinstancestrr   r   weighted_reciprocal_rank	r7   rd   rT   rD   ir4   retriever_docsdocrg   s	            r&   rY   zEnsembleRetriever.rank_fusion   s    4 !*$// :
 9 k&;&;*QQRUG@T&;&U
 
 s>*+ 	A *!,! :DC9Md3n5SVV!N1	 77G)
!s   =C73Cc                  K   t        j                  t        | j                        D cg c]8  \  }}|j	                  |t        ||j                  d|dz                      : c}}  d{   }t        t        |            D ]4  }||   D cg c]   }t        |t              st        |      n|" c}||<   6 | j                  |      }|S c c}}w 7 hc c}w w)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.
        rl   r=   rm   ro   Nrp   )asynciogatherrr   r*   rc   r   rs   rt   r?   ru   r   rw   rx   s	            r&   rb   zEnsembleRetriever.arank_fusion   s     &  '~~ %.doo$>	 !Ay !! "-"7"7jQ<P"7"Q	 
 
 s>*+ 	A *!,! 3=S(2Kc*QTT!N1	 77G-	
!s.   (C=C
'C/C0"C%C7"CC	doc_listsc                     t        |      t         j                        k7  rt        d      t        t              t        | j                        D ]f  \  }}t        |d      D ]Q  \  }} j                  |j                  n|j                   j                     xx   || j                  z   z  z  cc<   S h t        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:
            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.r=   )startc                 f    j                   | j                  S | j                  j                      S r1   r.   rq   rK   )r{   r7   s    r&   <lambda>z<EnsembleRetriever.weighted_reciprocal_rank.<locals>.<lambda>F  s4    {{* $$  dkk2 r8   Tc                 p    j                   | j                     S | j                  j                         S r1   r   )r{   	rrf_scorer7   s    r&   r   z<EnsembleRetriever.weighted_reciprocal_rank.<locals>.<lambda>M  s5    I$(KK$7   =@\\$++=V r8   )reverser   )r?   r+   
ValueErrorr   floatziprr   r.   rq   rK   r-   r   from_iterablesortedr'   )	r7   r   doc_listweightrankr{   all_docssorted_docsr   s	   `       @r&   rw   z*EnsembleRetriever.weighted_reciprocal_rank   s     y>S..N  '2%&8	 #It|| < 	.Hf&xq9 .	c  ;;. (( \\$++6	 tdff}-. .	. &&y1 
 r8   r1   ) __name__
__module____qualname____doc__r   r   __annotations__r   r-   intr.   r   rv   propertyr   r2   r   classmethodr   r   rB   r   r   r_   rc   r   rh   r   rj   rY   rb   rw    r8   r&   r)   r)   9   s    ]##%[AsK FHSM 
d#89 
 
 (#c3h C   $ >B"*>":MP	hD >B!!"*>":!MP!	h!F 4	
 
h* 9	
 
h4 ,0'' 4'
 (' 
h'\ ,0** 9*
 (* 
h*X1d8n-1	h1r8   r)   )(r   r}   collectionsr   collections.abcr   	itertoolsr   typingr   r   r   r	   r
   r   r   r   r   rU   r   r   langchain_core.documentsr   langchain_core.retrieversr   r   langchain_core.runnablesr   langchain_core.runnables.configr   r   langchain_core.runnables.utilsr   r   pydanticr   r   r   r'   r)   r   r8   r&   <module>r      s   
  # $ 
 
 
 . B 3 G %CLCx HQK hsAv.> 8A; "X Xr8   