U
    h+G                  	   @  s  d Z ddlmZ ddlZddl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 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"m#Z#m$Z$ dd
l%m&Z&m'Z'm(Z( ddl)m*Z*m+Z+m,Z, ddl-m.Z. ddl/m0Z0 ddl1m2Z2m3Z3 ddl4m5Z5 er2ddl6m7Z7 ddl8m9Z9 e:e;Z<dZ=dZ>dZ?G dd de@ZAddddddZBdddddd ZCd!d"d#d$d%d&ZDd?d'd(d)d*d+d,ZEG d-d. d.ee*ZFd/dd0d.d1d2d3d4d5d6ZGd@d.d1d8d9d:d;d;d<d=d>ZHdS )AzWrapper around Prem's Chat API.    )annotationsN)TYPE_CHECKINGAnyCallableDictIteratorListOptionalSequenceTupleTypeUnion)CallbackManagerForLLMRun)LanguageModelInput)BaseChatModel)create_base_retry_decorator)	AIMessageAIMessageChunkBaseMessageBaseMessageChunkChatMessageChatMessageChunkHumanMessageHumanMessageChunkSystemMessageSystemMessageChunkToolMessage)ChatGenerationChatGenerationChunk
ChatResult)	BaseModelField	SecretStr)Runnable)BaseTool)get_from_dict_or_envpre_initconvert_to_openai_tool)ChatCompletionResponseStream)ChatCompletionResponsezM
Given the set of tools you used and the response, provide the final answer

z
{json}
z3
tool id: {tool_id}
tool_response: {tool_response}
c                   @  s   e Zd ZdZdS )ChatPremAPIErrorzError with the `PremAI` API.N)__name__
__module____qualname____doc__ r0   r0   J/tmp/pip-unpacked-wheel-9gdii04g/langchain_community/chat_models/premai.pyr+   I   s   r+   strOptional[List[str]])textstopreturnc                 C  s8   |dkr| S |D ]"}|  |}|dkr| d| } q| S )z0Truncates text at the earliest stop token found.N)find)r4   r5   Z
stop_tokenZstop_token_idxr0   r0   r1   _truncate_at_stop_tokensM   s    
r9   r*   r   )responser5   r6   c              	   C  s*  | j stdg }| j D ]}|jj}|dkr<td| dt|jjpHd|d}|dkrftd| |dkr|jd	 }|dkrg }nd
d |D }|t|t||dd q|dkr|t|t	|dd q|t|t
||dd q| jdk	rt|ddd | jD idS t|ddidS dS )z4Converts a Prem API response into a LangChain resultz-ChatResponse must have at least one candidateNzChatResponse z must have a role. )r4   r5   z"ChatResponse must have a content: 	assistant
tool_callsc                 S  s,   g | ]$}|d  |d d |d d dqS )idfunctionname	arguments)r>   r@   argsr0   ).0Z	tool_callr0   r0   r1   
<listcomp>t   s
   

z'_response_to_result.<locals>.<listcomp>)contentr=   )r4   messageuserrE   rolerE   document_chunksc                 S  s   g | ]}|  qS r0   )Zto_dict)rC   chunkr0   r0   r1   rD      s    )generationsZ
llm_output)choicesr+   rF   rJ   r9   rE   appendr   r   r   r   rK   r   )r:   r5   rM   choicerJ   rE   r=   toolsr0   r0   r1   _response_to_result\   sV    

 
 
 	rR   r)   zType[BaseMessageChunk]zdTuple[Union[BaseMessageChunk, HumanMessageChunk, AIMessageChunk, SystemMessageChunk], Optional[str]])r:   default_classr6   c                 C  s   | j d j}|dd}|dd}i }| j d j}|dksD|tkrRt|d|fS |dksb|tkrrt||d|fS |d	ks|tkrt|d|fS |s|tkrt||d
|fS ||d|fS dS )z(Converts delta response to message chunkr   rJ   r;   rE   rG   rH   r<   )rE   additional_kwargssystem)rE   rJ   N)rN   deltagetfinish_reasonr   r   r   r   )r:   rS   Z_deltarJ   rE   rT   Zfinish_reasonsr0   r0   r1   (_convert_delta_response_to_message_chunk   s     
rY   List[BaseMessage]Optional[str]z*Tuple[Optional[str], List[Dict[str, Any]]])input_messagestemplate_idr6   c                 C  s  d}g }| D ]}t |tr(t|j}qt |tr|dkrR|dt|jd nLi }|jdk	rj|jdksxttddt|j|t|j< |d||d qt |t	r|j
dkst|j
dkr|d	t|jd n.|j|j|j|j
d
}|d	tj|dd qt |trqtdqd}| D ]0}t |tr,|j}|j}	|tj||	d7 }q,|dkrt}
|
|7 }
|d|
d ||fS )zcConverts a list of LangChain Messages into a simple dict
    which is the message structure in PremNrG   rI   r;   z9When using prompt template there should be id associated zwith each HumanMessage)rJ   r]   paramsr   r<   )r>   rE   response_metadatar=   )jsonzNo such role explicitly exists)tool_idZtool_response)
isinstancer   r2   rE   r   rO   r>   AssertionError
ValueErrorr   r=   lenr_   !INTERMEDIATE_TOOL_RESULT_TEMPLATEformatr   r+   Ztool_call_idSINGLE_TOOL_PROMPT_TEMPLATETOOL_PROMPT_HEADER)r\   r]   system_promptZexamples_and_messagesZ	input_msgr^   Zai_msg_to_jsonZtool_promptra   Ztool_resultpromptr0   r0   r1   _messages_to_prompt_dict   sj    




 
rl   c                      s\  e Zd ZU 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< eddZ	ded< dZ
ded< eddZded< eddZded< dZd
ed< dZded< dZded< ded< G dd dZed d d!d"d#Zed$d%d&d'Zed(d%d)d*Zdd(d+d,d-Zd=d.d/d0dd1d2d3d4Zd>d.d/d0dd5d2d6d7Zd8dd9d: fd;d<Z  ZS )?
ChatPremAIzPremAI Chat models.

    To use, you will need to have an API key. You can find your existing API Key
    or generate a new one here: https://app.premai.io/api_keys/
    int
project_idNapi_key)defaultaliaszOptional[SecretStr]premai_api_keyZ
model_namer[   model
session_id)rq   zOptional[float]temperaturetop_pzOptional[int]
max_tokens   max_retriesr;   rj   zOptional[dict]repositoriesFOptional[bool]	streamingr   clientc                   @  s   e Zd ZdZdZdZdS )zChatPremAI.ConfigTZforbidN)r,   r-   r.   Zallow_population_by_field_nameZarbitrary_types_allowedextrar0   r0   r0   r1   Config5  s   r   r   )valuesr6   c              
   C  s   zddl m} W n, tk
r< } ztd|W 5 d}~X Y nX z.t|dd}|t|tr\|n|jd|d< W n, tk
r } ztd	|W 5 d}~X Y nX |S )
zFValidate that the package is installed and that the API token is validr   )PremzQCould not import Prem Python package.Please install it with: `pip install premai`Nrs   ZPREMAI_API_KEY)rp   r~   z,Your API Key is incorrect. Please try again.)	premair   ImportErrorr%   rb   r2   Z_secret_value	Exceptionrd   )clsr   r   errorrs   r0   r0   r1   validate_environments:  s,      z ChatPremAI.validate_environmentsr2   )r6   c                 C  s   dS )Nr   r0   selfr0   r0   r1   	_llm_typeR  s    zChatPremAI._llm_typezDict[str, Any]c                 C  s   | j | j| j| j| jdS )Nrt   rj   rv   rx   r{   r   r   r0   r0   r1   _default_paramsV  s    zChatPremAI._default_params)kwargsr6   c                 K  s   ddddddg}g }|D ](}||krt d| d || q|D ]}|| qF| j|}t| j D ],}||d ks||d	krn||d  qn|S )
Nrw   Zfrequency_penaltyZpresence_penaltyZ
logit_biasr5   seedzWARNING: Parameter z is not supported in kwargs.r;   )warningswarnrO   popr   listkeysrW   )r   r   Zkwargs_to_ignoreZkeys_to_removekey
all_kwargsr0   r0   r1   _get_all_kwargs`  s&    
zChatPremAI._get_all_kwargsrZ   r3   "Optional[CallbackManagerForLLMRun]r   )messagesr5   run_managerr   r6   c           	      K  sv   d|krt ||d d\}}nt |\}}|d k	rB|dkrB||d< | jf |}t| f| j|d|d|}t||dS )Nr]   r]   r;   rj   Fro   r   streamr   )r:   r5   )rl   r   chat_with_retryro   rR   )	r   r   r5   r   r   rj   messages_to_passr   r:   r0   r0   r1   	_generatey  s(     	zChatPremAI._generatezIterator[ChatGenerationChunk]c                 k  s  d|krt ||d d\}}nt |\}}|d k	r<td d|kr\|d k	r\|dkr\||d< | jf |}t}t| f| j|d|d|D ]}	zPt|	|d\}
}|d k	rt|d	nd }t	|
|d
}|r|j
|j|d |V  W q tk
r } zW Y qW 5 d }~X Y qX qd S )Nr]   r   z,stop is not supported in langchain streamingrj   r;   Tr   )r:   rS   )rX   )rF   generation_info)rL   )rl   loggerwarningr   r   r   ro   rY   dictr   Zon_llm_new_tokenr4   r   )r   r   r5   r   r   rj   r   r   Zdefault_chunk_classZstreamed_responserL   rX   r   Zcg_chunk_r0   r0   r1   _stream  sR     

 
 
zChatPremAI._streamzDSequence[Union[Dict[str, Any], Type[BaseModel], Callable, BaseTool]]z)Runnable[LanguageModelInput, BaseMessage])rQ   r   r6   c                   s$   dd |D }t  jf d|i|S )Nc                 S  s   g | ]}t |qS r0   r'   )rC   Ztoolr0   r0   r1   rD     s     z)ChatPremAI.bind_tools.<locals>.<listcomp>rQ   )superbind)r   rQ   r   Zformatted_tools	__class__r0   r1   
bind_tools  s    zChatPremAI.bind_tools)NN)NN)r,   r-   r.   r/   __annotations__r!   rs   rt   ru   rv   rw   rx   rz   rj   r{   r}   r   r&   r   propertyr   r   r   r   r   r   __classcell__r0   r0   r   r1   rm      s8   
	     3rm   ry   rz   r   rn   z)Optional[Union[CallbackManagerForLLMRun]]zCallable[[Any], Any])llmrz   r   r6   c                C  s~   ddl }|jjj|jjj|jjj|jjj	|jj
j|jjj|jjj|jjj|jjj|jjj|jjj|jjjg}t|||d}|S )z/Create a retry decorator for PremAI API errors.r   N)Zerror_typesrz   r   )Zpremai.modelsmodelsZapi_response_validation_errorZAPIResponseValidationErrorZconflict_errorZConflictErrorZmodel_not_found_errorZModelNotFoundErrorZpermission_denied_errorZPermissionDeniedErrorZprovider_api_connection_errorZProviderAPIConnectionErrorZprovider_api_status_errorZProviderAPIStatusErrorZprovider_api_timeout_errorZProviderAPITimeoutErrorZprovider_internal_server_errorZProviderInternalServerErrorZprovider_not_found_errorZProviderNotFoundErrorZrate_limit_errorZRateLimitErrorZunprocessable_entity_errorZUnprocessableEntityErrorZvalidation_errorZValidationErrorr   )r   rz   r   r   errors	decoratorr0   r0   r1   create_prem_retry_decorator  s(      r   F
List[dict]boolr   r   )r   ro   r   r   r   r   r6   c                   sF   t   j|d}|ddddddd fdd	}|f |||d
|S )z+Using tenacity for retry in completion callr   Frn   r   r|   r   )ro   r   r   r   r6   c                   s"    j jjjf | ||d|}|S )Nro   r   r   )r~   ZchatZcompletionscreate)ro   r   r   r   r:   r   r0   r1   _completion_with_retry  s    z/chat_with_retry.<locals>._completion_with_retryr   )F)r   rz   )r   ro   r   r   r   r   Zretry_decoratorr   r0   r   r1   r     s    	   r   )N)FN)Ir/   
__future__r   loggingr   typingr   r   r   r   r   r   r	   r
   r   r   r   Zlangchain_core.callbacksr   Zlangchain_core.language_modelsr   Z*langchain_core.language_models.chat_modelsr   Z#langchain_core.language_models.llmsr   Zlangchain_core.messagesr   r   r   r   r   r   r   r   r   r   r   Zlangchain_core.outputsr   r   r   Zlangchain_core.pydantic_v1r    r!   r"   Zlangchain_core.runnablesr#   Zlangchain_core.toolsr$   Zlangchain_core.utilsr%   r&   Z%langchain_core.utils.function_callingr(   Z6premai.api.chat_completions.v1_chat_completions_creater)   Z&premai.models.chat_completion_responser*   	getLoggerr,   r   ri   rf   rh   r   r+   r9   rR   rY   rl   rm   r   r   r0   r0   r0   r1   <module>   sH   44
= H Y"  