U
    hV                     @   s  d dl 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
mZmZmZmZmZ d dlZd dl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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*m+Z+m,Z, d d
l-m.Z.m/Z/m0Z0m1Z1 d dl2m3Z3 d dl4m5Z5 d dl6m7Z7m8Z8m9Z9 d dl:m;Z; d dl<m=Z=m>Z> e?e@ZAdZBeeCdddZDeeEef edddZFeeEef ee edddZGeeeEeEeedddZHG dd deZIdS )    N)asynccontextmanager)AnyAsyncIteratorCallableDictIteratorListMappingOptionalSequenceTypeUnion)AsyncCallbackManagerForLLMRunCallbackManagerForLLMRun)LanguageModelInput)BaseChatModelagenerate_from_streamgenerate_from_stream)	AIMessageAIMessageChunkBaseMessageBaseMessageChunkChatMessageChatMessageChunkHumanMessageHumanMessageChunkSystemMessageSystemMessageChunkToolMessage)make_invalid_tool_callparse_tool_call)ChatGenerationChatGenerationChunk
ChatResult)	BaseModelField	SecretStrroot_validator)Runnable)BaseTool)convert_to_secret_strget_from_dict_or_envget_pydantic_field_namesconvert_to_openai_tool))_lc_invalid_tool_call_to_openai_tool_call!_lc_tool_call_to_openai_tool_callz/https://api.baichuan-ai.com/v1/chat/completions)messagereturnc                 C   s   | j }t| tr| j|d}nt| tr4d|d}nt| trd|d}d| jkrb| jd |d< q| jsn| jrdd | jD dd | jD  |d< nNt| t	rd| j
|| jp| jd	d
}n$t| trd|d}ntd|  |S )N)rolecontentuser	assistant
tool_callsc                 S   s   g | ]}t |qS  )r0   .0Ztcr8   r8   L/tmp/pip-unpacked-wheel-9gdii04g/langchain_community/chat_models/baichuan.py
<listcomp>P   s    z,_convert_message_to_dict.<locals>.<listcomp>c                 S   s   g | ]}t |qS r8   )r/   r9   r8   r8   r;   r<   R   s   toolname)r3   tool_call_idr4   r>   systemzGot unknown type )r4   
isinstancer   r3   r   r   additional_kwargsr7   invalid_tool_callsr   r?   r>   getr   	TypeError)r1   r4   Zmessage_dictr8   r8   r;   _convert_message_to_dictC   s6    







rF   )_dictr2   c           	      C   s  | d }|  dd}|dkr&t|dS |dkrg }g }i }|  d }r||d< |D ]R}z|t|dd	 W qT tk
r } z|t|t| W 5 d }~X Y qTX qTt||||d
S |dkri }d| kr| d |d< t||  d|dS |dkr t	|dS t
||dS d S )Nr3   r4    r5   r4   r6   r7   T)Z	return_id)r4   rB   r7   rC   r=   r>   r?   )r4   r?   rB   r@   r4   r3   )rD   r   appendr    	Exceptionr   strr   r   r   r   )	rG   r3   r4   r7   rC   rB   Zraw_tool_callsZraw_tool_caller8   r8   r;   _convert_dict_to_messagef   sF    


rO   )rG   default_classr2   c                 C   s   |  d}|  dpd}|dks(|tkr2t|dS |dksB|tkrLt|dS |dks\|tkrft|dS |sr|tkr~t||dS ||dS d S )	Nr3   r4   rH   r5   rI   r6   r@   rJ   )rD   r   r   r   r   )rG   rP   r3   r4   r8   r8   r;   _convert_delta_to_message_chunk   s    



rQ   )clientmethodurlkwargsr2   c              
   K  sD   ddl m} | j||f|4 I dH }||V  W 5 Q I dH R X dS )a  Async context manager for connecting to an SSE stream.

    Args:
        client: The httpx client.
        method: The HTTP method.
        url: The URL to connect to.
        kwargs: Additional keyword arguments to pass to the client.

    Yields:
        An EventSource object.
    r   )EventSourceN)Z	httpx_sserV   stream)rR   rS   rT   rU   rV   responser8   r8   r;   aconnect_httpx_sse   s    rY   c                       s  e Zd ZU dZeeeef dddZeedddZ	e
eddZeed	< e
d
dZeed< dZee ed< dZeed< dZee ed< e
dddZeed< dZeed< e
ddZee ed< dZeed< dZeed< dZeed< e
edZeeef ed < G d!d" d"Ze d#d$eeef eeef d%d&d'Z!e d#d$eed%d(d)Z"eeeef dd*d+Z#dFe$e% ee$e  ee& ee'd,d-d.Z(dGe$e% ee$e  ee& ee)e* d,d/d0Z+dHe$e% ee$e  ee, ee ee'd1d2d3Z-dIe$e% ee$e  ee, ee.e* d,d4d5Z/e$e% ee0j1d6d7d8Z2e$e% eeef d9d:d;Z3eeef dd<d=Z4e5eef e'd>d?d@Z6eeddAdBZ7e8e9eeef e:e; e<e=f  ee>e?e%f dC fdDdEZ@  ZAS )JChatBaichuanu  Baichuan chat model integration.

    Setup:
        To use, you should have the environment variable``BAICHUAN_API_KEY`` set with
    your API KEY.

        .. code-block:: bash

            export BAICHUAN_API_KEY="your-api-key"

    Key init args — completion params:
        model: Optional[str]
            Name of Baichuan model to use.
        max_tokens: Optional[int]
            Max number of tokens to generate.
        streaming: Optional[bool]
            Whether to stream the results or not.
        temperature: Optional[float]
            Sampling temperature.
        top_p: Optional[float]
            What probability mass to use.
        top_k: Optional[int]
            What search sampling control to use.

    Key init args — client params:
        api_key: Optional[str]
            Baichuan API key. If not passed in will be read from env var BAICHUAN_API_KEY.
        base_url: Optional[str]
            Base URL for API requests.

    See full list of supported init args and their descriptions in the params section.

    Instantiate:
        .. code-block:: python

            from langchain_community.chat_models import ChatBaichuan

            chat = ChatBaichuan(
                api_key=api_key,
                model='Baichuan4',
                # temperature=...,
                # other params...
            )

    Invoke:
        .. code-block:: python

            messages = [
                ("system", "你是一名专业的翻译家，可以将用户的中文翻译为英文。"),
                ("human", "我喜欢编程。"),
            ]
            chat.invoke(messages)

        .. code-block:: python

            AIMessage(
                content='I enjoy programming.',
                response_metadata={
                    'token_usage': {
                        'prompt_tokens': 93,
                        'completion_tokens': 5,
                        'total_tokens': 98
                    },
                    'model': 'Baichuan4'
                },
                id='run-944ff552-6a93-44cf-a861-4e4d849746f9-0'
            )

    Stream:
        .. code-block:: python

            for chunk in chat.stream(messages):
                print(chunk)

        .. code-block:: python

            content='I' id='run-f99fcd6f-dd31-46d5-be8f-0b6a22bf77d8'
            content=' enjoy programming.' id='run-f99fcd6f-dd31-46d5-be8f-0b6a22bf77d8

        .. code-block:: python

            stream = chat.stream(messages)
            full = next(stream)
            for chunk in stream:
                full += chunk
            full

        .. code-block:: python

            AIMessageChunk(
                content='I like programming.',
                id='run-74689970-dc31-461d-b729-3b6aa93508d2'
            )

    Async:
        .. code-block:: python

            await chat.ainvoke(messages)

            # stream
            # async for chunk in chat.astream(messages):
            #     print(chunk)

            # batch
            # await chat.abatch([messages])

        .. code-block:: python

            AIMessage(
                content='I enjoy programming.',
                response_metadata={
                    'token_usage': {
                        'prompt_tokens': 93,
                        'completion_tokens': 5,
                        'total_tokens': 98
                    },
                    'model': 'Baichuan4'
                },
                id='run-952509ed-9154-4ff9-b187-e616d7ddfbba-0'
            )
    Tool calling:

        .. code-block:: python
            class get_current_weather(BaseModel):
                '''Get current weather.'''

                location: str = Field('City or province, such as Shanghai')


            llm_with_tools = ChatBaichuan(model='Baichuan3-Turbo').bind_tools([get_current_weather])
            llm_with_tools.invoke('How is the weather today?')

        .. code-block:: python

            [{'name': 'get_current_weather',
            'args': {'location': 'New York'},
            'id': '3951017OF8doB0A',
            'type': 'tool_call'}]

    Response metadata
        .. code-block:: python

            ai_msg = chat.invoke(messages)
            ai_msg.response_metadata

        .. code-block:: python

            {
                'token_usage': {
                    'prompt_tokens': 93,
                    'completion_tokens': 5,
                    'total_tokens': 98
                },
                'model': 'Baichuan4'
            }

    )r2   c                 C   s   ddiS )Nbaichuan_api_keyBAICHUAN_API_KEYr8   selfr8   r8   r;   
lc_secretsU  s     zChatBaichuan.lc_secretsc                 C   s   dS )NTr8   r]   r8   r8   r;   lc_serializable[  s    zChatBaichuan.lc_serializablebase_url)defaultaliasbaichuan_api_baseapi_key)rc   r[   Nbaichuan_secret_keyF	streaming
max_tokens<   timeoutrequest_timeoutzBaichuan2-Turbo-192Kmodel333333?)rb   temperature   top_k333333?top_pwith_search_enhance)default_factorymodel_kwargsc                   @   s   e Zd ZdZdS )zChatBaichuan.ConfigTN)__name__
__module____qualname__Zallow_population_by_field_namer8   r8   r8   r;   Configz  s   ry   T)pre)valuesr2   c              
   C   s   t | }|di }t|D ]P}||kr8td| d||krtd| d| d| d ||||< q|| }|rtd| d	||d< |S )
z>Build extra kwargs from additional params that were passed in.ru   zFound z supplied twice.z	WARNING! z/ is not default parameter.
                    zJ was transferred to model_kwargs.
                    Please confirm that z is what you intended.zParameters za should be specified explicitly. Instead they were passed in as part of `model_kwargs` parameter.)	r,   rD   list
ValueErrorloggerwarningpopintersectionkeys)clsr{   Zall_required_field_namesextra
field_nameZinvalid_model_kwargsr8   r8   r;   build_extra}  s"    
zChatBaichuan.build_extrac                 C   s.   t |ddt|d< tt |ddgd|d< |S )Nrd   ZBAICHUAN_API_BASEr[   re   r\   )r+   DEFAULT_API_BASEr*   )r   r{   r8   r8   r;   validate_environment  s    z!ChatBaichuan.validate_environmentc                 C   s(   | j | j| j| j| j| jd}|| jS )z4Get the default parameters for calling Baichuan API.)rl   rn   rr   rp   rW   rh   )rl   rn   rr   rp   rg   rh   ru   )r^   Znormal_paramsr8   r8   r;   _default_params  s    	zChatBaichuan._default_params)messagesstoprun_managerrU   r2   c                 K   s^   | j r&| jf |||d|}t|S | j|f|}|jdkrLtd| | }| |S )N)r   r   r      "Error from Baichuan api response: )rg   _streamr   _chatstatus_coder}   json_create_chat_result)r^   r   r   r   rU   stream_iterresrX   r8   r8   r;   	_generate  s      
zChatBaichuan._generatec                 k   s   | j |fddi|}|jdkr.td| t}| D ]}|dd}|dd}t|dkrn|d nd }|d kr|q:|d	kr qt	
|}	|	d
D ]>}
t|
d|}|j}t|d}|r|j|j|d |V  qq:d S )NrW   Tr   r   zutf-8z
zdata:    z[DONE]choicesdeltar1   chunk)r   r   r}   r   
iter_linesdecodestripsplitlenr   loadsrD   rQ   	__class__r"   on_llm_new_tokenr4   )r^   r   r   r   rU   r   Zdefault_chunk_classr   partsrX   mZcg_chunkr8   r8   r;   r     s.    

 
zChatBaichuan._stream)r   r   r   rW   rU   r2   c              
      s   |d k	r|n| j }|r<| j|f||d|}t|I d H S | jf |}| j|f|}	dd l}
|
j|| jd4 I d H $}|j| j	|	dI d H }|
  W 5 Q I d H R X | | S )N)r   r   r   headersrj   r   )rg   _astreamr   _create_headers_parameters_create_payload_parametershttpxAsyncClientrk   postrd   raise_for_statusr   r   )r^   r   r   r   rW   rU   Zshould_streamr   r   payloadr   rR   rX   r8   r8   r;   
_agenerate  s,      zChatBaichuan._ageneratec                 K  s.  | j f |}| j|fddi|}dd l}|j|| jd4 I d H }t|d| j|d4 I d H }	|	 2 z3 d H W }
t	|
j
}t|d dkrqh|d d }t|d t}|d	d }|d k	rd	|ind }t||d
}|r|j|j|dI d H  |V  |d k	rh q
qh6 W 5 Q I d H R X W 5 Q I d H R X d S )NrW   Tr   r   POSTr   r   r   finish_reason)r1   generation_infor   )r   r   r   r   rk   rY   rd   Z	aiter_sser   r   datar   rQ   r   rD   r"   r   text)r^   r   r   r   rU   r   r   r   rR   Zevent_sourceZsser   choicer   r   r8   r8   r;   r     sL         
 zChatBaichuan._astream)r   rU   r2   c                 K   s<   | j |f|}| j}| jf |}tj|| j||| jd}|S )N)rT   rj   r   r   rW   )r   rd   r   requestsr   rk   rg   )r^   r   rU   r   rT   r   r   r8   r8   r;   r   +  s    zChatBaichuan._chat)r   r2   c              	   K   s   | j |}|dd}|dd}|dd}|d}|dd	}|d
d	}	|dg }
|dd |D |||||	|
d}|S )Nrn   rm   rp   ro   rr   rq   rl   rs   FrW   toolsc                 S   s   g | ]}t |qS r8   )rF   )r:   r   r8   r8   r;   r<   G  s     z;ChatBaichuan._create_payload_parameters.<locals>.<listcomp>)rl   r   rp   rr   rn   rs   rW   r   )r   r   )r^   r   rU   
parametersrn   rp   rr   rl   rs   rW   r   r   r8   r8   r;   r   9  s$    

z'ChatBaichuan._create_payload_parametersc                 K   sB   | j |}|di }d}| jr*| j }dd| d|}|S )Nr   rH   zapplication/jsonzBearer )zContent-TypeAuthorization)r   r   r[   Zget_secret_value)r^   rU   r   default_headersre   r   r8   r8   r;   r   R  s    

z'ChatBaichuan._create_headers_parameters)rX   r2   c                 C   sR   g }|d D ]$}t |d }t|d}|| q|d }|| jd}t||dS )Nr   r1   r   usage)token_usagerl   )generations
llm_output)rO   r!   rK   rl   r#   )r^   rX   r   cr1   genr   r   r8   r8   r;   r   `  s    
z ChatBaichuan._create_chat_resultc                 C   s   dS )Nzbaichuan-chatr8   r]   r8   r8   r;   	_llm_typek  s    zChatBaichuan._llm_type)r   rU   r2   c                    s$   dd |D }t  jf d|i|S )a  Bind tool-like objects to this chat model.

        Args:
            tools: A list of tool definitions to bind to this chat model.
                Can be a dictionary, pydantic model, callable, or BaseTool.
                Pydantic
                models, callables, and BaseTools will be automatically converted to
                their schema dictionary representation.
            **kwargs: Any additional parameters to pass to the
                :class:`~langchain.runnable.Runnable` constructor.
        c                 S   s   g | ]}t |qS r8   r-   )r:   r=   r8   r8   r;   r<     s     z+ChatBaichuan.bind_tools.<locals>.<listcomp>r   )superbind)r^   r   rU   Zformatted_toolsr   r8   r;   
bind_toolso  s    zChatBaichuan.bind_tools)NN)NN)NNN)NN)Brv   rw   rx   __doc__propertyr   rM   r_   boolr`   r%   r   rd   __annotations__r[   r&   rf   r
   rg   rh   intrk   rl   rn   floatrp   rr   rs   dictru   r   ry   r'   r   r   r   r   r   r   r#   r   r   r"   r   r   r   r   r   r   Responser   r   r   r	   r   r   r   r   r   r$   r   r)   r(   r   r   __classcell__r8   r8   r   r;   rZ      s   
 "  
  
!   
  
)

rZ   )Jr   logging
contextlibr   typingr   r   r   r   r   r   r	   r
   r   r   r   r   Zlangchain_core.callbacksr   r   Zlangchain_core.language_modelsr   Z*langchain_core.language_models.chat_modelsr   r   r   Zlangchain_core.messagesr   r   r   r   r   r   r   r   r   r   r   Z*langchain_core.output_parsers.openai_toolsr   r    Zlangchain_core.outputsr!   r"   r#   Zlangchain_core.pydantic_v1r$   r%   r&   r'   Zlangchain_core.runnablesr(   Zlangchain_core.toolsr)   Zlangchain_core.utilsr*   r+   r,   Z%langchain_core.utils.function_callingr.   Z(langchain_community.chat_models.llamacppr/   r0   	getLoggerrv   r~   r   r   rF   rM   rO   rQ   rY   rZ   r8   r8   r8   r;   <module>   s@   44
#*
    