U
    h3                     @   s  d Z 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 ddlmZ ddlmZ ddlmZ ddlmZ ed	eee
e f d
Zedeee
e
e  e	f d
ZG dd dZG dd deeef ZG dd deeef ZG dd deZdS )zSagemaker InvokeEndpoint API.    N)abstractmethod)	AnyDictGenericIteratorListMappingOptionalTypeVarUnion)CallbackManagerForLLMRun)LLM)pre_init)enforce_stop_tokens
INPUT_TYPE)boundOUTPUT_TYPEc                   @   s<   e Zd ZdZeddddZd dddZedd	d
ZdS )LineIteratora  Parse the byte stream input.

    The output of the model will be in the following format:

    b'{"outputs": [" a"]}
'
    b'{"outputs": [" challenging"]}
'
    b'{"outputs": [" problem"]}
'
    ...

    While usually each PayloadPart event from the event stream will
    contain a byte array with a full json, this is not guaranteed
    and some of the json objects may be split acrossPayloadPart events.

    For example:

    {'PayloadPart': {'Bytes': b'{"outputs": '}}
    {'PayloadPart': {'Bytes': b'[" problem"]}
'}}


    This class accounts for this by concatenating bytes written via the 'write' function
    and then exposing a method which will return lines (ending with a '
' character)
    within the buffer via the 'scan_lines' function.
    It maintains the position of the last read position to ensure
    that previous bytes are not exposed again.

    For more details see:
    https://aws.amazon.com/blogs/machine-learning/elevating-the-generative-ai-experience-introducing-streaming-support-in-amazon-sagemaker-hosting/
    N)streamreturnc                 C   s   t || _t | _d| _d S )Nr   )iterbyte_iteratorioBytesIObufferread_pos)selfr    r   O/tmp/pip-unpacked-wheel-9gdii04g/langchain_community/llms/sagemaker_endpoint.py__init__0   s    

zLineIterator.__init__r   c                 C   s   | S )Nr   r   r   r   r   __iter__5   s    zLineIterator.__iter__c                 C   s   | j | j | j  }|rJ|d tdkrJ|  jt|7  _|d d S zt| j}W n, tk
r   | j| j 	 j
k r~Y q  Y nX d|krq | j dtj | j |d d  q d S )N
ZPayloadPartr   ZBytes)r   seekr   readlineordlennextr   StopIteration	getbuffernbytesr   SEEK_ENDwrite)r   linechunkr   r   r   __next__8   s    
zLineIterator.__next__)__name__
__module____qualname____doc__r   r   r"   r1   r   r   r   r   r      s   r   c                   @   s\   e Zd ZU dZdZee ed< dZee ed< e	e
eedddZe	eedd	d
ZdS )ContentHandlerBasezHandler class to transform input from LLM to a
    format that SageMaker endpoint expects.

    Similarly, the class handles transforming output from the
    SageMaker endpoint to a format that LLM class expects.
    z
text/plaincontent_typeaccepts)promptmodel_kwargsr   c                 C   s   dS )zTransforms the input to a format that model can accept
        as the request Body. Should return bytes or seekable file
        like object in the format specified in the content_type
        request header.
        Nr   )r   r9   r:   r   r   r   transform_inputk   s    z"ContentHandlerBase.transform_input)outputr   c                 C   s   dS )z[Transforms the output from the model to string that
        the LLM class expects.
        Nr   )r   r<   r   r   r   transform_outputs   s    z#ContentHandlerBase.transform_outputN)r2   r3   r4   r5   r7   r	   str__annotations__r8   r   r   r   bytesr;   r   r=   r   r   r   r   r6   L   s   
r6   c                   @   s   e Zd ZdZdS )LLMContentHandlerzContent handler for LLM class.N)r2   r3   r4   r5   r   r   r   r   rA   z   s   rA   c                   @   s   e Zd ZU dZdZeed< dZeed< dZ	eed< dZ
ee ed< eed< d	Zeed
< dZee ed< dZee ed< G dd dZeeedddZeeeef dddZeedddZdeeee  ee eedddZdS )SagemakerEndpointa  Sagemaker Inference Endpoint models.

    To use, you must supply the endpoint name from your deployed
    Sagemaker model & the region where it is deployed.

    To authenticate, the AWS client uses the following methods to
    automatically load credentials:
    https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html

    If a specific credential profile should be used, you must pass
    the name of the profile from the ~/.aws/credentials file that is to be used.

    Make sure the credentials / roles used have the required policies to
    access the Sagemaker endpoint.
    See: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html
    Nclient endpoint_nameregion_namecredentials_profile_namecontent_handlerF	streamingr:   endpoint_kwargsc                   @   s   e Zd ZdZdS )zSagemakerEndpoint.ConfigZforbidN)r2   r3   r4   extrar   r   r   r   Config   s   rL   )valuesr   c              
   C   s   | ddk	r|S zzddl}z@|d dk	r<|j|d d}n| }|jd|d d|d< W n, tk
r } ztd	|W 5 d}~X Y nX W n tk
r   td
Y nX |S )z.Dont do anything if client provided externallyrC   Nr   rG   )Zprofile_namezsagemaker-runtimerF   )rF   zCould not load credentials to authenticate with AWS client. Please check that credentials in the specified profile name are valid.zRCould not import boto3 python package. Please install it with `pip install boto3`.)getboto3SessionrC   	Exception
ValueErrorImportError)clsrM   rO   sessioner   r   r   validate_environment   s2     
z&SagemakerEndpoint.validate_environmentr    c                 C   s   | j pi }d| jid|iS )zGet the identifying parameters.rE   r:   )r:   rE   )r   _model_kwargsr   r   r   _identifying_params  s    
z%SagemakerEndpoint._identifying_paramsc                 C   s   dS )zReturn type of llm.Zsagemaker_endpointr   r!   r   r   r   	_llm_type(  s    zSagemakerEndpoint._llm_type)r9   stoprun_managerkwargsr   c              
   K   sv  | j pi }||}| jpi }| j||}| jj}| jj}	| jr|rz|| jjf | j	|| jjd|}
t
|
d }d}|D ]@}t|}
|
dd }|dk	rt||}||7 }|| qz|W S  tk
r } ztd| W 5 d}~X Y nX n~z"| jjf | j	|||	d|}W n2 tk
rH } ztd	| W 5 d}~X Y nX | j|d }|dk	rnt||}|S dS )
af  Call out to Sagemaker inference endpoint.

        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 model.

        Example:
            .. code-block:: python

                response = se("Tell me a joke.")
        )EndpointNameBodyContentTyper_   rD   outputsr   Nz.Error raised by streaming inference endpoint: )r^   r_   r`   Acceptz$Error raised by inference endpoint: )r:   rJ   rH   r;   r7   r8   rI   rC   Z$invoke_endpoint_with_response_streamrE   r   jsonloadsrN   r   Zon_llm_new_tokenrQ   rR   Zinvoke_endpointr=   )r   r9   r[   r\   r]   rX   Z_endpoint_kwargsbodyr7   r8   respiteratorZcurrent_completionr/   Zresp_outputrV   responsetextr   r   r   _call-  sT    




"
 

zSagemakerEndpoint._call)NN)r2   r3   r4   r5   rC   r   r?   rE   r>   rF   rG   r	   rA   rI   boolr:   r   rJ   rL   r   rW   propertyr   rY   rZ   r   r   rj   r   r   r   r   rB   ~   s2   
A$  
rB   )r5   r   rc   abcr   typingr   r   r   r   r   r   r	   r
   r   Zlangchain_core.callbacksr   Z#langchain_core.language_models.llmsr   Zlangchain_core.utilsr   Zlangchain_community.llms.utilsr   r>   r   floatr   r   r6   rA   rB   r   r   r   r   <module>   s   ,:.