a
    bgo>                     @  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                   @  s@  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d#d#d$d%d&Zedd'd(d)Zed!d'd*d+Zd4dd,d-ddd.d/d0Zd5dd,d-dd1d.d2d3ZdS )6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_factoryzDict[str, Any]model_kwargsr   )values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 pt| j|d d< |d p| 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.   r2   r0   r   r   r   r!   spark_domainr2   r   )r   r.   r0   _SparkLLMClient)clsr3    r;   o/var/www/html/cobodadashboardai.evdpl.com/venv/lib/python3.9/site-packages/langchain_community/llms/sparkllm.pyvalidate_environment   sL    
zSparkLLM.validate_environment)r4   c                 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.   r2   )r>   Znormal_paramsr;   r;   r<   _default_params   s    zSparkLLM._default_paramszOptional[List[str]]z"Optional[CallbackManagerForLLMRun])promptstoprun_managerkwargsr4   c                 K  s   | j r4d}| j|||fi |D ]}||j7 }q |S d}| jd|dg| j| j| j  | jj| jdD ]}d|vrvqh|d d }qh|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*   datarJ   )	r(   _streamtextr   arunr&   r2   	subscriber,   )r>   rB   rC   rD   rE   
completionchunkrJ   r;   r;   r<   _call   s"    
zSparkLLM._callzIterator[GenerationChunk]c                 k  sh   | j d|dg| j| jd | j j| jdD ]4}d|vr<q.|d }|rR|| t|d dV  q.d S )NrG   rH   TrK   rL   rJ   )rN   )r   runr&   r2   rP   r,   Zon_llm_new_tokenr   )r>   rB   rC   rD   rE   rJ   deltar;   r;   r<   rM      s    

zSparkLLM._stream)NN)NN)__name__
__module____qualname____doc__r   __annotations__r   r   r   r    r"   r$   r&   r(   r,   r.   r0   dictr2   r   r=   propertyr?   rA   rS   rM   r;   r;   r;   r<   r      s2   
X*  (  r   c                   @  s   e Zd ZdZd0dddddddddZeddddd	d
dZd1ddddddddZd2ddddddddZddddddZ	dddddddZ
dddd d!Zdddd"d#d$Zd3d%ddd&d'd(d)Zd4d+d,d-d.d/ZdS )5r9   z
    Use websocket-client to call the SparkLLM interface provided by Xfyun,
    which is the iFlyTek's open platform for AI capabilities
    Nr%   r   zOptional[dict]r7   c                 C  sv   zdd l }|| _W n ty,   tdY n0 |s6dn|| _|| _|| _|pNd| _t | _ddd| _	|| _
|| _d S )Nr   zhCould not import websocket client python package. Please install it with `pip install websocket-client`.r5   r6   rF   	assistantrJ   rI   )	websocketwebsocket_clientImportErrorr!   r   r2   r8   r   queueblocking_messager   r   )r>   r   r   r   r!   r8   r2   r_   r;   r;   r<   __init__  s     	



z_SparkLLMClient.__init__)r!   r   r   r4   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   ri   
parsed_urlrj   rn   Zsignature_originZsignature_shaZsignature_sha_base64Zauthorization_originrh   params_dictZencoded_paramsurlr;   r;   r<   _create_url*  s:    

z_SparkLLMClient._create_urlFz
List[Dict]r'   None)messagesuser_idr2   r(   r4   c                 C  sl   | j d | j jt| j| j| j| j| j	| j
| jd}||_||_|d u rT| jn||_||_|  d S )NF)
on_messageon_erroron_closeon_open)r`   ZenableTraceZWebSocketAppr9   r~   r!   r   r   r   r   r   r   r   r   r2   r(   run_forever)r>   r   r   r2   r(   wsr;   r;   r<   rT   W  s"    z_SparkLLMClient.runzthreading.Threadc                 C  s$   t j| j||||fd}|  |S )N)targetargs)	threadingThreadrT   start)r>   r   r   r2   r(   Z	ws_threadr;   r;   r<   rO   p  s    	z_SparkLLMClient.arunr   zOptional[Any])r   errorr4   c                 C  s   | j d|i |  d S )Nr   )rb   putclose)r>   r   r   r;   r;   r<   r     s    z_SparkLLMClient.on_errorr+   )r   close_status_codeclose_reasonr4   c                 C  s(   t d||di | jddi d S )Nlog)r   r   doneT)loggerdebugrb   r   )r>   r   r   r   r;   r;   r<   r     s    z_SparkLLMClient.on_close)r   r4   c                 C  s6   ddd| _ t| j|j|j|jd}|| d S )NrF   r]   r^   )r   r   r2   )rc   jsondumps
gen_paramsr   r   r2   send)r>   r   rL   r;   r;   r<   r     s    z_SparkLLMClient.on_open)r   messager4   c           	      C  s  t |}|d d }|dkrL| jdd| d|d d  i |  n|d d	 }|d
 }|d d d }|jr| jd|d d i n| jd  |7  < |dkr|js| jd| ji |r|di di di ni }| jd|i |  d S )Nheadercoder   r   zCode: z	, Error: r   payloadchoicesstatusrN   rJ   rL      usage)r   loadsrb   r   r   r(   rc   get)	r>   r   r   rL   r   r   r   rJ   Z
usage_datar;   r;   r<   r     s,    

z_SparkLLMClient.on_messagelistr[   )r   r   r2   r4   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   rN   )r   	parameterr   r   zSpark Request Parameters: )r   r8   updater   r   )r>   r   r   r2   rL   r;   r;   r<   r     s    

z_SparkLLMClient.gen_paramsr)   zOptional[int]zGenerator[Dict, None, None])r*   r4   c              
   c  s   z| j j|d}W n6 t jyH } ztd| dW Y d }~n
d }~0 0 d|v r^t|d d|v rn|V  q d|v rxqd|vrq|V  q d S )NrK   z-SparkLLMClient wait LLM api response timeout z secondsr   r   r   rL   )rb   r   EmptyTimeoutErrorConnectionError)r>   r*   rJ   _r;   r;   r<   rP     s     
z_SparkLLMClient.subscribe)NNN)NF)NF)N)r)   )rV   rW   rX   rY   rd   staticmethodr~   rT   rO   r   r   r   r   r   rP   r;   r;   r;   r<   r9     s(   
   0    	 r9   )*
__future__r   ru   rr   ro   r   loggingrb   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   	getLoggerrV   r   r   r9   r;   r;   r;   r<   <module>   s,    
 m