
    ihY                        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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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/m0Z0m1Z1m2Z2 d dl3m4Z4m5Z5 d dl6m7Z7 d dl8m9Z9m:Z:m;Z;  ejx                  e=      Z>dZ?dZ@de#deAfdZBdeeCef   de#fdZDdeeCef   dee$   de$fdZE G d de      ZF G d d      ZGy)    N)datetime)Queue)mktime)	AnyDict	GeneratorIteratorListMappingOptionalTypecast)	urlencodeurlparse
urlunparse)format_date_time)CallbackManagerForLLMRun)BaseChatModelgenerate_from_stream)	AIMessageAIMessageChunkBaseMessageBaseMessageChunkChatMessageChatMessageChunkFunctionMessageChunkHumanMessageHumanMessageChunkSystemMessageToolMessageChunk)make_invalid_tool_callparse_tool_call)ChatGenerationChatGenerationChunk
ChatResult)get_from_dict_or_envget_pydantic_field_names)
get_fields)
ConfigDictFieldmodel_validatorz$wss://spark-api.xf-yun.com/v3.5/chatzgeneralv3.5messagereturnc                    t        | t              rd| j                  d}|S t        | t              rd| j                  d}|S t        | t              rkd| j                  d}d| j
                  v r| j
                  d   |d<   |d   dk(  rd |d<   d| j
                  v r| j
                  d   |d<   |d   dk(  rd |d<   |S t        | t              rd| j                  d}|S t        d	|        )
Nuser)rolecontent	assistantfunction_callr1    
tool_callssystemzGot unknown type )
isinstancer   r1   r   r   additional_kwargsr   
ValueError)r,   message_dicts     f/var/www/html/dev/engine/venv/lib/python3.12/site-packages/langchain_community/chat_models/sparkllm.pyconvert_message_to_dictr<   9   s   ';' &7??C( ' 
G\	* &7??C$ # 
GY	' +Hg777,3,E,Eo,VL)I&",*.Y'7444)0)B)B<)PL&I&",*.Y'  
G]	+ (W__E  ,WI677    _dictc           
         | d   }| d   }|dk(  rt        |      S |dk(  r~g }i }| j                  d      x}rt        |      |d<   g }| j                  d      x}r-||d<   | d   D ]  }	 |j                  t	        |d	             ! ni }|xs d
}
t        |
|||      S |dk(  rt        |      S t        ||      S # t
        $ r.}	|j                  t        |t        |	                   Y d }	~	d }	~	ww xY w)Nr0   r1   r/   r1   r2   r3   r5   T)	return_idr4   )r1   r8   r5   invalid_tool_callsr6   r1   r0   )r   getdictappendr"   	Exceptionr!   strr   r   r   )r>   msg_rolemsg_contentrB   r8   r3   r5   raw_tool_callsraw_tool_caller1   s              r;   convert_dict_to_messagerN   S   s2   V}H	"K6K00	[	 "$!IIo66=615m1Do.
"YY|44>4.<l+!&|!4 %%omt&TU !##/!1	
 	
 
X	[11;X>>! ! &--.}c!fE s   )B==	C4$C//C4default_classc                 D   t        t        | j                  d            }t        t        | j                  d      xs d      }i }| j                  d      r!t        | d         }d|v r
|d   d|d<   ||d<   | j                  d      r| d   |d<   |dk(  s	|t        k(  rt	        |      S |d	k(  s	|t
        k(  rt        ||
      S |dk(  s	|t        k(  rt        || d         S |dk(  s	|t        k(  rt        || d         S |s	|t        k(  rt        ||      S  ||      S )Nr0   r1   r4   r3   namer5   r/   r@   r2   )r1   r8   function)r1   rQ   tooltool_call_id)r1   rT   rC   )	r   rH   rD   rE   r   r   r   r    r   )r>   rO   rI   rJ   r8   r3   s         r;   _convert_delta_to_message_chunkrU   v   s5    C6*+HsEIIi06B7K yy!U?34]"}V'<'D$&M&!-:/*yy*/*=,'6].?? 55	[	 M^$CkEVWW	Z	=4H#H#KeFmLL	V	}0@@%BWXX	]&66(CC[11r=   c                      e Zd ZU dZedefd       Zedee	e	f   fd       Z
dZeed<    edd      Zee	   ed	<   	  edd
      Zee	   ed<   	  edd      Zee	   ed<   	  edd      Zee	   ed<   	  edd      Zee	   ed<   	 dZe	ed<   dZeed<   	  edd      Zeed<   	  ed      Zeed<   	 dZeed<   	  ee      Zee	ef   ed <   	  ed!"      Z e d#$      ed%edefd&              Z! e d#$      ed%ee	ef   defd'              Z"	 	 d0d(e#e$   d)ee#e	      d*ee%   d+ede&e'   f
d,Z(	 	 	 d1d(e#e$   d)ee#e	      d*ee%   d-ee   d+ede)fd.Z*ede	fd/       Z+y)2ChatSparkLLMu-  IFlyTek Spark chat model integration.

    Setup:
        To use, you should have the environment variable``IFLYTEK_SPARK_API_KEY``,
        ``IFLYTEK_SPARK_API_SECRET`` and ``IFLYTEK_SPARK_APP_ID``.

    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:
        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.chat_models import ChatSparkLLM

            chat = ChatSparkLLM(
                api_key="your-api-key",
                api_secret="your-api-secret",
                model='Spark4.0 Ultra',
                # temperature=...,
                # other params...
            )

    Invoke:
        .. code-block:: python

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

        .. code-block:: python

            AIMessage(
                content='I like programming.',
                response_metadata={
                    'token_usage': {
                        'question_tokens': 3,
                        'prompt_tokens': 16,
                        'completion_tokens': 4,
                        'total_tokens': 20
                    }
                },
                id='run-af8b3531-7bf7-47f0-bfe8-9262cb2a9d47-0'
            )

    Stream:
        .. code-block:: python

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

        .. code-block:: python

            content='I' id='run-fdbb57c2-2d32-4516-b894-6c5a67605d83'
            content=' like programming' id='run-fdbb57c2-2d32-4516-b894-6c5a67605d83'
            content='.' id='run-fdbb57c2-2d32-4516-b894-6c5a67605d83'

        .. 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-aca2fa82-c2e4-4835-b7e2-865ddd3c46cb'
            )

    Response metadata
        .. code-block:: python

            ai_msg = chat.invoke(messages)
            ai_msg.response_metadata

        .. code-block:: python

            {
                'token_usage': {
                    'question_tokens': 3,
                    'prompt_tokens': 16,
                    'completion_tokens': 4,
                    'total_tokens': 20
                }
            }

    r-   c                      y)z9Return whether this model can be serialized by Langchain.F )clss    r;   is_lc_serializablezChatSparkLLM.is_lc_serializable  s     r=   c                     ddddddS )NIFLYTEK_SPARK_APP_IDIFLYTEK_SPARK_API_KEYIFLYTEK_SPARK_API_SECRETIFLYTEK_SPARK_API_URLIFLYTEK_SPARK_LLM_DOMAIN)spark_app_idspark_api_keyspark_api_secretspark_api_urlspark_llm_domainrY   selfs    r;   
lc_secretszChatSparkLLM.lc_secrets  s     34 :4 :
 	
r=   Nclientapp_id)defaultaliasrb   api_keyrc   
api_secretrd   api_urlre   modelrf   lc_userspark_user_idF	streaming   timeout)rm   request_timeoutg      ?)rl   temperature   top_k)default_factorymodel_kwargsT)populate_by_namebefore)modevaluesc           	         t        |ddgd      |d<   t        |ddgd      |d<   t        |ddgd	      |d<   t        |d
dt              |d
<   t        |ddt              |d<   t        |       j	                         D ci c]  \  }}|j
                  ||j
                    }}}|j                  d      |d   d<   |j                  d      |d   d<   t        |d   |d   |d   |d
   |d   |d         |d<   |S c c}}w )Nrb   rk   r]   rc   rn   r^   rd   ro   r_   re   r`   rf   ra   rx   r|   rz   )rk   rn   ro   rp   spark_domainr|   rj   )r&   SPARK_API_URLSPARK_LLM_DOMAINr(   itemsrl   rD   _SparkLLMClient)rZ   r   rQ   fielddefault_valuess        r;   validate_environmentz!ChatSparkLLM.validate_environment/  sa    "6X&""
~
 #7i(##

 &:.&&
!"
 #7#	#
 &:&	&
!"  *#446
e}}( %--
 

 1?0B0B=0Q~}-*8*<*<W*E~w'*.)?+01?+ 23/
x !
s   =#C9c           
      `   t        |       }|j                  di       }t        |      D ]M  }||v rt        d| d      ||vst        j                  d| d| d| d       |j                  |      ||<   O |j                  |j                               }|rt        d| d	      ||d<   |S )
z>Build extra kwargs from additional params that were passed in.r|   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   listr9   loggerwarningpopintersectionkeys)rZ   r   all_required_field_namesextra
field_nameinvalid_model_kwargss         r;   build_extrazChatSparkLLM.build_extrae  s     $<C#@ 

>2.v, 		;JU" 6*5E!FGG!99!* .L !))34JN
 %+JJz$:j!		;  8DDUZZ\R23 4S T 
 "'~r=   messagesstoprun_managerkwargsc              +     K   t         }| j                  j                  |D cg c]  }t        |       c}| j                  | j
                  d       | j                  j                  | j                        D ]P  }d|vr|d   }t        ||      }	t        |	      }
|r&|j                  t        |	j                        |
       |
 R y c c}w w)NT)rt   rv   datar,   )chunk)r   rj   arunr<   rs   r|   	subscriberw   rU   r$   on_llm_new_tokenrH   r1   )rh   r   r   r   r   default_chunk_classmr1   deltar   cg_chunks              r;   _streamzChatSparkLLM._stream  s      -19:A$Q':	 	 	
 {{,,T5I5I,J 	GW$FOE3E;NOE*59H,,S-?x,PN	 ;s    CCBCstreamc                    |s| j                   r! | j                  d	|||d|}t        |      S | j                  j	                  |D cg c]  }t        |       c}| j                  | j                  d       i }i }	| j                  j                  | j                        D ]  }
d|
v r|
d   |	d<   d|
vr|
d   } t        |      }t        |      g}t        ||	      S c c}w )
N)r   r   r   Fr   usagetoken_usager   r   )generations
llm_outputrY   )rt   r   r   rj   r   r<   rs   r|   r   rw   rN   r#   r%   )rh   r   r   r   r   r   stream_iterr   
completionr   r1   r,   r   s                r;   	_generatezChatSparkLLM._generate  s    T^^&$,, !+IOK (4419:A$Q':		
 

{{,,T5I5I,J 	)G'!,3G,<
=)W$ J	) **5%g67kjII ;s   	C#c                      y)Nzspark-llm-chatrY   rg   s    r;   	_llm_typezChatSparkLLM._llm_type  s    r=   )NNNNN),__name__
__module____qualname____doc__classmethodboolr[   propertyr   rH   ri   rj   r   __annotations__r*   rb   r   rc   rd   re   rf   rs   rt   rw   intrx   floatrz   rE   r|   r)   model_configr+   r   r   r
   r   r   r	   r$   r   r%   r   r   rY   r=   r;   rW   rW      s   m^ 4   
DcN 
 
 FC"'H"EL(3-E#(Y#GM8C=G&+D&MhsmM#(Y#GM8C=G&+D&HhsmH"M3"It/ 95OS50s+K++E3N.#(#>L$sCx.>QL (#.$ .3 .  $.h (#c3h C   $: %):>	{# tCy! 67	
  
%	&8 %):>!%J{#J tCy!J 67	J
 J J 
J@  3    r=   rW   c                   x   e Zd ZdZ	 	 	 ddedededee   dee   dee   fd	Zedededed
efd       Z		 	 dde
e   dedee   ded
df
dZ	 	 dde
e   dedee   ded
ej                  f
dZdedee   d
dfdZdededed
dfdZded
dfdZdeded
dfdZ	 ddededee   d
efdZd dee   d
eeddf   fdZy)!r   z
    Use websocket-client to call the SparkLLM interface provided by Xfyun,
    which is the iFlyTek's open platform for AI capabilities
    Nrk   rn   ro   rp   r   r|   c                     	 dd l }|| _        |st        n|| _        || _        || _        |xs t        | _        t               | _
        ddd| _        || _        || _        y # t        $ r t        d      w xY w)Nr   zhCould not import websocket client python package. Please install it with `pip install websocket-client`.r4   r2   rC   )	websocketwebsocket_clientImportErrorr   rp   rk   r|   r   r   r   queueblocking_messagern   ro   )rh   rk   rn   ro   rp   r   r|   r   s           r;   __init__z_SparkLLMClient.__init__  s    	$-D! -4}((<,<"''
,. D$  	I 	s   A! !A6r-   c                    t        t        t        j                         j	                                     }t        |       }|j                  }|j                  }d| d| d| d}t        j                  |j                  d      |j                  d      t        j                        j                         }t        j                  |      j!                  d      }	d| d	|	 d
}
t        j                  |
j                  d            j!                  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)rp   rn   ro   r   
parsed_urlr   r   signature_originsignature_shasignature_sha_base64authorization_originr   params_dictencoded_paramsurls                  r;   _create_urlz_SparkLLMClient._create_url  sf     x||~'?'?'A BC g&
  #D6$vdV9M g&##G,nn
 &(	 	  &//>EEwEW!*7) 466J5K1 N(()=)D)DW)MNUU V 

 )6tTR";/!!!!!!##	
 
r=   r   user_idrt   c                    | j                   j                  d       | j                   j                  t        j	                  | j
                  | j                  | j                        | j                  | j                  | j                  | j                        }||_        ||_        || j                  n||_        ||_        |j!                          y )NF)
on_messageon_erroron_closeon_open)r   enableTraceWebSocketAppr   r   rp   rn   ro   r   r   r   r   r   r   r|   rt   run_forever)rh   r   r   r|   rt   wss         r;   runz_SparkLLMClient.run  s     	))%0""//''
 ]]]]LL 0 

 
/;/C$++ 
r=   c                 p    t        j                  | j                  ||||f      }|j                          |S )N)targetargs)	threadingThreadr   start)rh   r   r   r|   rt   	ws_threads         r;   r   z_SparkLLMClient.arun'  s>     $$88	
	 	r=   r   errorc                 ^    | j                   j                  d|i       |j                          y )Nr   )r   putclose)rh   r   r   s      r;   r   z_SparkLLMClient.on_error:  s     

'(

r=   close_status_codeclose_reasonc                 r    t         j                  d||di       | j                  j                  ddi       y )Nlog)r   r   doneT)r   debugr   r   )rh   r   r   r   s       r;   r   z_SparkLLMClient.on_close>  s7    ):$0	
 	

~&r=   c                     ddd| _         t        j                  | j                  |j                  |j
                  |j                              }|j                  |       y )Nr4   r2   rC   )r   r   r|   )r   jsondumps
gen_paramsr   r   r|   send)rh   r   r   s      r;   r   z_SparkLLMClient.on_openI  sN    ,. DzzOObjjr  

 	r=   r,   c                    t        j                  |      }|d   d   }|dk7  r:| j                  j                  dd| d|d   d    i       |j	                          y |d   d	   }|d
   }|d   d   d   }|j
                  r$| j                  j                  d|d   d   i       n| j                  dxx   |z  cc<   |dk(  r|j
                  s'| j                  j                  d| j                  i       |r2|j                  di       j                  di       j                  di       ni }| j                  j                  d|i       |j	                          y y )Nheadercoder   r   zCode: z	, Error: r,   payloadchoicesstatustextr1   r      r   )r  loadsr   r   r   rt   r   rD   )	rh   r   r,   r   r	  r  r  r1   
usage_datas	            r;   r   z_SparkLLMClient.on_messageR  sJ   zz'"H~f%19JJNNF4&	$x.2K1LMN HHJ9oi0GX&Ffoa(3G||

(:;<%%i0G;0{||JJNNFD,A,A#BC  HHY+//<@@L 
 

45
 r=   c                     | j                   |ddd| j                  iidd|iid}|r|d   d   j                  |       t        j	                  d|        |S )	N)rk   uidchatdomainr,   r  )r  	parameterr
  r  zSpark Request Parameters: )rk   r   updater   r  )rh   r   r   r|   r   s        r;   r  z_SparkLLMClient.gen_paramsm  sm     "&W= 8T->->"?@!FH#56
 f%,,\:1$89r=   rv   c              #      K   	 	 | j                   j                  |      }d|v rt	        |d         d|v r| 9d|v ry d|vry | G# t         j                  $ r}t        d| d      d }~ww xY ww)Nr   z-SparkLLMClient wait LLM api response timeout z secondsr   r   r   r   )r   rD   EmptyTimeoutErrorConnectionError)rh   rv   r1   _s       r;   r   z_SparkLLMClient.subscribe{  s     **...9
 '!%gg&677'! W$M!  ;; "CG9HU s'   A5A *A5A2A--A22A5r   )NF)N)ru   )r   r   r   r   rH   r   rE   r   staticmethodr   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r   r   rY   r=   r;   r   r     s    "&&*'+%% % 	%
 #% sm% tn%8 *S *3 *C *C * *` (,t*  tn	
  
: (,t*  tn	
  
		&3 x}  	'3 	'3 	'c 	'd 	'# $ S 3 4 8 LP'*:B4.	# 	$dBR8S r=   r   )Hr   r   r   r  loggingr   r   r   r   timer   typingr   r   r   r	   r
   r   r   r   r   urllib.parser   r   r   wsgiref.handlersr   langchain_core.callbacksr   *langchain_core.language_models.chat_modelsr   r   langchain_core.messagesr   r   r   r   r   r   r   r   r   r   r    *langchain_core.output_parsers.openai_toolsr!   r"   langchain_core.outputsr#   r$   r%   langchain_core.utilsr&   r'   langchain_core.utils.pydanticr(   pydanticr)   r*   r+   	getLoggerr   r   r   r   rE   r<   rH   rN   rU   rW   r   rY   r=   r;   <module>r+     s             V V V 8 8 -    
 5 7 7			8	$6  [ T 4 ?738#4  ?  ?F2382-12B-C226k = k \	M Mr=   