U
    h'                     @   s   d Z ddlZddlmZ ddlmZmZmZmZm	Z	m
Z
 ddlZddlZddlZddlmZ ddlmZmZ ddlmZ dgZG d	d deeZG d
d dZdS )z-written under MIT Licence, Michael Feil 2023.    N)ThreadPoolExecutor)AnyCallableDictListOptionalTuple)
Embeddings)	BaseModelroot_validator)get_from_dict_or_envInfinityEmbeddingsc                   @   s   e Zd ZU dZeed< dZeed< dZeed< G dd dZ	e
d	d
eedddZee eee  dddZee eee  dddZeee dddZeee dddZdS )r   aB  Self-hosted embedding models for `infinity` package.

    See https://github.com/michaelfeil/infinity
    This also works for text-embeddings-inference and other
    self-hosted openai-compatible servers.

    Infinity is a package to interact with Embedding Models on https://github.com/michaelfeil/infinity


    Example:
        .. code-block:: python

            from langchain_community.embeddings import InfinityEmbeddings
            InfinityEmbeddings(
                model="BAAI/bge-small",
                infinity_api_url="http://localhost:7997",
            )
    modelzhttp://localhost:7997infinity_api_urlNclientc                   @   s   e Zd ZdZdS )zInfinityEmbeddings.ConfigZforbidN)__name__
__module____qualname__extra r   r   K/tmp/pip-unpacked-wheel-9gdii04g/langchain_community/embeddings/infinity.pyConfig/   s   r   T)pre)valuesreturnc                 C   s&   t |dd|d< t|d d|d< |S )z?Validate that api key and python package exists in environment.r   ZINFINITY_API_URL)hostr   )r   &TinyAsyncOpenAIInfinityEmbeddingClient)clsr   r   r   r   validate_environment2   s      
z'InfinityEmbeddings.validate_environmenttextsr   c                 C   s   | j j| j|d}|S )zCall out to Infinity's embedding endpoint.

        Args:
            texts: The list of texts to embed.

        Returns:
            List of embeddings, one for each text.
        r   r    )r   embedr   selfr    
embeddingsr   r   r   embed_documents?   s
    	z"InfinityEmbeddings.embed_documentsc                    s   | j j| j|dI dH }|S )zAsync call out to Infinity's embedding endpoint.

        Args:
            texts: The list of texts to embed.

        Returns:
            List of embeddings, one for each text.
        r!   N)r   aembedr   r#   r   r   r   aembed_documentsN   s
    	z#InfinityEmbeddings.aembed_documents)textr   c                 C   s   |  |gd S )zCall out to Infinity's embedding endpoint.

        Args:
            text: The text to embed.

        Returns:
            Embeddings for the text.
        r   )r&   )r$   r)   r   r   r   embed_query]   s    	zInfinityEmbeddings.embed_queryc                    s   |  |gI dH }|d S )zAsync call out to Infinity's embedding endpoint.

        Args:
            text: The text to embed.

        Returns:
            Embeddings for the text.
        Nr   )r(   )r$   r)   r%   r   r   r   aembed_queryh   s    	zInfinityEmbeddings.aembed_query)r   r   r   __doc__str__annotations__r   r   r   r   r   r   r   r   floatr&   r(   r*   r+   r   r   r   r   r      s   
c                   @   s,  e Zd ZdZdeeej ddddZe	e
fee eeee ef ddd	Zee eee  d
ddZe	eee  ee dddZeee eeef dddZeee eee  dddZeee eee  dddZejeeef eee  dddZeee eee  dddZdS )r   a
  Helper tool to embed Infinity.

    It is not a part of Langchain's stable API,
    direct use discouraged.

    Example:
        .. code-block:: python


            mini_client = TinyAsyncInfinityEmbeddingClient(
            )
            embeds = mini_client.embed(
                model="BAAI/bge-small",
                text=["doc1", "doc2"]
            )
            # or
            embeds = await mini_client.aembed(
                model="BAAI/bge-small",
                text=["doc1", "doc2"]
            )

    http://localhost:7797/v1N)r   
aiosessionr   c                 C   s6   || _ || _| j d ks$t| j dk r,tdd| _d S )N   z( param `host` must be set to a valid url   )r   r1   len
ValueError_batch_size)r$   r   r1   r   r   r   __init__   s
    z/TinyAsyncOpenAIInfinityEmbeddingClient.__init__)r    sorterr   c                    sR   t dkrdd fS tfddD  fdd D }| fddfS )a  Sort texts in ascending order, and
        delivers a lambda expr, which can sort a same length list
        https://github.com/UKPLab/sentence-transformers/blob/
        c5f93f70eca933c78695c5bc686ceda59651ae3b/sentence_transformers/SentenceTransformer.py#L156

        Args:
            texts (List[str]): _description_
            sorter (Callable, optional): _description_. Defaults to len.

        Returns:
            Tuple[List[str], Callable]: _description_

        Example:
            ```
            texts = ["one","three","four"]
            perm_texts, undo = self._permute(texts)
            texts == undo(perm_texts)
            ```
           c                 S   s   | S )Nr   )tr   r   r   <lambda>       zATinyAsyncOpenAIInfinityEmbeddingClient._permute.<locals>.<lambda>c                    s   g | ]} | qS r   r   ).0Zsen)r8   r   r   
<listcomp>   s     zCTinyAsyncOpenAIInfinityEmbeddingClient._permute.<locals>.<listcomp>c                    s   g | ]} | qS r   r   r=   idx)r    r   r   r>      s     c                    s    fddt D S )Nc                    s   g | ]} | qS r   r   r?   Zunsorted_embeddingsr   r   r>      s    zUTinyAsyncOpenAIInfinityEmbeddingClient._permute.<locals>.<lambda>.<locals>.<listcomp>)npargsortrA   )length_sorted_idxrA   r   r;      s   
)r4   rB   rC   )r    r8   Ztexts_sortedr   )rD   r8   r    r   _permute   s
    z/TinyAsyncOpenAIInfinityEmbeddingClient._permuter   c                 C   sJ   t |dkr|gS g }tdt || jD ]}||||| j   q(|S )aX  
        splits Lists of text parts into batches of size max `self._batch_size`
        When encoding vector database,

        Args:
            texts (List[str]): List of sentences
            self._batch_size (int, optional): max batch size of one request.

        Returns:
            List[List[str]]: Batches of List of sentences
        r9   r   )r4   ranger6   append)r$   r    Zbatchesstart_indexr   r   r   _batch   s    z-TinyAsyncOpenAIInfinityEmbeddingClient._batch)batch_of_textsr   c                 C   s@   t | dkr$t | d dkr$| d S g }| D ]}|| q,|S )Nr9   r   )r4   extend)rJ   r    Zsublistr   r   r   _unbatch   s    z/TinyAsyncOpenAIInfinityEmbeddingClient._unbatch)r   r    r   c                 C   s"   t | j dddit ||ddS )zBuild the kwargs for the Post request, used by sync

        Args:
            model (str): _description_
            texts (List[str]): _description_

        Returns:
            Dict[str, Collection[str]]: _description_
        z/embeddingszcontent-typezapplication/json)inputr   )urlheadersjson)dictr   )r$   r   r    r   r   r   _kwargs_post_request   s    

 z;TinyAsyncOpenAIInfinityEmbeddingClient._kwargs_post_request)r   batch_textsr   c                 C   sN   t jf | j||d}|jdkr8td|j d|j dd | d D S )Nr!      5Infinity returned an unexpected response with status : c                 S   s   g | ]}|d  qS 	embeddingr   r=   er   r   r   r>      s     zNTinyAsyncOpenAIInfinityEmbeddingClient._sync_request_embed.<locals>.<listcomp>data)requestspostrR   status_code	Exceptionr)   rP   )r$   r   rS   responser   r   r   _sync_request_embed   s    
z:TinyAsyncOpenAIInfinityEmbeddingClient._sync_request_embedc              	   C   s   |  |\}}| |}| j|gt| |f}t|dkrHtt| }n"td}t|j| }W 5 Q R X | |}	||	}
|
S )zcall the embedding of model

        Args:
            model (str): to embedding model
            texts (List[str]): List of sentences to embed.

        Returns:
            List[List[float]]: List of vectors for each sentence
        r9       )rE   rI   ra   r4   listmapr   rL   )r$   r   r    
perm_textsunpermute_funcperm_texts_batchedZmap_argsembeddings_batch_permpembeddings_permr%   r   r   r   r"      s    



z,TinyAsyncOpenAIInfinityEmbeddingClient.embed)sessionkwargsr   c                    sz   |j f |4 I d H V}|jdkr8td|j d|j | I d H d }dd |D W  5 Q I d H R  S Q I d H R X d S )NrT   rU   rV   r[   c                 S   s   g | ]}|d  qS rW   r   rY   r   r   r   r>   #  s     zITinyAsyncOpenAIInfinityEmbeddingClient._async_request.<locals>.<listcomp>)r]   statusr_   r)   rP   )r$   rk   rl   r`   rX   r   r   r   _async_request  s    
z5TinyAsyncOpenAIInfinityEmbeddingClient._async_requestc           	   
      s    |\}}|}jdkr:tjdtjddd_j4 I dH (tj fdd|D  I dH }W 5 Q I dH R X |}||}|S )zcall the embedding of model, async method

        Args:
            model (str): to embedding model
            texts (List[str]): List of sentences to embed.

        Returns:
            List[List[float]]: List of vectors for each sentence
        NTrb   )limit)	trust_envZ	connectorc                    s$   g | ]}j j |d dqS )r!   )rk   rl   )rn   rR   )r=   r:   r   r$   rk   r   r   r>   9  s
   zATinyAsyncOpenAIInfinityEmbeddingClient.aembed.<locals>.<listcomp>)	rE   rI   r1   aiohttpClientSessionZTCPConnectorasyncioZgatherrL   )	r$   r   r    re   rf   rg   rh   rj   r%   r   rq   r   r'   %  s     


 


z-TinyAsyncOpenAIInfinityEmbeddingClient.aembed)r0   N)r   r   r   r,   r-   r   rr   rs   r7   staticmethodr4   r   r   r   rE   rI   r   rL   r   rR   r/   ra   r"   rn   r'   r   r   r   r   r   u   s:      !	 
 

r   )r,   rt   concurrent.futuresr   typingr   r   r   r   r   r   rr   ZnumpyrB   r\   Zlangchain_core.embeddingsr	   Zlangchain_core.pydantic_v1r
   r   Zlangchain_core.utilsr   __all__r   r   r   r   r   r   <module>   s    d