U
    h	j                     @  s  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mZmZ d dlZd dlZd dlmZmZ d dl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#m$Z$m%Z%m&Z& e'e(Z)d
ddddddZ*dddddZ+G dd deZ,G dd de,Z-dS )    )annotationsN)AbstractSetAnyAsyncIterator
CollectionDictIteratorListLiteralMappingOptionalSetTupleUnion)AsyncCallbackManagerForLLMRunCallbackManagerForLLMRun)BaseLLM)
GenerationGenerationChunk	LLMResult)Field	SecretStrroot_validator)get_pydantic_field_names)build_extra_kwargsfrom_envsecret_from_envzSet[str]Dict[str, Any]None)keysresponsetoken_usagereturnc                 C  sN   |  |d }|D ]6}||kr0|d | ||< q||  |d | 7  < qdS )zUpdate token usage.usageN)intersection)r   r    r!   Z_keys_to_use_key r&   >/tmp/pip-unpacked-wheel-n8reftby/langchain_openai/llms/base.py_update_token_usage$   s
    r(   r   )stream_responser"   c                 C  sR   | d st ddS t | d d d t| d d dd| d d ddd	d
S )z0Convert a stream response to a generation chunk.choices )textr   r,   finish_reasonNlogprobsr-   r.   r,   generation_info)r   dictget)r)   r&   r&   r'   $_stream_response_to_generation_chunk0   s    
r4   c                      sZ  e Zd ZU dZ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< dZded< dZde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edddd Zd!ed"< ed#ed$ddd Zd%ed&< ed'ed(d)gddd Zd%ed*< eed+dddZd%ed,< d-Zded.< edd/d
Zd0ed1< eedZd2ed3< d4Zded5< dZd6ed7< dZd6ed8< d9Zd:ed;< e Z d<ed=< d>Z!d?ed@< dZ"d%edA< dZ#dBedC< dZ$dDedE< dZ%dFedG< dZ&dFedH< dZ'dIedJ< G dKdL dLZ(e)ddMdddNdOdPZ*e)d9dddQdRdRdNdSdTZ+e,ddUdVdWZ-dddXdYddZd[d\d]Z.dddXd^dd_d[d`daZ/ddbdXdYddcdddedfZ0ddbdXd^ddcdddgdhZ1dddbdXdidjdkdlZ2ddmddbddnd%dcdodpdqZ3e,ddUdrdsZ4e,dtdUdudvZ5e,ddUdwdxZ6ddydz fd{d|Z7e8ddd}d~dZ9e,ddUddZ:dddddZ;  Z<S )
BaseOpenAIz'Base OpenAI large language model class.NT)defaultexcluder   clientasync_clientgpt-3.5-turbo-instructmodel)r6   aliasstr
model_namegffffff?floattemperature   int
max_tokens   top_pr   frequency_penaltypresence_penaltynbest_of)default_factoryr   model_kwargsapi_keyOPENAI_API_KEY)r6   )r<   rJ   zOptional[SecretStr]openai_api_keybase_urlZOPENAI_API_BASEzOptional[str]openai_api_baseorganizationZOPENAI_ORG_IDZOPENAI_ORGANIZATIONopenai_organizationZOPENAI_PROXYopenai_proxy   
batch_sizetimeoutz,Union[float, Tuple[float, float], Any, None]request_timeoutzOptional[Dict[str, float]]
logit_bias   max_retrieszOptional[int]seedr.   Fbool	streamingz'Union[Literal['all'], AbstractSet[str]]allowed_specialallz&Union[Literal['all'], Collection[str]]disallowed_specialtiktoken_model_namezUnion[Mapping[str, str], None]default_headersz!Union[Mapping[str, object], None]default_queryzUnion[Any, None]http_clienthttp_async_clientzOptional[Mapping[str, Any]]
extra_bodyc                   @  s   e Zd ZdZdZdS )zBaseOpenAI.Configz'Configuration for this pydantic object.TN)__name__
__module____qualname____doc__Zallow_population_by_field_namer&   r&   r&   r'   Config   s   rk   )pre)valuesr"   c                 C  s(   t | }|di }t||||d< |S )z>Build extra kwargs from additional params that were passed in.rK   )r   r3   r   )clsrm   Zall_required_field_namesextrar&   r&   r'   build_extra   s      zBaseOpenAI.build_extra)rl   Zskip_on_failureZallow_reuser   c                 C  s   |d dk rt d|d r0|d dkr0t d|d rL|d dkrLt d|d r`|d  nd	|d
 |d |d |d |d |d d}|dsd|d i}tjf ||j|d< |dsd|d i}tjf ||j|d< |S )z?Validate that api key and python package exists in environment.rH   rD   zn must be at least 1.r]   z!Cannot stream results when n > 1.rI   z'Cannot stream results when best_of > 1.rN   NrR   rP   rW   rZ   rb   rc   )rL   rQ   rO   rV   rZ   rb   rc   r8   rd   r9   re   )
ValueErrorZget_secret_valuer3   openaiOpenAIZcompletionsZAsyncOpenAI)rn   rm   Zclient_paramsZsync_specificZasync_specificr&   r&   r'   validate_environment   s:    
 
 zBaseOpenAI.validate_environmentr"   c              	   C  sl   | j | j| j| j| j| j| j| jd}| jdk	r:| j|d< | j	dk	rN| j	|d< | j
dkrb| j
|d< || jS )z2Get the default parameters for calling OpenAI API.)r@   rE   rF   rG   rH   rX   r[   r.   NrC   rf   rD   rI   )r@   rE   rF   rG   rH   rX   r[   r.   rC   rf   rI   rK   )selfZnormal_paramsr&   r&   r'   _default_params   s     





zBaseOpenAI._default_paramszOptional[List[str]]z"Optional[CallbackManagerForLLMRun]zIterator[GenerationChunk])promptstoprun_managerkwargsr"   c                 k  s   | j |ddi}| ||g| | jjf d|i|D ]N}t|tsL| }t|}|r~|j|j	|| j
|jrv|jd nd d |V  q6d S NstreamTrx   r.   )chunkverboser.   )_invocation_paramsget_sub_promptsr8   create
isinstancer2   
model_dumpr4   on_llm_new_tokenr,   r   r1   rv   rx   ry   rz   r{   paramsZstream_respr~   r&   r&   r'   _stream   s     

zBaseOpenAI._streamz'Optional[AsyncCallbackManagerForLLMRun]zAsyncIterator[GenerationChunk]c                 K s   | j |ddi}| ||g| | jjf d|i|I d H 2 z\3 d H W }t|tsZ| }t|}|r|j|j	|| j
|jr|jd nd dI d H  |V  q<6 d S r|   )r   r   r9   r   r   r2   r   r4   r   r,   r   r1   r   r&   r&   r'   _astream  s(    


zBaseOpenAI._astream	List[str]r   )promptsry   rz   r{   r"   c                 K  sR  | j }||}| |||}g }i }dddh}	d}
|D ]}| jrt|dkrVtdd}| j|d ||f|D ]}|dkr|}qp||7 }qp|dk	st||j|j	r|j	
dnd|j	r|j	
d	ndd
 q6| jjf d|i|}t|ts| }|
drt|
d||d  t|	|| |
s6|
d}
q6| j|||||
dS )at  Call out to OpenAI's endpoint with k unique prompts.

        Args:
            prompts: The prompts to pass into the model.
            stop: Optional list of stop words to use when generating.

        Returns:
            The full LLM output.

        Example:
            .. code-block:: python

                response = openai.generate(["Tell me a joke."])
        completion_tokensprompt_tokenstotal_tokensNrD   ,Cannot stream results with multiple prompts.r   r-   r.   r,   r-   r.   rx   errorr*   system_fingerprintr   )r   r   r]   lenrq   r   AssertionErrorappendr,   r1   r3   r8   r   r   r2   r   extendr(   create_llm_resultrv   r   ry   rz   r{   r   sub_promptsr*   r!   _keysr   Z_promptsZ
generationr~   r    r&   r&   r'   	_generate!  sV    



    zBaseOpenAI._generatec                   s:  | j }||}| |||}g }i }dddh}	d}
|D ]}| jrt|dkrTtdd}| j|d ||f|2 z"3 dH W }|dkr|}qn||7 }qn6 |dk	st||j|j	r|j	
dnd|j	r|j	
d	ndd
 q6| jjf d|i|I dH }t|ts
| }||d  t|	|| q6| j|||||
dS )z:Call out to OpenAI's endpoint async with k unique prompts.r   r   r   NrD   r   r   r-   r.   r   rx   r*   r   )r   r   r]   r   rq   r   r   r   r,   r1   r3   r9   r   r   r2   r   r   r(   r   r   r&   r&   r'   
_agenerateq  sZ    
      zBaseOpenAI._ageneratezList[List[str]])r   r   ry   r"   c                   sh   |dk	r||d< |d dkrBt  dkr0td d |d<  fdd	tdt  jD }|S )
z!Get the sub prompts for llm call.Nry   rC   rD   z7max_tokens set to -1 not supported for multiple inputs.r   c                   s   g | ]} ||j   qS r&   )rU   ).0ir   rv   r&   r'   
<listcomp>  s   z.BaseOpenAI.get_sub_prompts.<locals>.<listcomp>)r   rq   max_tokens_for_promptrangerU   )rv   r   r   ry   r   r&   r   r'   r     s    zBaseOpenAI.get_sub_promptsr   zDict[str, int])r*   r   r   r!   r   r"   c                C  st   g }| d| j}t|D ]4\}}	||| |d |  }
|dd |
D  q|| jd}|rh||d< t||dS )z2Create the LLMResult from the choices and prompts.rH   rD   c              	   S  s0   g | ](}t |d  t|d|dddqS )r,   r-   r.   r/   r0   )r   r2   r3   )r   choicer&   r&   r'   r     s   z0BaseOpenAI.create_llm_result.<locals>.<listcomp>)r!   r>   r   )generations
llm_output)r3   rH   	enumerater   r>   r   )rv   r*   r   r   r!   r   r   rH   r   _Zsub_choicesr   r&   r&   r'   r     s    
zBaseOpenAI.create_llm_resultc                 C  s   | j S )z,Get the parameters used to invoke the model.)rw   rv   r&   r&   r'   r     s    zBaseOpenAI._invocation_paramszMapping[str, Any]c                 C  s   d| j i| jS )zGet the identifying parameters.r>   )r>   rw   r   r&   r&   r'   _identifying_params  s    zBaseOpenAI._identifying_paramsc                 C  s   dS )zReturn type of llm.rr   r&   r   r&   r&   r'   	_llm_type  s    zBaseOpenAI._llm_typez	List[int])r,   r"   c                   s|   | j dk	r|  |S tjd dk r.t |S | jp8| j}zt|}W n t	k
rf   t
d}Y nX |j|| j| jdS )z-Get the token IDs using the tiktoken package.NrD      Zcl100k_base)r^   r`   )Zcustom_get_token_idssysversion_infosuperget_num_tokensra   r>   tiktokenZencoding_for_modelKeyErrorZget_encodingencoder^   r`   )rv   r,   r>   enc	__class__r&   r'   get_token_ids  s    

zBaseOpenAI.get_token_ids)	modelnamer"   c                 C  s   ddddddddddddddddddddddddd	d	d
d
d}d| krT|  dd } || d}|dkrtd|  dd|  |S )ao  Calculate the maximum number of tokens possible to generate for a model.

        Args:
            modelname: The modelname we want to know the context size for.

        Returns:
            The maximum context size

        Example:
            .. code-block:: python

                max_tokens = openai.modelname_to_contextsize("gpt-3.5-turbo-instruct")
        i  i    i   i   i@  i  i  i  iA  i   )zgpt-4o-minizgpt-4ozgpt-4o-2024-05-13zgpt-4z
gpt-4-0314z
gpt-4-0613z	gpt-4-32kzgpt-4-32k-0314zgpt-4-32k-0613zgpt-3.5-turbozgpt-3.5-turbo-0301zgpt-3.5-turbo-0613zgpt-3.5-turbo-16kzgpt-3.5-turbo-16k-0613r:   ztext-ada-001Zadaztext-babbage-001Zbabbageztext-curie-001ZcurieZdavinciztext-davinci-003ztext-davinci-002zcode-davinci-002zcode-davinci-001zcode-cushman-002zcode-cushman-001zft-:r   NzUnknown model: z=. Please provide a valid OpenAI model name.Known models are: z, )splitr3   rq   joinr   )r   Zmodel_token_mappingZcontext_sizer&   r&   r'   modelname_to_contextsize   sN     
z#BaseOpenAI.modelname_to_contextsizec                 C  s   |  | jS )z$Get max context size for this model.)r   r>   r   r&   r&   r'   max_context_size<  s    zBaseOpenAI.max_context_size)rx   r"   c                 C  s   |  |}| j| S )ao  Calculate the maximum number of tokens possible to generate for a prompt.

        Args:
            prompt: The prompt to pass into the model.

        Returns:
            The maximum number of tokens to generate for a prompt.

        Example:
            .. code-block:: python

                max_tokens = openai.max_token_for_prompt("Tell me a joke.")
        )r   r   )rv   rx   Z
num_tokensr&   r&   r'   r   A  s    
z BaseOpenAI.max_tokens_for_prompt)NN)NN)NN)NN)N)=rg   rh   ri   rj   r   r8   __annotations__r9   r>   r@   rC   rE   rF   rG   rH   rI   r2   rK   r   rN   r   rP   rR   rS   rU   rW   rX   rZ   r[   r.   r]   setr^   r`   ra   rb   rc   rd   re   rf   rk   r   rp   rt   propertyrw   r   r   r   r   r   r   r   r   r   r   staticmethodr   r   r   __classcell__r&   r&   r   r'   r5   ?   s   
 
 
 
 
	#       S  < ;r5   c                      sr   e Zd ZdZeddddZeddddZed	d fd
dZeddddZ	ed	dddZ
  ZS )rs   u  OpenAI completion model integration.

    Setup:
        Install ``langchain-openai`` and set environment variable ``OPENAI_API_KEY``.

        .. code-block:: bash

            pip install -U langchain-openai
            export OPENAI_API_KEY="your-api-key"

    Key init args — completion params:
        model: str
            Name of OpenAI model to use.
        temperature: float
            Sampling temperature.
        max_tokens: Optional[int]
            Max number of tokens to generate.
        logprobs: Optional[bool]
            Whether to return logprobs.
        stream_options: Dict
            Configure streaming outputs, like whether to return token usage when
            streaming (``{"include_usage": True}``).

    Key init args — client params:
        timeout: Union[float, Tuple[float, float], Any, None]
            Timeout for requests.
        max_retries: int
            Max number of retries.
        api_key: Optional[str]
            OpenAI API key. If not passed in will be read from env var OPENAI_API_KEY.
        base_url: Optional[str]
            Base URL for API requests. Only specify if using a proxy or service
            emulator.
        organization: Optional[str]
            OpenAI organization ID. If not passed in will be read from env
            var OPENAI_ORG_ID.

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

    Instantiate:
        .. code-block:: python

            from langchain_openai import OpenAI

            llm = OpenAI(
                model="gpt-3.5-turbo-instruct",
                temperature=0,
                max_retries=2,
                # api_key="...",
                # base_url="...",
                # organization="...",
                # other params...
            )

    Invoke:
        .. code-block:: python

            input_text = "The meaning of life is "
            llm.invoke(input_text)

        .. code-block:: none

            "a philosophical question that has been debated by thinkers and scholars for centuries."

    Stream:
        .. code-block:: python

            for chunk in llm.stream(input_text):
                print(chunk, end="|")

        .. code-block:: none

            a| philosophical| question| that| has| been| debated| by| thinkers| and| scholars| for| centuries|.

        .. code-block:: python

            "".join(llm.stream(input_text))

        .. code-block:: none

            "a philosophical question that has been debated by thinkers and scholars for centuries."

    Async:
        .. code-block:: python

            await llm.ainvoke(input_text)

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

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

        .. code-block:: none

            "a philosophical question that has been debated by thinkers and scholars for centuries."

    r   ru   c                 C  s
   dddgS )z*Get the namespace of the langchain object.Z	langchainZllmsrr   r&   rn   r&   r&   r'   get_lc_namespace  s    zOpenAI.get_lc_namespacer\   c                 C  s   dS )z9Return whether this model can be serialized by Langchain.Tr&   r   r&   r&   r'   is_lc_serializable  s    zOpenAI.is_lc_serializabler   c                   s   d| j it jS )Nr;   )r>   r   r   r   r   r&   r'   r     s    zOpenAI._invocation_paramszDict[str, str]c                 C  s   ddiS )NrN   rM   r&   r   r&   r&   r'   
lc_secrets  s    zOpenAI.lc_secretsc                 C  s8   i }| j r| j |d< | jr$| j|d< | jr4| j|d< |S )NrP   rR   rS   )rP   rR   rS   )rv   
attributesr&   r&   r'   lc_attributes  s    


zOpenAI.lc_attributes)rg   rh   ri   rj   classmethodr   r   r   r   r   r   r   r&   r&   r   r'   rs   S  s   drs   ).
__future__r   loggingr   typingr   r   r   r   r   r   r	   r
   r   r   r   r   r   rr   r   Zlangchain_core.callbacksr   r   Z#langchain_core.language_models.llmsr   Zlangchain_core.outputsr   r   r   Zlangchain_core.pydantic_v1r   r   r   Zlangchain_core.utilsr   Zlangchain_core.utils.utilsr   r   r   	getLoggerrg   loggerr(   r4   r5   rs   r&   r&   r&   r'   <module>   s(   <
    