o
    ]+ ij                     @  sN  d dl m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	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 e	rVd d
lmZ edede
f dZeeZ d<ddZ!d=ddZ"d>ddZ#d?ddZ$d@ddZ%dAd"d#Z&dBd&d'Z'		(dCdDd1d2Z(G d3d4 d4ed(d5Z)edd6d7dEd:d;Z*dS )F    )annotationsN)Mapping)TYPE_CHECKINGAnyCallableOptionalTypeVarUnion)	TypedDict)client)run_helpers)	warn_beta)InputTokenDetailsOutputTokenDetailsUsageMetadata)genaiCzgenai.Client)boundddictreturnc                 C  s   dd |   D S )z#Remove None values from dictionary.c                 S     i | ]\}}|d ur||qS N .0kvr   r   f/home/app/PaddleOCR-VL-test/.venv_paddleocr/lib/python3.10/site-packages/langsmith/wrappers/_gemini.py
<dictcomp>!       z_strip_none.<locals>.<dictcomp>)items)r   r   r   r   _strip_none   s   r"   kwargsNonec                 C  s2   d| v rt | d tst| d | d< dS dS dS )zBConvert GenerateContentConfig to dict for LangSmith compatibility.configN)
isinstancer   vars)r#   r   r   r   _convert_config_for_tracing$   s   r(   inputsc                 C  s  |  d}|s	| S t|tr#d|dg|  dddd |  D S t|trYtdd	 |D rHd
d |D |  dddd |  D S g }|D ]}t|trG| dd}| dg }g }g }|D ]}t|trd|v r|d r||d  |d|d d qfd|v r|d }	|	 dd}
|	 dd}t|trt	
|d}n|}|dd|
 d| ddd qfd|v r|d }|d| d| d i d!d" qfd#|v sd$|v r| d#p| d$}|d%urt|ts| }|d#| d&| d| d'i d(d) qft|tr$|| |d|d qf|r8td*d	 |D r8d+|}n|r=|nd,}|||d qL||  ddd-d |  D S | S ).u  Process Gemini inputs to normalize them for LangSmith tracing.

    Example:
        {"contents": "Hello", "model": "gemini-pro"}
        → {"messages": [{"role": "user", "content": "Hello"}], "model": "gemini-pro"}
        {"contents": [{"role": "user", "parts": [{"text": "What is AI?"}]}], "model": "gemini-pro"}
        → {"messages": [{"role": "user", "content": "What is AI?"}], "model": "gemini-pro"}
    contentsuserrolecontentmodel)messagesr/   c                 S     i | ]\}}|d vr||qS )r*   r/   r   r   r   r   r   r   =   r    z*_process_gemini_inputs.<locals>.<dictcomp>c                 s  s    | ]}t |tV  qd S r   )r&   strr   itemr   r   r   	<genexpr>C   s    z)_process_gemini_inputs.<locals>.<genexpr>c                 S  s   g | ]}d |dqS )r+   r,   r   r4   r   r   r   
<listcomp>F   s    z*_process_gemini_inputs.<locals>.<listcomp>c                 S  r1   r2   r   r   r   r   r   r   H   r    r-   partstexttyper9   inline_data	mime_type
image/jpegdata    utf-8	image_urldata:;base64,highurldetailr;   rB   ZfunctionResponsefunction_responsenameresponse)rK   rL   )r;   rJ   function_callfunctionCallNidargsrO   rK   	argumentsr;   rM   c                 s  s    | ]
}| d dkV  qdS )r;   r9   Ngetr   pr   r   r   r6      s    

 c                 S  r1   r2   r   r   r   r   r   r      r    )rU   r&   r3   r!   listallr   appendbytesbase64	b64encodedecodeto_dictjoin)r)   r*   r0   r.   r-   r8   Z
text_partscontent_partspartr<   r=   r?   data_b64rJ   rM   Zmessage_contentr   r   r   _process_gemini_inputs*   s   











rf   c                 C  st   t | }|di }t|dr|j}t|dd}t|dd}n|d}|d}|d}dd|d|||d	S )
z*Extract invocation parameters for tracing.r%   temperatureZmax_output_tokensNZstop_sequencesgoogleZchatr/   )Zls_providerZls_model_typeZls_model_nameZls_temperatureZls_max_tokensZls_stop)r"   rU   hasattrrg   getattr)r#   strippedr%   rg   Z
max_tokensstopr   r   r   _infer_invocation_params   s    



rm   gemini_usage_metadatar   c                 C  s   |  dpd}|  dpd}|  dpd}|  dpd}|  dp$|| }i }|r-||d< i }|r5||d< t|||tdi d	d
 | D tdi dd
 | D dS )z2Convert Gemini usage metadata to LangSmith format.prompt_token_countr   candidates_token_countcached_content_token_countthoughts_token_counttotal_token_countZ
cache_readZ	reasoningc                 S  r   r   r   r   r   r   r   r      r    z*_create_usage_metadata.<locals>.<dictcomp>c                 S  r   r   r   r   r   r   r   r      r    )input_tokensoutput_tokenstotal_tokensinput_token_detailsoutput_token_detailsNr   )rU   r   r   r!   r   )rn   ro   rp   rq   rr   rs   rw   rx   r   r   r   _create_usage_metadata   s2   
ry   rL   r   c              
   C  s  zt | dr|  }nt | dr|  }n
dt| dt| i}d}g }d}d|v r|d r|d d }d|v r|d }d	|v r|d	 r|d	 D ]}d|v rc|d rc||d 7 }|d|d d
 qHd|v r|d dur|d }|dd}	|dd}
t|
trt	
|
d}n|
}|dd|	 d| ddd qHd|v sd|v r|dp|d}|durt|ts| }|d|d|d|di dd qHd|v r|d r|d }nd|v r|d }|d|d
 dd  |D }|r|pdd!|d"d  t|D d#}n t|d$ks |r'|d d% dkr'|d!|d&}n|d!|d&}|d'}tdddd(}|ryt|}t }|ryz|jd)i d'i }|| |  W n tyx } ztd*|  W Y d}~nd}~ww |d+r|d d!||d+ |d,W S t|d tr|d d!||d-W S |d d!||d-W S  ty } ztd.|  d/| iW  Y d}~S d}~ww )0z$Process Gemini response for tracing.ra   
model_dumpr9   rY   N
candidatesr   r.   r8   r:   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rI   rM   rN   rO   rK   rP   rQ   rS   finish_reasonc                 S  s   g | ]}| d dkr|qS rS   rT   rV   r   r   r   r7   2  r    z6_process_generate_content_response.<locals>.<listcomp>Z	assistantc              
   S  sN   g | ]#\}}|d   dpd| d||d  d t|d  d ddqS )rM   rO   Zcall_functionrK   rR   )rK   rR   )rO   r;   indexr}   )rU   jsondumps)r   iZtcr   r   r   r7   9  s    

)r.   r-   r|   
tool_calls   r;   )r.   r-   r|   usage_metadatart   ru   rv   metadata!Failed to update usage metadata: r   )r.   r-   r|   r   r   )r.   r-   r|   r   z"Error processing Gemini response: output)ri   ra   rz   rj   r3   r\   rU   r&   r]   r^   r_   r`   r   	enumeratelenr   ry   r   get_current_run_treeextra
setdefaultupdatepatch	Exceptionloggerwarningdebug)rL   ZrdictZcontent_resultrc   r|   	candidater.   rd   r<   r=   r?   re   rM   r   resultr   
usage_dictcurrent_runmetaer   r   r   "_process_generate_content_response   s   











		r   
all_chunksrZ   c           	      C  s  | sdt dddddS d}d}| D ]-}zt|dr"|jr"||j7 }|}W q ty? } ztd|  W Y d}~qd}~ww t dddd}|rz~t|dr|jrt|jd	r^|j }n-t|jd
rj|j }n!t	|jddt	|jddt	|jddt	|jddt	|jddd}t
|}t }|rz|jdi di }|| |  W n ty } ztd|  W Y d}~nd}~ww W n ty } ztd|  W Y d}~nd}~ww ||dS )z/Reduce streaming chunks into a single response.rY   r   r   )r.   r   Nr9   zError processing chunk: r   ra   rz   ro   rp   rq   rr   rs   )ro   rp   rq   rr   rs   r   r   z+Error extracting metadata from last chunk: )r   ri   r9   r   r   r   r   ra   rz   rj   ry   r   r   r   r   r   r   r   )	r   	full_text
last_chunkchunkr   r   r   r   r   r   r   r   _reduce_generate_content_chunks  s   

r   Foriginal_generater   rK   r3   tracing_extraOptional[TracingExtra]is_streamingboolc                   sR   |pi t  fdd}t  fdd}tr'|S |S )z7Create a wrapper for Gemini's generate_content methods.c               	     sH   t | tjdd rtnd t stnd td}|| i |S NZllm)rK   Zrun_typeZ	reduce_fnZprocess_inputsZprocess_outputsZ_invocation_params_fnr   r(   r   Z	traceabler   rf   r   rm   rP   r#   	decoratorr   rK   r   Ztextrar   r   generate  s   

	z_get_wrapper.<locals>.generatec               	     sP   t | tjdd rtnd t stnd td}|| i |I d H S r   r   r   r   r   r   	agenerate  s   

	z_get_wrapper.<locals>.agenerate)	functoolswrapsr   is_async)r   rK   r   r   r   r   r   r   r   _get_wrapper  s   r   c                   @  s&   e Zd ZU ded< ded< ded< dS )TracingExtrazOptional[Mapping[str, Any]]r   zOptional[list[str]]tagszOptional[ls_client.Client]r   N)__name__
__module____qualname____annotations__r   r   r   r   r     s   
 r   )totalZChatGoogleGenerativeAI)r   	chat_namer   r   c                C  s  |pi }t | drt | jdrt | jjdrtdt | dr1t | jdr1t| jj||dd| j_t | drHt | jdrHt| jj||dd| j_t | d	rht | jdrht | jjdrht| jjj||dd| jj_t | d	rt | jdrt | jjdrt| jjj||dd| jj_| S )
a  Patch the Google Gen AI client to make it traceable.

    .. warning::
        **BETA**: This wrapper is in beta.

    Supports:
        - generate_content() and generate_content_stream() methods
        - Sync and async clients
        - Streaming and non-streaming responses
        - Tool/function calling with proper UI rendering
        - Multimodal inputs (text + images)
        - Image generation with inline_data support
        - Token usage tracking including reasoning tokens

    Args:
        client (genai.Client): The Google Gen AI client to patch.
        tracing_extra (Optional[TracingExtra], optional): Extra tracing information.
            Defaults to None.
        chat_name (str, optional): The run name for the chat endpoint.
            Defaults to "ChatGoogleGenerativeAI".

    Returns:
        genai.Client: The patched client.

    Examples:

        .. code-block:: python

            from google import genai
            from google.genai import types
            from langsmith import wrappers

            # Use Google Gen AI client same as you normally would.
            client = wrappers.wrap_gemini(genai.Client(api_key="your-api-key"))

            # Basic text generation:
            response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents="Why is the sky blue?",
            )
            print(response.text)

            # Streaming:
            for chunk in client.models.generate_content_stream(
                model="gemini-2.5-flash",
                contents="Tell me a story",
            ):
                print(chunk.text, end="")

            # Tool/Function calling:
            schedule_meeting_function = {
                "name": "schedule_meeting",
                "description": "Schedules a meeting with specified attendees.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "attendees": {"type": "array", "items": {"type": "string"}},
                        "date": {"type": "string"},
                        "time": {"type": "string"},
                        "topic": {"type": "string"},
                    },
                    "required": ["attendees", "date", "time", "topic"],
                },
            }

            tools = types.Tool(function_declarations=[schedule_meeting_function])
            config = types.GenerateContentConfig(tools=[tools])

            response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents="Schedule a meeting with Bob and Alice tomorrow at 2 PM.",
                config=config,
            )

            # Image generation:
            response = client.models.generate_content(
                model="gemini-2.5-flash-image",
                contents=["Create a picture of a futuristic city"],
            )

            # Save generated image
            from io import BytesIO
            from PIL import Image

            for part in response.candidates[0].content.parts:
                if part.inline_data is not None:
                    image = Image.open(BytesIO(part.inline_data.data))
                    image.save("generated_image.png")

    .. versionadded:: 0.4.33
        Initial beta release of Google Gemini wrapper.

    modelsgenerate_content__wrapped__zfThis Google Gen AI client has already been wrapped. Wrapping a client multiple times is not supported.F)r   r   generate_content_streamTaio)ri   r   r   
ValueErrorr   r   r   )r   r   r   r   r   r   wrap_gemini  sb   d


	

r   )r   r   r   r   )r#   r   r   r$   )r)   r   r   r   )r#   r   r   r   )rn   r   r   r   )rL   r   r   r   )r   rZ   r   r   )NF)
r   r   rK   r3   r   r   r   r   r   r   )r   r   r   r   r   r3   r   r   )+
__future__r   r^   r   r   loggingcollections.abcr   typingr   r   r   r   r   r	   Ztyping_extensionsr
   Z	langsmithr   Z	ls_clientr   Z#langsmith._internal._beta_decoratorr   Zlangsmith.schemasr   r   r   rh   r   r   	getLoggerr   r   r"   r(   rf   rm   ry   r   r   r   r   r   r   r   r   r   <module>   sB     	



 


" 
#L2