
    h#)                     .   d 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
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! 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IterableIterator)chain)AnyCallableOptional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              #   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/eduruby.in/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e	 ddedee   dedee   fd       Ze	 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>N   s-      '
i>T>T'
6:D'
'
s   )r   r)   )selfs    r%   r1   zEnsembleRetriever.config_specsK   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_weightsR   s;     zz)$vl34L!"\!1 2\ AF9r7   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rH   inheritable_tags
local_tagsinheritable_metadatalocal_metadatanamerun_namerun_managerrC   )langchain_core.callbacksrF   r   	configurer=   rI   rJ   on_retriever_startget_namerank_fusionon_retriever_end	Exceptionon_retriever_error)	r6   rB   rC   rD   rF   callback_managerrS   resultr#   s	            r%   invokezEnsembleRetriever.invokeZ   s    	=v&*44JJ{#JJy%0#ZZ3yy!'J!;== 5 
 :&99
 J':4==?
 	

	%%eV%TF
 )K(( M  	**1-	s   5C 	C>'C99C>c                 X  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   )AsyncCallbackManagerrG   rH   FrI   rJ   rK   rP   rQ   rR   )rT   r`   r   rU   r=   rI   rJ   rV   rW   arank_fusionrY   rZ   r[   )	r6   rB   rC   rD   r`   r\   rS   r]   r#   s	            r%   ainvokezEnsembleRetriever.ainvoke   sK     	Bv&/99JJ{#JJy%0#ZZ3yy!'J!;== : 
 @,??
 J':4==?
 	
 
	,,' -  F /+..   M)
	  	00333	sf   B7D*9C8:D*?C> C:C> D*1C<2D*:C> <D*>	D'D"DD""D''D*queryrS   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.
        )rX   r6   rc   rS   s      r%   _get_relevant_documentsz)EnsembleRetriever._get_relevant_documents   s    " {33r7   c                B   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)ra   re   s      r%   _aget_relevant_documentsz*EnsembleRetriever._aget_relevant_documents   s!     " &&uk::::s   )rC   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rG   page_content)	enumerater)   r^   r   	get_childranger>   
isinstancestrr   r   weighted_reciprocal_rankr6   rc   rS   rC   ir3   retriever_docsdocs           r%   rX   zEnsembleRetriever.rank_fusion   s    6 !*$// :	
 9 )33*QUG8L3M	
 	
 s>*+ 	A *!,! :DC9Md3n5SVV!N1	 ,,^<<'	
!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 fc 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.
        rj   r<   rk   rm   Nrn   )asynciogatherrp   r)   rb   r   rq   rr   r>   rs   r   ru   rv   s           r%   ra   zEnsembleRetriever.arank_fusion   s     &  '~~ %.doo$>	 !Ay !! "-"7"7jQ<P"7"Q	 
 
 s>*+ 	A *!,! 3=S(2Kc*QTT!N1	 ,,^<<)	
!s.   (C=C
'C/C0"C%C7 CC	doc_listsc                     t        |      t         j                        k7  rd}t        |      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 r0   r-   ro   rJ   )ry   r6   s    r%   <lambda>z<EnsembleRetriever.weighted_reciprocal_rank.<locals>.<lambda>F  s4    {{* $$  dkk2 r7   Tc                 p    j                   | j                     S | j                  j                         S r0   r   )ry   	rrf_scorer6   s    r%   r   z<EnsembleRetriever.weighted_reciprocal_rank.<locals>.<lambda>M  s5    I$(KK$7   =@\\$++=V r7   )reverser   )r>   r*   
ValueErrorr   floatziprp   r-   ro   rJ   r,   r   from_iterablesortedr&   )	r6   r}   msgdoc_listweightrankry   all_docsr   s	   `       @r%   ru   z*EnsembleRetriever.weighted_reciprocal_rank   s      y>S..PCS/! '2%&8	 #It|| < 	.Hf&xq9 .	c  ;;. (( \\$++6	 tdff}-. .	. &&y1 
 	
r7   r0   )!__name__
__module____qualname____doc__listr   __annotations__r   r,   intr-   r
   rt   propertyr   r1   r   classmethoddictr   rA   r   r   r   r^   rb   r   rf   r   rh   rX   ra   ru    r7   r%   r(   r(   6   s    ]##%[AsK FHSM 
d#89 
 
 (#c3h C   $  ,0"" (" 	"
 
h" "H  ,0&& (& 	&
 
h& &P44 4	4
 
h4&;; 9	;
 
h;0 ,0&=&= 4&=
 (&= 
h&=Z ,0(=(= 9(=
 ((= 
h(=T0
X'0
 
h0
r7   r(   )(r   r{   collectionsr   collections.abcr   r   r   	itertoolsr   typingr   r	   r
   r   r   rT   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   r7   r%   <module>r      s   
  # 8 8   . B 3 G % &CLCx HQK hsAv.> 8A; "Z
 Z
r7   