o
    Zho>                     @  s  d dl mZ d dlZd dlZd dlZd dlZd dlZd dl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 d dlmZmZmZ d dlmZ d d	lmZ d d
lmZ d dlmZ d dl m!Z!m"Z" d dl#m$Z$ e%e&Z'G dd deZ(G dd dZ)dS )    )annotationsN)datetime)Queue)mktime)AnyDict	GeneratorIteratorListOptional)	urlencodeurlparse
urlunparse)format_date_time)CallbackManagerForLLMRun)LLM)GenerationChunk)get_from_dict_or_envpre_init)Fieldc                   @  s6  e Zd ZU dZdZded< edddZded< 	 edd	dZded
< 	 edddZ	ded< 	 edddZ
ded< 	 edddZded< 	 dZded< dZded< 	 edddZded< 	 dZded< 	 dZded< 	 eed Zd!ed"< 	 ed7d&d'Zed8d(d)Zed9d*d+Z		d:d;d2d3Z		d:d<d5d6ZdS )=SparkLLMuT  iFlyTek Spark completion model integration.

    Setup:
        To use, you should set environment variables ``IFLYTEK_SPARK_APP_ID``,
        ``IFLYTEK_SPARK_API_KEY`` and ``IFLYTEK_SPARK_API_SECRET``.

    .. code-block:: bash

            export IFLYTEK_SPARK_APP_ID="your-app-id"
            export IFLYTEK_SPARK_API_KEY="your-api-key"
            export IFLYTEK_SPARK_API_SECRET="your-api-secret"

    Key init args — completion params:
        model: Optional[str]
            Name of IFLYTEK SPARK model to use.
        temperature: Optional[float]
            Sampling temperature.
        top_k: Optional[float]
            What search sampling control to use.
        streaming: Optional[bool]
             Whether to stream the results or not.

    Key init args — client params:
        app_id: Optional[str]
            IFLYTEK SPARK API KEY. Automatically inferred from env var `IFLYTEK_SPARK_APP_ID` if not provided.
        api_key: Optional[str]
            IFLYTEK SPARK API KEY. If not passed in will be read from env var IFLYTEK_SPARK_API_KEY.
        api_secret: Optional[str]
            IFLYTEK SPARK API SECRET. If not passed in will be read from env var IFLYTEK_SPARK_API_SECRET.
        api_url: Optional[str]
            Base URL for API requests.
        timeout: Optional[int]
            Timeout for requests.

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

    Instantiate:
        .. code-block:: python

            from langchain_community.llms import SparkLLM

            llm = SparkLLM(
                app_id="your-app-id",
                api_key="your-api_key",
                api_secret="your-api-secret",
                # model='Spark4.0 Ultra',
                # temperature=...,
                # other params...
            )

    Invoke:
        .. code-block:: python

            input_text = "用50个字左右阐述，生命的意义在于"
            llm.invoke(input_text)

        .. code-block:: python

            '生命的意义在于实现自我价值，追求内心的平静与快乐，同时为他人和社会带来正面影响。'

    Stream:
        .. code-block:: python

            for chunk in llm.stream(input_text):
                print(chunk)

        .. code-block:: python

            生命 | 的意义在于 | 不断探索和 | 实现个人潜能，通过 | 学习 | 、成长和对社会 | 的贡献，追求内心的满足和幸福。

    Async:
        .. code-block:: python

            await llm.ainvoke(input_text)

            # stream:
            # async for chunk in llm.astream(input_text):
            #    print(chunk)

            # batch:
            # await llm.abatch([input_text])

        .. code-block:: python

            '生命的意义在于实现自我价值，追求内心的平静与快乐，同时为他人和社会带来正面影响。'

    Nr   clientapp_id)defaultaliasOptional[str]spark_app_idapi_keyspark_api_key
api_secretspark_api_secretapi_urlspark_api_urlmodelspark_llm_domainZlc_userstrspark_user_idFbool	streaming   timeoutintrequest_timeoutg      ?floattemperature   top_k)default_factoryDict[str, Any]model_kwargsvaluesr   returnc                 C  s   t |ddgd|d< t |ddgd|d< t |ddgd	|d< t |d
dgdd|d
< t |ddgdd|d< |d p:| j|d d< |d pE| j|d d< t|d |d |d |d
 |d |d d|d< |S )Nr   r   ZIFLYTEK_SPARK_APP_IDr   r   ZIFLYTEK_SPARK_API_KEYr    r   ZIFLYTEK_SPARK_API_SECRETr"   r!   ZIFLYTEK_SPARK_API_URL$wss://spark-api.xf-yun.com/v3.5/chatr$   r#   ZIFLYTEK_SPARK_LLM_DOMAINgeneralv3.5r.   r3   r0   )r   r   r   r!   spark_domainr3   r   )r   r.   r0   _SparkLLMClient)clsr4    r;   X/var/www/html/lang_env/lib/python3.10/site-packages/langchain_community/llms/sparkllm.pyvalidate_environment   sL   
zSparkLLM.validate_environmentc                 C  s   dS )zReturn type of llm.zspark-llm-chatr;   )selfr;   r;   r<   	_llm_type   s   zSparkLLM._llm_typec                 C  s(   | j | j| j| j| jd}i || jS )z4Get the default parameters for calling SparkLLM API.)r$   streamr,   r0   r.   )r$   r(   r,   r0   r.   r3   )r>   Znormal_paramsr;   r;   r<   _default_params   s   zSparkLLM._default_paramspromptstopOptional[List[str]]run_manager"Optional[CallbackManagerForLLMRun]kwargsc                 K  s   | j rd}| j|||fi |D ]}||j7 }q|S d}| jd|dg| j| j| j  | jj| jdD ]}d|vr;q4|d d }q4|S )av  Call out to an sparkllm for each generation with a prompt.
        Args:
            prompt: The prompt to pass into the model.
            stop: Optional list of stop words to use when generating.
        Returns:
            The string generated by the llm.

        Example:
            .. code-block:: python
                response = client("Tell me a joke.")
         userrolecontentr*   datarL   )	r(   _streamtextr   arunr&   r3   	subscriber,   )r>   rB   rC   rE   rG   
completionchunkrL   r;   r;   r<   _call   s"   
zSparkLLM._callIterator[GenerationChunk]c                 k  sj    | j d|dg| j| jd | j j| jdD ]}d|vrq|d }|r*|| t|d dV  qd S )NrI   rJ   TrM   rN   rL   )rP   )r   runr&   r3   rR   r,   Zon_llm_new_tokenr   )r>   rB   rC   rE   rG   rL   deltar;   r;   r<   rO      s   

zSparkLLM._stream)r4   r   r5   r   )r5   r%   )r5   r2   )NN)
rB   r%   rC   rD   rE   rF   rG   r   r5   r%   )
rB   r%   rC   rD   rE   rF   rG   r   r5   rV   )__name__
__module____qualname____doc__r   __annotations__r   r   r   r    r"   r$   r&   r(   r,   r.   r0   dictr3   r   r=   propertyr?   rA   rU   rO   r;   r;   r;   r<   r      sH   
 X*(r   c                   @  s   e Zd ZdZ			d7d8ddZed9ddZ		d:d;ddZ		d:d<ddZd=d!d"Z	d>d&d'Z
d?d(d)Zd@d+d,Z	dAdBd/d0ZdCdDd5d6ZdS )Er9   z
    Use websocket-client to call the SparkLLM interface provided by Xfyun,
    which is the iFlyTek's open platform for AI capabilities
    Nr   r%   r   r   r!   r   r8   r3   Optional[dict]c                 C  sr   z	dd l }|| _W n ty   tdw |sdn|| _|| _|| _|p%d| _t | _ddd| _	|| _
|| _d S )Nr   zhCould not import websocket client python package. Please install it with `pip install websocket-client`.r6   r7   rH   	assistantrL   rK   )	websocketwebsocket_clientImportErrorr!   r   r3   r8   r   queueblocking_messager   r   )r>   r   r   r   r!   r8   r3   rc   r;   r;   r<   __init__  s"   	



z_SparkLLMClient.__init__r5   c                 C  s   t tt  }t| }|j}|j}d| d| d| d}tj	|
d|
dtjd }t|jdd}	d| d	|	 d
}
t|

djdd}|||d}t|}t|j|j|j|j||jf}|S )zK
        Generate a request url with an api key and an api secret.
        zhost: z
date: z
GET z	 HTTP/1.1zutf-8)	digestmod)encodingz	api_key="zQ", algorithm="hmac-sha256",         headers="host date request-line", signature="")authorizationdatehost)r   r   r   now	timetupler   netlocpathhmacnewencodehashlibsha256digestbase64	b64encodedecoder   r   schemeparamsfragment)r!   r   r   rm   
parsed_urlrn   rr   Zsignature_originZsignature_shaZsignature_sha_base64Zauthorization_originrl   params_dictZencoded_paramsurlr;   r;   r<   _create_url*  s>   
z_SparkLLMClient._create_urlFmessages
List[Dict]user_idr(   r'   Nonec                 C  sl   | j d | j jt| j| j| j| j| j	| j
| jd}||_||_|d u r*| jn||_||_|  d S )NF)
on_messageon_erroron_closeon_open)rd   ZenableTraceZWebSocketAppr9   r   r!   r   r   r   r   r   r   r   r   r3   r(   run_forever)r>   r   r   r3   r(   wsr;   r;   r<   rW   W  s"   z_SparkLLMClient.runthreading.Threadc                 C  s$   t j| j||||fd}|  |S )N)targetargs)	threadingThreadrW   start)r>   r   r   r3   r(   Z	ws_threadr;   r;   r<   rQ   p  s   	z_SparkLLMClient.arunr   r   errorOptional[Any]c                 C  s   | j d|i |  d S )Nr   )rf   putclose)r>   r   r   r;   r;   r<   r     s   z_SparkLLMClient.on_errorclose_status_coder+   close_reasonc                 C  s(   t d||di | jddi d S )Nlog)r   r   doneT)loggerdebugrf   r   )r>   r   r   r   r;   r;   r<   r     s   z_SparkLLMClient.on_closec                 C  s6   ddd| _ t| j|j|j|jd}|| d S )NrH   ra   rb   )r   r   r3   )rg   jsondumps
gen_paramsr   r   r3   send)r>   r   rN   r;   r;   r<   r     s   z_SparkLLMClient.on_openmessagec           	      C  s  t |}|d d }|dkr'| jdd| d|d d  i |  d S |d d	 }|d
 }|d d d }|jrI| jd|d d i n	| jd  |7  < |dkr|jsb| jd| ji |rr|di di di ni }| jd|i |  d S d S )Nheadercoder   r   zCode: z	, Error: r   payloadchoicesstatusrP   rL   rN      usage)r   loadsrf   r   r   r(   rg   get)	r>   r   r   rN   r   r   r   rL   Z
usage_datar;   r;   r<   r     s.   
z_SparkLLMClient.on_messagelistr^   c                 C  sP   | j |ddd| jiidd|iid}|r|d d | td|  |S )	N)r   uidZchatdomainr   rP   )r   	parameterr   r   zSpark Request Parameters: )r   r8   updater   r   )r>   r   r   r3   rN   r;   r;   r<   r     s   

z_SparkLLMClient.gen_paramsr)   r*   Optional[int]Generator[Dict, None, None]c              
   c  s    	 z	| j j|d}W n t jy  } ztd| dd }~ww d|v r+t|d d|v r3|V  qd|v r9d S d|vr?d S |V  q)	NTrM   z-SparkLLMClient wait LLM api response timeout z secondsr   r   r   rN   )rf   r   EmptyTimeoutErrorConnectionError)r>   r*   rL   _r;   r;   r<   rR     s*   
z_SparkLLMClient.subscribe)NNN)r   r%   r   r%   r   r%   r!   r   r8   r   r3   r`   )r!   r%   r   r%   r   r%   r5   r%   )NF)
r   r   r   r%   r3   r`   r(   r'   r5   r   )
r   r   r   r%   r3   r`   r(   r'   r5   r   )r   r   r   r   r5   r   )r   r   r   r+   r   r%   r5   r   )r   r   r5   r   )r   r   r   r%   r5   r   )N)r   r   r   r%   r3   r`   r5   r^   )r)   )r*   r   r5   r   )rY   rZ   r[   r\   rh   staticmethodr   rW   rQ   r   r   r   r   r   rR   r;   r;   r;   r<   r9     s*    
0



	r9   )*
__future__r   ry   rv   rs   r   loggingrf   r   r   r   timer   typingr   r   r   r	   r
   r   urllib.parser   r   r   Zwsgiref.handlersr   Zlangchain_core.callbacksr   Z#langchain_core.language_models.llmsr   Zlangchain_core.outputsr   Zlangchain_core.utilsr   r   Zpydanticr   	getLoggerrY   r   r   r9   r;   r;   r;   r<   <module>   s.     
 m