U
    h;                     @  sl  d dl mZ d dl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 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 d dlmZmZ d d	l m!Z! d d
l"m#Z#m$Z$m%Z%m&Z&m'Z' e(e)Z*edZ+dddddZ,dddddZ-ddddddZ.ddddddZ/ddddddZ0ddddd Z1d!d"dd#d$Z2G d%d deZ3dS )&    )annotationsN)AnyAsyncIterableAsyncIteratorCallableDictIterableIteratorListMappingOptionalTupleTypeVar)AsyncCallbackManagerForLLMRunCallbackManagerForLLMRun)BaseLLM)
GenerationGenerationChunk	LLMResult)Field)get_from_dict_or_envpre_init)	HTTPError)before_sleep_logretryretry_if_exception_typestop_after_attemptwait_exponentialTTongyizCallable[[Any], Any])llmreturnc                 C  s6   d}d}t dt| jtd||dtttttj	dS )N      T)Z
multiplierminmax)reraisestopwaitr   Zbefore_sleep)
r   r   max_retriesr   r   r   r   loggerloggingWARNING)r    Zmin_secondsZmax_seconds r-   C/tmp/pip-unpacked-wheel-9gdii04g/langchain_community/llms/tongyi.py_create_retry_decorator*   s    
r/   r   )respr!   c                 C  sr   | d dkr| S | d dkrDt d| d  d| d  d| d  n*td	| d  d| d  d| d  | d
dS )z,Check the response from the completion call.status_code   )i  i  zstatus_code: z	 
 code: codez 
 message: messagez"HTTP error occurred: status_code: )responseN)
ValueErrorr   )r0   r-   r-   r.   check_response8   s      r7   )r    kwargsr!   c                   s*   t  }|ddd fdd}|f |S )*Use tenacity to retry the completion call.r   _kwargsr!   c                    s    j jf | }t|S Nclientcallr7   )r;   r0   r    r-   r.   _generate_with_retryM   s    z1generate_with_retry.<locals>._generate_with_retryr/   )r    r8   retry_decoratorrA   r-   r@   r.   generate_with_retryI   s    rD   c                   s*   t  }|ddd fdd}|f |S )r9   r   r:   c                  ;  s&    j jf | }|D ]}t|V  qd S r<   r=   )r;   	responsesr0   r@   r-   r.   _stream_generate_with_retryY   s    z?stream_generate_with_retry.<locals>._stream_generate_with_retryrB   )r    r8   rC   rF   r-   r@   r.   stream_generate_with_retryU   s    rG   c                 K s4   G dd d}|| f|2 z3 dH W }|V  q6 dS )zAsync version of `stream_generate_with_retry`.

    Because the dashscope SDK doesn't provide an async API,
    we wrap `stream_generate_with_retry` with an async generator.c                   @  sF   e Zd ZdddddZdddd	Zddd
dZddddZdS )z8astream_generate_with_retry.<locals>._AioTongyiGeneratorr   r   )_llmr;   c                 [  s   t |f|| _d S r<   )rG   	generator)selfrH   r;   r-   r-   r.   __init__i   s    zAastream_generate_with_retry.<locals>._AioTongyiGenerator.__init__zAsyncIterator[Any]r!   c                 S  s   | S r<   r-   rJ   r-   r-   r.   	__aiter__l   s    zBastream_generate_with_retry.<locals>._AioTongyiGenerator.__aiter__c                   s,   t  d | jI d H }|d k	r$|S td S r<   )asyncioget_running_looprun_in_executor
_safe_nextStopAsyncIteration)rJ   valuer-   r-   r.   	__anext__o   s     
zBastream_generate_with_retry.<locals>._AioTongyiGenerator.__anext__c                 S  s(   zt | jW S  tk
r"   Y d S X d S r<   )nextrI   StopIterationrM   r-   r-   r.   rR   x   s    zCastream_generate_with_retry.<locals>._AioTongyiGenerator._safe_nextN)__name__
__module____qualname__rK   rN   rU   rR   r-   r-   r-   r.   _AioTongyiGeneratorh   s   	r[   Nr-   )r    r8   r[   chunkr-   r-   r.   astream_generate_with_retryb   s    r]   zIterable[T]zIterator[Tuple[T, bool]])iterabler!   c                 c  sR   t | }zt|}W n tk
r*   Y dS X |D ]}|dfV  |}q0|dfV  dS )z[Generate elements from an iterable,
    and a boolean indicating if it is the last element.NFT)iterrV   rW   r^   iteratoritemZ	next_itemr-   r-   r.   generate_with_last_element_mark   s    
rc   zAsyncIterable[T]zAsyncIterator[Tuple[T, bool]]c                 C sb   |   }z| I dH }W n tk
r0   Y dS X |2 z3 dH W }|dfV  |}q66 |dfV  dS )zaGenerate elements from an async iterable,
    and a boolean indicating if it is the last element.NFT)rN   rU   rS   r`   r-   r-   r.    agenerate_with_last_element_mark   s    
rd   c                      sz  e Zd ZU dZeddddZded< edd	d
Zded< ee	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ddddZeddd d!d"Zeddd#d$Zed%d fd&d'ZdEd(d)d*dd+d,d-d.ZdFd(d)d/dd+d,d0d1ZdGdd)d*dd2d3d4d5ZdHdd)d/dd6d3d7d8Zdddd9d:d;ZedIdddd=d>d?Zed@dAdBdCdDZ  ZS )Jr   uP	  Tongyi completion model integration.

    Setup:
        Install ``dashscope`` and set environment variables ``DASHSCOPE_API_KEY``.

        .. code-block:: bash

            pip install dashscope
            export DASHSCOPE_API_KEY="your-api-key"

    Key init args — completion params:
        model: str
            Name of Tongyi model to use.
        top_p: float
            Total probability mass of tokens to consider at each step.
        streaming: bool
            Whether to stream the results or not.

    Key init args — client params:
        api_key: Optional[str]
            Dashscope API KEY. If not passed in will be read from env var DASHSCOPE_API_KEY.
        max_retries: int
            Maximum number of retries to make when generating.

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

    Instantiate:
        .. code-block:: python

            from langchain_community.llms import Tongyi

            llm = Tongyi(
                model="qwen-max",
                # top_p="...",
                # api_key="...",
                # 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

            '探索、成长、连接与爱。在有限的时间里，寻找个人价值，贡献于他人和社会，体验丰富多彩的情感与经历，不断学习进步，让世界因自己的存在而更美好。'

    zDict[str, str]rL   c                 C  s   ddiS )Ndashscope_api_keyDASHSCOPE_API_KEYr-   rM   r-   r-   r.   
lc_secrets   s    zTongyi.lc_secretsr   r>   z	qwen-plusmodel)defaultaliasstr
model_name)default_factoryzDict[str, Any]model_kwargsg?floattop_pNapi_keyzOptional[str]re   Fbool	streaming
   intr)   c                 C  s   dS )zReturn type of llm.Ztongyir-   rM   r-   r-   r.   	_llm_type  s    zTongyi._llm_typer   )valuesr!   c                 C  sn   t |ddgd|d< zddl}W n tk
r<   tdY nX z|j|d< W n tk
rh   tdY nX |S )	z?Validate that api key and python package exists in environment.re   rq   rf   r   NzZCould not import dashscope python package. Please install it with `pip install dashscope`.r>   z`dashscope` has no `Generation` attribute, this is likely due to an old version of the dashscope package. Try upgrading it with `pip install --upgrade dashscope`.)r   	dashscopeImportErrorr   AttributeErrorr6   )clsrw   rx   r-   r-   r.   validate_environment  s$      

zTongyi.validate_environmentc                 C  s   | j | j| jd}|| jS )z7Get the default parameters for calling Tongyi Qwen API.)rh   rp   rq   )rl   rp   re   rn   )rJ   Znormal_paramsr-   r-   r.   _default_params   s
    zTongyi._default_paramszMapping[str, Any]c                   s   d| j it jS )Nrl   )rl   super_identifying_paramsrM   	__class__r-   r.   r   +  s    zTongyi._identifying_paramsz	List[str]zOptional[List[str]]z"Optional[CallbackManagerForLLMRun]r   )promptsr'   run_managerr8   r!   c                 K  s   g }| j rtt|dkrtdd }| j|d ||f|D ]}|d krJ|}q8||7 }q8|d k	s`t|| |g nJ| jf d|i|}|D ]0}	t| fd|	i|}
|t	f | 
|
g qt|d| jidS )Nr"   ,Cannot stream results with multiple prompts.r   r'   promptrl   generationsZ
llm_output)rs   lenr6   _streamAssertionErrorappend_chunk_to_generation_invocation_paramsrD   r   _generation_from_qwen_respr   rl   rJ   r   r'   r   r8   r   Z
generationr\   paramsr   
completionr-   r-   r.   	_generate/  s.    
 zTongyi._generatez'Optional[AsyncCallbackManagerForLLMRun]c              	     s   g }| j r~t|dkrtdd }| j|d ||f|2 z"3 d H W }|d krR|}q8||7 }q86 |d k	sjt|| |g n`| jf d|i|}|D ]F}	t	 
d tjtf| |	d|I d H }
|tf | |
g qt|d| jidS )Nr"   r   r   r'   )r    r   rl   r   )rs   r   r6   _astreamr   r   r   r   rO   rP   rQ   	functoolspartialrD   r   r   r   rl   r   r-   r-   r.   
_agenerateP  s<    "
 zTongyi._ageneratezIterator[GenerationChunk])r   r'   r   r8   r!   c           	      k  sl   | j f |dd|}tt| fd|i|D ]8\}}tf | ||}|r`|j|j|| jd |V  q.d S NT)r'   streamr   )r\   verbose)r   rc   rG   r   r   on_llm_new_tokentextr   	rJ   r   r'   r   r8   r   Zstream_respis_last_chunkr\   r-   r-   r.   r   v  s&     
zTongyi._streamzAsyncIterator[GenerationChunk]c           	      K s|   | j f |dd|}tt| fd|i|2 zF3 d H W \}}tf | ||}|rn|j|j|| jdI d H  |V  q.6 d S r   )r   rd   r]   r   r   r   r   r   r   r-   r-   r.   r     s&     
zTongyi._astream)r'   r8   r!   c                 K  s0   | j |}|d k	r||d< |dr,d|d< |S )Nr'   r   TZincremental_output)r}   get)rJ   r'   r8   r   r-   r-   r.   r     s    
zTongyi._invocation_paramsT)r0   r   r!   c                 C  sL   |r6t | d d t | d d | d t | d ddS t | d d dS d S )	Noutputr   finish_reason
request_idusage)r   r   Ztoken_usager   generation_info)r   )dict)r0   r   r-   r-   r.   r     s    


	z!Tongyi._generation_from_qwen_respr   r   )r\   r!   c                 C  s   t | j| jdS )Nr   )r   r   r   )r\   r-   r-   r.   r     s    zTongyi._chunk_to_generation)NN)NN)NN)NN)T)rX   rY   rZ   __doc__propertyrg   __annotations__r   rl   r   rn   rp   re   rs   r)   rv   r   r|   r}   r   r   r   r   r   r   staticmethodr   r   __classcell__r-   r-   r   r.   r      sH   
L
  $  )     )4
__future__r   rO   r   r+   typingr   r   r   r   r   r   r	   r
   r   r   r   r   Zlangchain_core.callbacksr   r   Z#langchain_core.language_models.llmsr   Zlangchain_core.outputsr   r   r   Zlangchain_core.pydantic_v1r   Zlangchain_core.utilsr   r   Zrequests.exceptionsr   Ztenacityr   r   r   r   r   	getLoggerrX   r*   r   r/   r7   rD   rG   r]   rc   rd   r   r-   r-   r-   r.   <module>   s*   8
 