o
    ZhSV                     @   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. d dl/m0Z0 d dl1m2Z2m3Z3m4Z4 d dl5m6Z6 d dl7m8Z8m9Z9m:Z:m;Z;m<Z< d dl=m>Z>m?Z? e@eAZBdZCdedeDfddZEdeeFef defddZGdeeFef dee defddZHededeFdeFdedef
dd ZIG d!d" d"eZJd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)Runnable)BaseTool)convert_to_secret_strget_from_dict_or_envget_pydantic_field_namesconvert_to_openai_tool)	BaseModel
ConfigDictField	SecretStrmodel_validator))_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}|S t| trd|d}|S t| trNd|d}d| jv r4| jd |d< |S | js:| jrLdd | jD dd | jD  |d< |S t| t	rdd| j
|| jp_| jd	d
}|S t| trpd|d}|S td|  )N)rolecontentuser	assistant
tool_callsc                 S      g | ]}t |qS  )r1   .0Ztcr:   r:   _/var/www/html/lang_env/lib/python3.10/site-packages/langchain_community/chat_models/baichuan.py
<listcomp>V   s    z,_convert_message_to_dict.<locals>.<listcomp>c                 S   r9   r:   )r0   r;   r:   r:   r=   r>   X   s    toolname)r4   tool_call_idr5   r@   systemzGot unknown type )r5   
isinstancer   r4   r   r   additional_kwargsr8   invalid_tool_callsr   rA   r@   getr   	TypeError)r2   r5   Zmessage_dictr:   r:   r=   _convert_message_to_dictI   s@   








rH   _dictc           	      C   s
  | d }|  dd}|dkrt|dS |dkr\g }g }i }|  d }rT||d< |D ])}z|t|dd	 W q* tyS } z|t|t| W Y d }~q*d }~ww t||||d
S |dkrvi }d| v rl| d |d< t||  d|dS |dkrt	|dS t
||dS )Nr4   r5    r6   r5   r7   r8   T)Z	return_id)r5   rD   r8   rE   r?   r@   rA   )r5   rA   rD   rB   r5   r4   )rF   r   appendr    	Exceptionr   strr   r   r   r   )	rI   r4   r5   r8   rE   rD   Zraw_tool_callsZraw_tool_caller:   r:   r=   _convert_dict_to_messagel   sJ   

rQ   default_classc                 C   s   |  d}|  dpd}|dks|tkrt|dS |dks!|tkr&t|dS |dks.|tkr3t|dS |s9|tkr?t||dS ||dS )	Nr4   r5   rJ   r6   rK   r7   rB   rL   )rF   r   r   r   r   )rI   rR   r4   r5   r:   r:   r=   _convert_delta_to_message_chunk   s   




rS   clientmethodurlkwargsc              	   K  sf   ddl m} | j||fi |4 I dH }||V  W d  I dH  dS 1 I dH s,w   Y  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_sserX   stream)rT   rU   rV   rW   rX   responser:   r:   r=   aconnect_httpx_sse   s
   .r[   c                       s(  e Zd ZU dZedeeef fddZedef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 < 	 ed!d"Z e!d#d$e"d%eeef defd&d'Z#e!d#d$e"d%edefd(d)Z$edeeef fd*d+Z%		dGd,e&e' d-ee&e  d.ee( d/ede)f
d0d1Z*		dGd,e&e' d-ee&e  d.ee( d/ede+e, f
d2d3Z-			dHd,e&e' d-ee&e  d.ee. d4ee d/ede)fd5d6Z/		dGd,e&e' d-ee&e  d.ee. d/ede0e, f
d7d8Z1d,e&e' d/ede2j3fd9d:Z4d,e&e' deeef fd;d<Z5deeef fd=d>Z6d?e7eef de)fd@dAZ8edefdBdCZ9dDe:e;eeef e<e= e>e?f  d/ede@eAe'f f fdEdFZB  ZCS )I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'
            }

    r3   c                 C   s   ddiS )Nbaichuan_api_keyBAICHUAN_API_KEYr:   selfr:   r:   r=   
lc_secrets[  s   zChatBaichuan.lc_secretsc                 C      dS )NTr:   r_   r:   r:   r=   lc_serializablea     zChatBaichuan.lc_serializablebase_url)defaultaliasbaichuan_api_baseapi_key)rg   r]   Nbaichuan_secret_keyF	streaming
max_tokens<   timeoutrequest_timeoutzBaichuan2-Turbo-192Kmodel333333?)rf   temperature   top_k333333?top_pwith_search_enhance)default_factorymodel_kwargsT)Zpopulate_by_namebefore)modevaluesc              
   C   s   t | }|di }t|D ](}||v rtd| d||vr6td| d| d| d ||||< q|| }|rHtd| d	||d< |S )
z>Build extra kwargs from additional params that were passed in.ry   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(   rF   list
ValueErrorloggerwarningpopintersectionkeys)clsr|   Zall_required_field_namesextra
field_nameZinvalid_model_kwargsr:   r:   r=   build_extra  s,   
zChatBaichuan.build_extrac                 C   s.   t |ddt|d< tt |ddgd|d< |S )Nrh   ZBAICHUAN_API_BASEr]   ri   r^   )r'   DEFAULT_API_BASEr&   )r   r|   r:   r:   r=   validate_environment  s   z!ChatBaichuan.validate_environmentc                 C   s,   | j | j| j| j| j| jd}i || jS )z4Get the default parameters for calling Baichuan API.)rp   rr   rv   rt   rY   rl   )rp   rr   rv   rt   rk   rl   ry   )r`   Znormal_paramsr:   r:   r=   _default_params  s   	zChatBaichuan._default_paramsmessagesstoprun_managerrW   c                 K   sb   | j r| jd|||d|}t|S | j|fi |}|jdkr(td| | }| |S )N)r   r   r      "Error from Baichuan api response: r:   )rk   _streamr   _chatstatus_coder~   json_create_chat_result)r`   r   r   r   rW   stream_iterresrZ   r:   r:   r=   	_generate  s   

zChatBaichuan._generatec                 k   s    | j |fddi|}|jdkrtd| t}| D ]R}|dd}|dd}t|dkr8|d nd }|d u r?q|d	krF d S t	
|}	|	d
D ]}
t|
d|}|j}t|d}|rl|j|j|d |V  qPqd S )NrY   Tr   r   zutf-8z
zdata:    z[DONE]choicesdeltar2   chunk)r   r   r~   r   
iter_linesdecodestripsplitlenr   loadsrF   rS   	__class__r"   on_llm_new_tokenr5   )r`   r   r   r   rW   r   Zdefault_chunk_classr   partsrZ   mZcg_chunkr:   r:   r=   r     s2   



zChatBaichuan._streamrY   c              	      s   |d ur|n| j }|r| j|f||d|}t|I d H S | jdi |}| j|fi |}	dd l}
|
j|| jd4 I d H }|j| j	|	dI d H }|
  W d   I d H  n1 I d H s`w   Y  | | S )N)r   r   r   headersrn   r   r:   )rk   _astreamr   _create_headers_parameters_create_payload_parametershttpxAsyncClientro   postrh   raise_for_statusr   r   )r`   r   r   r   rY   rW   Zshould_streamr   r   payloadr   rT   rZ   r:   r:   r=   
_agenerate  s,   
(zChatBaichuan._ageneratec              
   K  sh  | j di |}| j|fddi|}dd l}|j|| jd4 I d H }t|d| j|d4 I d H _}	|	 2 zN3 d H W }
t	|
j
}t|d dkrLq7|d d }t|d t}|d	d }|d urgd	|ind }t||d
}|r||j|j|dI d H  |V  |d ur nq76 W d   I d H  n1 I d H sw   Y  W d   I d H  d S 1 I d H sw   Y  d S )NrY   Tr   r   POSTr   r   r   finish_reason)r2   generation_infor   r:   )r   r   r   r   ro   r[   rh   Z	aiter_sser   r   datar   rS   r   rF   r"   r   text)r`   r   r   r   rW   r   r   r   rT   Zevent_sourceZsser   choicer   r   r:   r:   r=   r     sJ   
*.zChatBaichuan._astreamc                 K   sD   | j |fi |}| j}| jdi |}tj|| j||| jd}|S )N)rV   rn   r   r   rY   r:   )r   rh   r   requestsr   ro   rk   )r`   r   rW   r   rV   r   r   r:   r:   r=   r   4  s   zChatBaichuan._chatc              	   K   s   i | j |}|dd}|dd}|dd}|d}|dd	}|d
d	}	|dg }
|dd |D |||||	|
d}|S )Nrr   rq   rt   rs   rv   ru   rp   rw   FrY   toolsc                 S   r9   r:   )rH   )r<   r   r:   r:   r=   r>   P      z;ChatBaichuan._create_payload_parameters.<locals>.<listcomp>)rp   r   rt   rv   rr   rw   rY   r   )r   r   )r`   r   rW   
parametersrr   rt   rv   rp   rw   rY   r   r   r:   r:   r=   r   B  s$   
z'ChatBaichuan._create_payload_parametersc                 K   sF   i | j |}|di }d}| jr| j }dd| d|}|S )Nr   rJ   zapplication/jsonzBearer )zContent-TypeAuthorization)r   r   r]   Zget_secret_value)r`   rW   r   default_headersri   r   r:   r:   r=   r   [  s   
z'ChatBaichuan._create_headers_parametersrZ   c                 C   sR   g }|d D ]}t |d }t|d}|| q|d }|| jd}t||dS )Nr   r2   r   usage)token_usagerp   )generations
llm_output)rQ   r!   rM   rp   r#   )r`   rZ   r   cr2   genr   r   r:   r:   r=   r   i  s   
z ChatBaichuan._create_chat_resultc                 C   rb   )Nzbaichuan-chatr:   r_   r:   r:   r=   	_llm_typet  rd   zChatBaichuan._llm_typer   c                    s$   dd |D }t  jd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   r9   r:   r)   )r<   r?   r:   r:   r=   r>     r   z+ChatBaichuan.bind_tools.<locals>.<listcomp>r   Nr:   )superbind)r`   r   rW   Zformatted_toolsr   r:   r=   
bind_toolsx  s   zChatBaichuan.bind_tools)NN)NNN)D__name__
__module____qualname____doc__propertyr   rO   ra   boolrc   r-   r   rh   __annotations__r]   r.   rj   r
   rk   rl   intro   rp   rr   floatrt   rv   rw   dictry   r   r,   Zmodel_configr/   classmethodr   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__r:   r:   r   r=   r\      s   
  



!



)


r\   )Kr   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.runnablesr$   Zlangchain_core.toolsr%   Zlangchain_core.utilsr&   r'   r(   Z%langchain_core.utils.function_callingr*   Zpydanticr+   r,   r-   r.   r/   Z(langchain_community.chat_models.llamacppr0   r1   	getLoggerr   r   r   r   rH   rO   rQ   rS   r[   r\   r:   r:   r:   r=   <module>   sR    44
#)

