o
    ZhX                     @  s4  d dl mZ d dl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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 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*m+Z+m,Z, d dlm-Z. d dl/m0Z0m1Z1 d d	l2m3Z3 d d
l4m5Z5m6Z6 d dl7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z> d dl?m@Z@ d dlAmBZBmCZCmDZD d dlEmFZF d dlGmHZHmIZImJZJ d dlKmLZLmMZMmNZN d dlOmPZPmQZQmRZR d dlSmTZT d dlUmVZV d dlWmXZXmYZYmZZZm[Z[m\Z\ d dl]m^Z^m_Z_m`Z`maZambZb d dlcmdZdmeZe d dlfmgZgmhZhmiZimjZj d dlkmlZlmmZmmnZnmoZompZpmqZqmrZr d dlsmtZtmuZu ddlvmwZx dayeze{Z|ee$e}e~e
f ede
f f ZG dd degZd`d"d#Zdad(d)Zdad*d+Zdbd/d0Zdcd4d5Z	ddded;d<ZdfdBdCZ	dgdhdHdIZ	dgdidMdNZ		djdkdUdVZdldWdXZG dYdZ dZeie5Zdmd^d_ZdS )n    )annotationsN)
itemgetter)AnyAsyncIteratorCallableDictIteratorListMappingOptionalSequenceTupleTypeUnioncast)GenerativeServiceAsyncClient)Blob	CandidateCodeExecutionContentFileDataFunctionCallFunctionDeclarationFunctionResponseGenerateContentRequestGenerateContentResponseGenerationConfigPartSafetySetting
ToolConfigVideoMetadata)Tool)AsyncCallbackManagerForLLMRunCallbackManagerForLLMRun)LanguageModelInput)BaseChatModelLangSmithParams)	AIMessageAIMessageChunkBaseMessageFunctionMessageHumanMessageSystemMessageToolMessage)UsageMetadata)invalid_tool_call	tool_calltool_call_chunk)OutputParserLike)JsonOutputKeyToolsParserPydanticToolsParserparse_tool_calls)ChatGenerationChatGenerationChunk
ChatResult)RunnableRunnableConfigRunnablePassthrough)BaseToolconvert_to_openai_tool)	BaseModel
ConfigDictField	SecretStrmodel_validator)before_sleep_logretryretry_if_exception_typestop_after_attemptwait_exponential)Selfis_typeddict)GoogleGenerativeAIErrorSafetySettingDict_BaseGoogleGenerativeAIget_client_info)_tool_choice_to_tool_config_ToolChoiceType_ToolConfigDict	_ToolDict&convert_to_genai_function_declarationsis_basemodel_subclass_safetool_to_dict)ImageBytesLoaderimage_bytes_to_b64_string   )_genai_extensionF.c                   @  s   e Zd ZdZdS )ChatGoogleGenerativeAIErrora  
    Custom exception class for errors associated with the `Google GenAI` API.

    This exception is raised when there are specific issues related to the
    Google genai API usage in the ChatGoogleGenerativeAI class, such as unsupported
    message types or roles.
    N)__name__
__module____qualname____doc__ r_   r_   Y/var/www/html/lang_env/lib/python3.10/site-packages/langchain_google_genai/chat_models.pyrZ      s    rZ   returnCallable[[Any], Any]c                  C  s^   d} d}d}d}t dt|t| ||dttjjjttjjjB ttjjj	B t
ttjdS )a  
    Creates and returns a preconfigured tenacity retry decorator.

    The retry decorator is configured to handle specific Google API exceptions
    such as ResourceExhausted and ServiceUnavailable. It uses an exponential
    backoff strategy for retries.

    Returns:
        Callable[[Any], Any]: A retry decorator configured for handling specific
        Google API exceptions.
       rX   <   T)
multiplierminmax)reraisestopwaitrE   before_sleep)rE   rG   rH   rF   googleapi_core
exceptionsZResourceExhaustedZServiceUnavailableZGoogleAPIErrorrD   loggerloggingWARNING)re   Zmin_secondsZmax_secondsmax_retriesr_   r_   r`   _create_retry_decorator   s   
rs   generation_methodr   kwargsr   c                   s&   t  }|d fdd}|di |S )	  
    Executes a chat generation method with retry logic using tenacity.

    This function is a wrapper that applies a retry mechanism to a provided
    chat generation function. It is useful for handling intermittent issues
    like network errors or temporary service unavailability.

    Args:
        generation_method (Callable): The chat generation method to be executed.
        **kwargs (Any): Additional keyword arguments to pass to the generation method.

    Returns:
        Any: The result from the chat generation method.
    ru   r   ra   c               
     s   z di | W S  t jjjy) } zd|jv rd}t|W Y d }~d S d }~w t jjjy? } ztd| |d }~w tyL } z|d }~ww )Nzlocation is not supportedzYour location is not supported by google-generativeai at the moment. Try to use ChatVertexAI LLM from langchain_google_vertexai.%Invalid argument provided to Gemini: r_   )	rl   rm   rn   ZFailedPreconditionmessage
ValueErrorInvalidArgumentrZ   	Exception)ru   exc	error_msgert   r_   r`   _chat_with_retry   s(   
z*_chat_with_retry.<locals>._chat_with_retryNru   r   ra   r   r_   )rs   )rt   ru   retry_decoratorr   r_   r   r`   r      s   r   c                   s<   t  }ddlm  |d	 fdd}|d
i |I dH S )rv   r   )rz   ru   r   ra   c               
     s\   zdi | I d H W S   y  } zt d| |d }~w ty- } z|d }~ww )Nrw   r_   )rZ   r{   )ru   r~   rz   rt   r_   r`   _achat_with_retry   s   z,_achat_with_retry.<locals>._achat_with_retryNr   r_   )rs   Zgoogle.api_core.exceptionsrz   )rt   ru   r   r   r_   r   r`   r      s   r   partdictboolc                 C  s   d| v S )Ntyper_   )r   r_   r_   r`   _is_openai_parts_format   s   r   raw_content&Union[str, Sequence[Union[str, dict]]]
List[Part]c           	      C  s  g }t | tr
| gn| }t }|D ]}t |tr!|t|d qt |trt|r|d dkr;|t|d d q|d dkrb|d }t |trYd|vrUtd| |d }||	| q|d dkrd|vrstd	| |d }t }d
|v rt
|d
 |d|_nd|v rt|d |d|_ntd| d|v rt|d }||_|| qtd|d  dtd |tt|d qtd|S )z:Converts a list of LangChain messages into a google parts.textr   r   	image_urlurlz#Unrecognized message image format: Zmedia	mime_typez!Missing mime_type in media part: data)r   r   file_uri)r   r   z.Media part must have either data or file_uri: video_metadataz Unrecognized message part type: z6. Only text, image_url, and media types are supported.z<Unrecognized message part format. Assuming it's a text part.z0Gemini only supports text and inline_data parts.)
isinstancestrrV   appendr   r
   r   r   ry   Z	load_partr   inline_datar   	file_datar    r   ro   warningrZ   )	r   partscontentZimage_loaderr   Zimg_urlr   Z
media_partmetadatar_   r_   r`   _convert_to_parts   sd   




r   rx   ToolMessage | FunctionMessagenameOptional[str]r   c                 C  s~   | j p
|p
| jd}t| jts| j}nzt| j}W n tjy*   | j}Y nw t	t
|t|ts7d|in|dd}|S )z5Converts a tool or function message to a google part.r   output)r   response)Zfunction_response)r   additional_kwargsgetr   r   r   jsonloadsJSONDecodeErrorr   r   r   )rx   r   r   r   r_   r_   r`   _convert_tool_message_to_part:  s   
r   tool_messagesSequence[ToolMessage]
ai_messager'   
list[Part]c                 C  sp   dd |j D }g }t| D ]'\}}|s |S |j|v r5||j }t||dd}|| ||j q|S )zj
    Finds relevant tool messages for the AI message and converts them to a single
    list of Parts.
    c                 S  s   i | ]}|d  |qS )idr_   ).0r0   r_   r_   r`   
<dictcomp>[      z7_get_ai_message_tool_messages_parts.<locals>.<dictcomp>r   r   )
tool_calls	enumerateZtool_call_idr   r   r   pop)r   r   Ztool_calls_idsr   irx   r0   r   r_   r_   r`   #_get_ai_message_tool_messages_partsS  s   


r   input_messagesSequence[BaseMessage]convert_system_message_to_human'Tuple[Optional[Content], List[Content]]c                 C  s  g }|r	t d d }dd | D }dd | D }t|D ]\}}t|trBt|j}|dkr5t|d}n|d ur@|j	| n	 qt|t
rd}	|jrg }
|jD ]}t|d |d	 d
}|
t|d qQt||d}|t|	|
d |td|d q|jd }rt|d t|d d
}t|dg}nAt|j}n;t|trd}	t|j}|dkr|r|rdd |jD | }d }nt|trd}	t|g}ntdt| d| d|t|	|d q||fS )Nz3Convert_system_message_to_human will be deprecated!c                 S  s   g | ]	}t |ts|qS r_   r   r-   r   rx   r_   r_   r`   
<listcomp>r  
    
z'_parse_chat_history.<locals>.<listcomp>c                 S  s   g | ]	}t |tr|qS r_   r   r   r_   r_   r`   r   u  r   r   r   modelr   args)r   r   )function_call)r   r   )roler   userr   	argumentsrX   c                 S  s   g | ]}|qS r_   r_   )r   pr_   r_   r`   r     s    zUnexpected message with type z at the position .)warningswarnr   r   r,   r   r   r   r   extendr'   r   r   r   r   r   r   r   r   r   r+   r*   r   ry   r   )r   r   messagessystem_instructionZmessages_without_tool_messagesr   r   rx   Zsystem_partsr   Zai_message_partsr0   r   Ztool_messages_partsZraw_function_callr   r_   r_   r`   _parse_chat_historyi  sv   







r   response_candidater   	streamingc                   s  d }i }g }g }g }| j jD ]}z|j}|d ur|d}W n ty*   d }Y nw |d urS|s4|}nt|tr@|r@||g}nt|trM|rM|| n|rSt	dt
|dr|jd ur|jjr|jjrd|jj|jjd}	|su|	g}nt|tr||	g}nt|tr||	 nt	dt
|dr|jd ur|jjrd|jjd}
|s|
g}nt|tr||
g}nt|tr||
 nt	d|jjdr|jjdd  }d	d
t|jj|did}|s|g}n t|tr|r||g}nt|tr|r|| n|rt	d|jrd|jji}tj|jd  t fdd D |d< ||d< |rJ|t|d|d|dtt |dd qzt d|igddd }W n. t	y } z!|t!|d|d|dtt t|d W Y d }~qd }~ww |t"|d |d |dtt d q|d u rd}t#dd |D rt$%d |rt&t't(tt)t(tt*t+t+f f  f |||d S t,t't(tt)t(tt*t+t+f f  f ||||d!S )"N
zUnexpected content typeexecutable_code)r   r   languagecode_execution_result)r   r   zimage/   r   r   )image_format)r   r   r   r   c                   s   i | ]}| | qS r_   r_   )r   kZfunction_call_args_dictr_   r`   r     r   z-_parse_response_candidate.<locals>.<dictcomp>r   r   r   index)r   r   r   r   functionF)Z	return_idr   )r   r   r   error)r   r   r    c                 s  s"    | ]}t |tod |v V  qdS )r   N)r   r   )r   itemr_   r_   r`   	<genexpr>.  s     z,_parse_response_candidate.<locals>.<genexpr>u   
        ⚠️ Warning: Output may vary each run.  
        - 'executable_code': Always present.  
        - 'execution_result' & 'image_url': May be absent for some queries.  

        Validate before using in production.
)r   r   tool_call_chunks)r   r   r   invalid_tool_calls)-r   r   r   rstripAttributeErrorr   r   listr   r{   hasattrr   coder   r   r   r   r   
startswithrW   r   r   r   protoMessageto_dictr   dumpsr1   r   uuiduuid4r5   r/   r0   anyr   r   r(   r   r   r	   r   r   r'   )r   r   r   r   r   r   r   r   r   Zcode_messageZexecution_resultr   rx   r   Ztool_call_dictr~   r_   r   r`   _parse_response_candidate  s   








	
	


$$r   r   r   stream
prev_usageOptional[UsageMetadata]r8   c                 C  s  dt j| ji}|r|d nd}|r|d nd}|r|d nd}z/| jj}| jj}| jj}	| jj}
|| |
 |	 dkrMt	|| || |	| d|
id}nd}W n t
y[   d}Y nw g }| jD ]=}i }|jrs|jj|d	< | j|d
< dd |jD |d< t||d}||_|r|ttt||d qa|t||d qa| jstd| j  |rttddi dg}n	ttdi dg}t||dS )z9Converts a PaLM API response into a LangChain ChatResult.prompt_feedbackinput_tokensr   output_tokenstotal_tokensZ
cache_read)r   r   r   Zinput_token_detailsNfinish_reasonZ
model_namec                 S  s   g | ]
}t jj|d dqS )F)Zuse_integers_for_enums)r   r   r   )r   Zsafety_ratingr_   r_   r`   r   p  s    z'_response_to_result.<locals>.<listcomp>safety_ratings)r   )rx   generation_infozKGemini produced an empty response. Continuing with empty message
Feedback: r   )r   )generations
llm_output)r   r   r   r   usage_metadataZprompt_token_countZcandidates_token_countZtotal_token_countZcached_content_token_countr.   r   
candidatesr   r   Zmodel_versionr   r   r   r7   r   r(   r6   ro   r   r'   r8   )r   r   r   r   Zprev_input_tokensZprev_output_tokensZprev_total_tokensr   r   r   Zcache_read_tokensZlc_usager   	candidater   rx   r_   r_   r`   _response_to_resultH  sn   




r   c                   C  s$   zt   W dS  ty   Y dS w )NTF)asyncioget_running_loopRuntimeErrorr_   r_   r_   r`   _is_event_loop_running  s   r  c                	      s  e Zd ZU dZe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< 	 dZded< 	 eddZednddZedoddZedpddZedpddZedddqdd Zedrd"d#Zedsd%d&Z	dtddd'du fd2d3Z	dtdvd6d7Z	dtdwd;d<Z		dxdddddddd=dydMdNZ		dxdddddddd=dz fdPdQZ		dxdddddddd=d{dSdTZ		dxdddddddd=d| fdVdWZdddddddddXd}dZd[Zd~d^d_Z dd`ddedfZ!	dtddgddjdkZ"edpdldmZ#  Z$S )ChatGoogleGenerativeAIa]!  `Google AI` chat models integration.

    Instantiation:
        To use, you must have either:

            1. The ``GOOGLE_API_KEY`` environment variable set with your API key, or
            2. Pass your API key using the google_api_key kwarg
            to the ChatGoogleGenerativeAI constructor.

        .. code-block:: python

            from langchain_google_genai import ChatGoogleGenerativeAI

            llm = ChatGoogleGenerativeAI(model="gemini-1.5-pro")
            llm.invoke("Write me a ballad about LangChain")

    Invoke:
        .. code-block:: python

            messages = [
                ("system", "Translate the user sentence to French."),
                ("human", "I love programming."),
            ]
            llm.invoke(messages)

        .. code-block:: python

            AIMessage(
                content="J'adore programmer. \n",
                response_metadata={'prompt_feedback': {'block_reason': 0, 'safety_ratings': []}, 'finish_reason': 'STOP', 'safety_ratings': [{'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HATE_SPEECH', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HARASSMENT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_DANGEROUS_CONTENT', 'probability': 'NEGLIGIBLE', 'blocked': False}]},
                id='run-56cecc34-2e54-4b52-a974-337e47008ad2-0',
                usage_metadata={'input_tokens': 18, 'output_tokens': 5, 'total_tokens': 23}
            )

    Stream:
        .. code-block:: python

            for chunk in llm.stream(messages):
                print(chunk)

        .. code-block:: python

            AIMessageChunk(content='J', response_metadata={'finish_reason': 'STOP', 'safety_ratings': []}, id='run-e905f4f4-58cb-4a10-a960-448a2bb649e3', usage_metadata={'input_tokens': 18, 'output_tokens': 1, 'total_tokens': 19})
            AIMessageChunk(content="'adore programmer. 
", response_metadata={'finish_reason': 'STOP', 'safety_ratings': [{'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HATE_SPEECH', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HARASSMENT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_DANGEROUS_CONTENT', 'probability': 'NEGLIGIBLE', 'blocked': False}]}, id='run-e905f4f4-58cb-4a10-a960-448a2bb649e3', usage_metadata={'input_tokens': 18, 'output_tokens': 5, 'total_tokens': 23})

        .. code-block:: python

            stream = llm.stream(messages)
            full = next(stream)
            for chunk in stream:
                full += chunk
            full

        .. code-block:: python

            AIMessageChunk(
                content="J'adore programmer. \n",
                response_metadata={'finish_reason': 'STOPSTOP', 'safety_ratings': [{'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HATE_SPEECH', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HARASSMENT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_DANGEROUS_CONTENT', 'probability': 'NEGLIGIBLE', 'blocked': False}]},
                id='run-3ce13a42-cd30-4ad7-a684-f1f0b37cdeec',
                usage_metadata={'input_tokens': 36, 'output_tokens': 6, 'total_tokens': 42}
            )

    Async:
        .. code-block:: python

            await llm.ainvoke(messages)

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

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

    Tool calling:
        .. code-block:: python

            from pydantic import BaseModel, Field


            class GetWeather(BaseModel):
                '''Get the current weather in a given location'''

                location: str = Field(
                    ..., description="The city and state, e.g. San Francisco, CA"
                )


            class GetPopulation(BaseModel):
                '''Get the current population in a given location'''

                location: str = Field(
                    ..., description="The city and state, e.g. San Francisco, CA"
                )


            llm_with_tools = llm.bind_tools([GetWeather, GetPopulation])
            ai_msg = llm_with_tools.invoke(
                "Which city is hotter today and which is bigger: LA or NY?"
            )
            ai_msg.tool_calls

        .. code-block:: python

            [{'name': 'GetWeather',
              'args': {'location': 'Los Angeles, CA'},
              'id': 'c186c99f-f137-4d52-947f-9e3deabba6f6'},
             {'name': 'GetWeather',
              'args': {'location': 'New York City, NY'},
              'id': 'cebd4a5d-e800-4fa5-babd-4aa286af4f31'},
             {'name': 'GetPopulation',
              'args': {'location': 'Los Angeles, CA'},
              'id': '4f92d897-f5e4-4d34-a3bc-93062c92591e'},
             {'name': 'GetPopulation',
              'args': {'location': 'New York City, NY'},
              'id': '634582de-5186-4e4b-968b-f192f0a93678'}]

    Use Search with Gemini 2:
        .. code-block:: python

            from google.ai.generativelanguage_v1beta.types import Tool as GenAITool
            llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash-exp")
            resp = llm.invoke(
                "When is the next total solar eclipse in US?",
                tools=[GenAITool(google_search={})],
            )

    Structured output:
        .. code-block:: python

            from typing import Optional

            from pydantic import BaseModel, Field


            class Joke(BaseModel):
                '''Joke to tell user.'''

                setup: str = Field(description="The setup of the joke")
                punchline: str = Field(description="The punchline to the joke")
                rating: Optional[int] = Field(description="How funny the joke is, from 1 to 10")


            structured_llm = llm.with_structured_output(Joke)
            structured_llm.invoke("Tell me a joke about cats")

        .. code-block:: python

            Joke(
                setup='Why are cats so good at video games?',
                punchline='They have nine lives on the internet',
                rating=None
            )

    Image input:
        .. code-block:: python

            import base64
            import httpx
            from langchain_core.messages import HumanMessage

            image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
            image_data = base64.b64encode(httpx.get(image_url).content).decode("utf-8")
            message = HumanMessage(
                content=[
                    {"type": "text", "text": "describe the weather in this image"},
                    {
                        "type": "image_url",
                        "image_url": {"url": f"data:image/jpeg;base64,{image_data}"},
                    },
                ]
            )
            ai_msg = llm.invoke([message])
            ai_msg.content

        .. code-block:: python

            'The weather in this image appears to be sunny and pleasant. The sky is a bright blue with scattered white clouds, suggesting fair weather. The lush green grass and trees indicate a warm and possibly slightly breezy day. There are no signs of rain or storms. 
'

    Token usage:
        .. code-block:: python

            ai_msg = llm.invoke(messages)
            ai_msg.usage_metadata

        .. code-block:: python

            {'input_tokens': 18, 'output_tokens': 5, 'total_tokens': 23}


    Response metadata
        .. code-block:: python

            ai_msg = llm.invoke(messages)
            ai_msg.response_metadata

        .. code-block:: python

            {
                'prompt_feedback': {'block_reason': 0, 'safety_ratings': []},
                'finish_reason': 'STOP',
                'safety_ratings': [{'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HATE_SPEECH', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HARASSMENT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_DANGEROUS_CONTENT', 'probability': 'NEGLIGIBLE', 'blocked': False}]
            }

    NT)defaultexcluder   clientasync_client_running)default_factoryzSequence[Tuple[str, str]]default_metadataFr   r   r   cached_content)Zpopulate_by_namera   Dict[str, str]c                 C  s   ddiS )Ngoogle_api_keyZGOOGLE_API_KEYr_   selfr_   r_   r`   
lc_secrets  s   z!ChatGoogleGenerativeAI.lc_secretsr   c                 C     dS )Nzchat-google-generative-air_   r  r_   r_   r`   	_llm_type     z ChatGoogleGenerativeAI._llm_typec                 C     d| j v pd| j v pd| j v S Nzgemini-1.5-prozgemini-1.5-flashzgemini-2r   r  r_   r_   r`   _supports_code_execution  
   
z/ChatGoogleGenerativeAI._supports_code_executionc                 C  r  )NTr_   r  r_   r_   r`   is_lc_serializable  r  z)ChatGoogleGenerativeAI.is_lc_serializableafter)moderI   c                 C  s  | j durd| j   krdkstd td| jdur0d| j  kr+dks0td td| jdur>| jdkr>td| jdsKd| j | _| jpOi }t| | _	t
d	}d}| jsot| jtrl| j }n| j}| j}tj| j||| j|d
| _d| _| S )z@Validates params and passes them to google-generativeai package.Nr   g       @z+temperature must be in the range [0.0, 2.0]rX   z%top_p must be in the range [0.0, 1.0]ztop_k must be positivezmodels/r  credentialsZapi_keyclient_infoclient_options	transport)temperaturery   top_ptop_kr   r   additional_headerstupleitemsr	  rN   r  r   r  rB   get_secret_valuer  genaixZbuild_generative_servicer  r  r  )r  r#  r  r  r  r_   r_   r`   validate_environment  s<   
z+ChatGoogleGenerativeAI.validate_environment"v1betaGenerativeServiceAsyncClientc                 C  sZ   d }| j st| jtr| j }n| j}| js*t r*tj| j |t	d| j
| jd| _| jS )Nr  r  )r  r   r  rB   r&  r  r  r'  Zbuild_generative_async_servicerN   r  r  )r  r  r_   r_   r`   async_client  s   z#ChatGoogleGenerativeAI.async_clientDict[str, Any]c                 C  s   | j | j| j| j| j| jdS )zGet the identifying parameters.r   r   r"  nsafety_settingsresponse_modalitiesr,  r  r_   r_   r`   _identifying_params  s   z*ChatGoogleGenerativeAI._identifying_params)code_executionri   inputr$   configOptional[RunnableConfig]r1  Optional[bool]ri   Optional[list[str]]ru   r)   c                  sb   	 |dur$| j std| j d|vr tt d}|g|d< ntdt j||fd|i|S )z
        Enable code execution. Supported on: gemini-1.5-pro, gemini-1.5-flash,
        gemini-2.0-flash, and gemini-2.0-pro. When enabled, the model can execute
        code to solve problems.
        NzCode execution is only supported on Gemini 1.5 Pro,                     Gemini 1.5 Flash, Gemini 2.0 Flash, and Gemini 2.0 Pro models.                     Current model: toolsr1  z>Tools are already defined.code_execution tool can't be definedri   )r  ry   r   
GoogleToolr   superinvoke)r  r2  r3  r1  ri   ru   code_execution_tool	__class__r_   r`   r;    s   zChatGoogleGenerativeAI.invokeOptional[List[str]]r&   c                 K  sj   | j d
d|i|}td| jd|d| jd}|d| j }r%||d< |p,|dd }r3||d	< |S )z Get standard params for tracing.ri   Zgoogle_genaiZchatr   )Zls_providerZls_model_nameZls_model_typeZls_temperaturemax_output_tokensls_max_tokensNls_stopr_   )Z_get_invocation_paramsr&   r   r   r   r@  )r  ri   ru   paramsZ	ls_paramsrA  rB  r_   r_   r`   _get_ls_params   s   z%ChatGoogleGenerativeAI._get_ls_paramsgeneration_configOptional[Dict[str, Any]]r   c              	   C  sL   dd | j | j|| j| j| j| jd D }|ri ||}tdi |S )Nc                 S  s   i | ]\}}|d ur||qS Nr_   )r   r   vr_   r_   r`   r     s
    	
z:ChatGoogleGenerativeAI._prepare_params.<locals>.<dictcomp>)Zcandidate_countr   Zstop_sequencesr@  r"  r!  r/  r_   )r-  r   r@  r"  r!  r/  r%  r   )r  ri   rE  Z
gen_configr_   r_   r`   _prepare_params  s   z&ChatGoogleGenerativeAI._prepare_params)r7  	functionsr.  tool_configrE  r
  tool_choicer   List[BaseMessage]run_manager"Optional[CallbackManagerForLLMRun]r7  0Optional[Sequence[Union[_ToolDict, GoogleTool]]]rJ  ,Optional[Sequence[_FunctionDeclarationType]]r.  Optional[SafetySettingDict]rK  &Optional[Union[Dict, _ToolConfigDict]]rL  &Optional[Union[_ToolChoiceType, bool]]r8   c                K  sL   | j ||||||||	p| j|
d	}tdd|i|| jj| jd}t|S )Nri   r7  rJ  r.  rK  rE  r
  rL  requestrt   r   r_   )_prepare_requestr
  r   r  generate_contentr	  r   )r  r   ri   rN  r7  rJ  r.  rK  rE  r
  rL  ru   rV  r   r_   r_   r`   	_generate'  s(   
z ChatGoogleGenerativeAI._generate'Optional[AsyncCallbackManagerForLLMRun]c                  s   | j si ||||||d}t j|||fi |I d H S | j||||||||	p,| j|
d	}tdd|i|| j j| jdI d H }t|S )Nr7  rJ  r.  rK  rE  rU  rV  rW  r_   )	r*  r:  
_ageneraterX  r
  r   rY  r	  r   )r  r   ri   rN  r7  rJ  r.  rK  rE  r
  rL  ru   updated_kwargsrV  r   r=  r_   r`   r]  I  sJ   
z!ChatGoogleGenerativeAI._agenerateIterator[ChatGenerationChunk]c                k  s    | j ||||||||	p| j|
d	}td|| jjd|d| ji}d }|D ]S}t|d|d}tt|j	d }tt
|j}|jpBi }|d u rJ|jn$t|dd|dd |dd|dd |d	d|d	d d
}|rw||j |V  q'd S )NrU  rV  rt   r   Tr   r   r   r   r   r   r   r   r   r_   )rX  r
  r   r  stream_generate_contentr	  r   r   r7   r   r(   rx   r   r.   r   on_llm_new_tokenr   )r  r   ri   rN  r7  rJ  r.  rK  rE  r
  rL  ru   rV  r   prev_usage_metadatachunk_chat_resultgenrx   curr_usage_metadatar_   r_   r`   _streamz  s^   





zChatGoogleGenerativeAI._stream"AsyncIterator[ChatGenerationChunk]c                 s\  | j s)i ||||||d}t j|||fi |2 z	3 d H W }|V  q6 d S | j||||||||	p6| j|
d	}d }td|| j jd|d| jiI d H 2 zZ3 d H W }t|d|d}t	t
|jd }t	t|j}|jpoi }|d u rw|jn$t|dd|dd |d	d|d	d |d
d|d
d d}|r||jI d H  |V  qP6 d S )Nr\  rU  r`  r   Tra  r   r   r   r   rb  r_   )r*  r:  _astreamrX  r
  r   rc  r	  r   r   r7   r   r(   rx   r   r.   r   rd  r   )r  r   ri   rN  r7  rJ  r.  rK  rE  r
  rL  ru   r^  valuerV  re  rf  rg  rh  rx   ri  r=  r_   r`   rl    s   






zChatGoogleGenerativeAI._astream)ri   r7  rJ  r.  rK  rL  rE  r
  -Tuple[GenerateContentRequest, Dict[str, Any]]c             
   C  s  |r|rt d|d|d }
tt d}||gkr|}
n|r&t|g}
n|r-t|g}
g }|D ]}t|trA|jsAtd q1|	| q1|}t
|| jd\}}|r|
scd|d|d}t |g }|
D ]*}t|d	rtt|}|d
d |jD  qgt|trt|drqgtd| dt||}d }|rt|d d}g }|rdd | D }t| j||
||| j||d|	d}|r||_|S )NUMust specify at most one of tool_choice and tool_config, received both:

tool_choice=

tool_config=r8  z@HumanMessage with empty content was removed to prevent API error)r   zReceived tool_choice=z but no tools=z>. 'tool_choice' can only be specified if 'tools' is specified.function_declarationsc                 s  s    | ]}|j V  qd S rG  r   r   fr_   r_   r`   r   9  s    
z:ChatGoogleGenerativeAI._prepare_request.<locals>.<genexpr>r1  zTool z- doesn't have function_declarations attributefunction_calling_config)rt  c                 S  s   g | ]
\}}t ||d qS ))category	threshold)r   )r   ctr_   r_   r`   r   L  s    
z;ChatGoogleGenerativeAI._prepare_request.<locals>.<listcomp>)rE  )r   contentsr7  rK  r.  rE  r
  )ry   r9  r   rS   r   r+   r   r   r   r   r   r   r   r   r   r   rq  	TypeErrorrO   r   r%  r   r   rI  r   )r  r   ri   r7  rJ  r.  rK  rL  rE  r
  formatted_toolsr<  Zfiltered_messagesrx   r   historymsgZ	all_namesrx  Zt_with_declarationsZformatted_tool_configZformatted_safety_settingsrV  r_   r_   r`   rX    s   








z'ChatGoogleGenerativeAI._prepare_requestr   intc                 C  s(   | j j| jtt|dgdgd}|jS )a  Get the number of tokens present in the text.

        Useful for checking if an input will fit in a model's context window.

        Args:
            text: The string input to tokenize.

        Returns:
            The integer number of tokens in the text.
        r   r   )r   ry  )r  Zcount_tokensr   r   r   r   )r  r   resultr_   r_   r`   get_num_tokens`  s   z%ChatGoogleGenerativeAI.get_num_tokens)include_rawschemaUnion[Dict, Type[BaseModel]]r  4Runnable[LanguageModelInput, Union[Dict, BaseModel]]c          
      K  s  | dd }| dd }|rtd| t|}t|tr*t|r*t|gdd}ntd da	t
|dd}| jr<|nd }z| j|g|ddit|d	d
}W n tya   | j|g|d}Y nw |rtjtd|B dd djtjdd dgdd}	d|i|	B S ||B S )NmethodstrictzReceived unsupported arguments T)r7  first_tool_onlyzChatGoogleGenerativeAI.with_structured_output with dict schema has changed recently to align with behavior of other LangChain chat models. More context: https://github.com/langchain-ai/langchain-google/pull/772)Zkey_namer  Zfunction_calling)ru   r  )rL  Zls_structured_output_formatrL  rawc                 S     d S rG  r_   _r_   r_   r`   <lambda>      z?ChatGoogleGenerativeAI.with_structured_output.<locals>.<lambda>)parsedparsing_errorc                 S  r  rG  r_   r  r_   r_   r`   r    r  )r  r  )Zexception_key)r   ry   _get_tool_namer   r   rT   r4   r   r   "WARNED_STRUCTURED_OUTPUT_JSON_MODEr3   _supports_tool_choice
bind_toolsr>   r{   r;   Zassignr   Zwith_fallbacks)
r  r  r  ru   r  Z	tool_nameparserrL  ZllmZparser_with_fallbackr_   r_   r`   with_structured_outputp  sH   
z-ChatGoogleGenerativeAI.with_structured_outputr  LSequence[dict[str, Any] | type | Callable[..., Any] | BaseTool | GoogleTool])Runnable[LanguageModelInput, BaseMessage]c                K  s   |r|rt d|d|z	dd |D }W n ty'   tt|g}Y nw |r/||d< n|r6||d< n	 | jd	d|i|S )
a3  Bind tool-like objects to this chat model.

        Assumes model is compatible with google-generativeAI tool-calling API.

        Args:
            tools: A list of tool definitions to bind to this chat model.
                Can be a pydantic model, callable, or BaseTool. Pydantic
                models, callables, and BaseTools will be automatically converted to
                their schema dictionary representation.
            **kwargs: Any additional parameters to pass to the
                :class:`~langchain.runnable.Runnable` constructor.
        ro  rp  c                 S  s   g | ]}t |qS r_   r=   )r   toolr_   r_   r`   r         z5ChatGoogleGenerativeAI.bind_tools.<locals>.<listcomp>rL  rK  r7  Nr_   )ry   r{   rU   rS   bind)r  r7  rK  rL  ru   r{  r_   r_   r`   r    s(   


z!ChatGoogleGenerativeAI.bind_toolsc                 C  r  r  r  r  r_   r_   r`   r    r  z,ChatGoogleGenerativeAI._supports_tool_choice)ra   r  )ra   r   ra   r   )ra   rI   )ra   r)  )ra   r+  rG  )r2  r$   r3  r4  r1  r5  ri   r6  ru   r   ra   r)   )ri   r?  ru   r   ra   r&   )ri   r?  rE  rF  ra   r   )NN)r   rM  ri   r?  rN  rO  r7  rP  rJ  rQ  r.  rR  rK  rS  rE  rF  r
  r   rL  rT  ru   r   ra   r8   )r   rM  ri   r?  rN  r[  r7  rP  rJ  rQ  r.  rR  rK  rS  rE  rF  r
  r   rL  rT  ru   r   ra   r8   )r   rM  ri   r?  rN  rO  r7  rP  rJ  rQ  r.  rR  rK  rS  rE  rF  r
  r   rL  rT  ru   r   ra   r_  )r   rM  ri   r?  rN  r[  r7  rP  rJ  rQ  r.  rR  rK  rS  rE  rF  r
  r   rL  rT  ru   r   ra   rk  )r   rM  ri   r?  r7  rP  rJ  rQ  r.  rR  rK  rS  rL  rT  rE  rF  r
  r   ra   rn  )r   r   ra   r~  )r  r  r  r   ru   r   ra   r  )
r7  r  rK  rS  rL  rT  ru   r   ra   r  )%r[   r\   r]   r^   rA   r  __annotations__r  r   r	  r   r
  r@   Zmodel_configpropertyr  r  r  classmethodr  rC   r(  r*  r0  r;  rD  rI  rZ  r]  rj  rl  rX  r  r  r  r  __classcell__r_   r_   r=  r`   r    s   
  N"%%4AP
\6)r  r  "Union[_ToolDict, GoogleTool, Dict]r   c              
   C  sn   zt t| g}dd |d D d W S  ty6 } zt| r0ttt| d d W  Y d }~S |d }~ww )Nc                 S  s   g | ]}|d  qS r   r_   rr  r_   r_   r`   r     r  z"_get_tool_name.<locals>.<listcomp>rq  r   r   r   )rU   rS   ry   rJ   r>   r   r   )r  Z
genai_toolr~   r_   r_   r`   r    s   "r  )ra   rb   )rt   r   ru   r   ra   r   )r   r   ra   r   )r   r   ra   r   rG  )rx   r   r   r   ra   r   )r   r   r   r'   ra   r   )F)r   r   r   r   ra   r   )r   r   r   r   ra   r'   )FN)r   r   r   r   r   r   ra   r8   r  )r  r  ra   r   )
__future__r   r   r   rp   r   r   operatorr   typingr   r   r   r   r   r	   r
   r   r   r   r   r   r   Zgoogle.api_corerl   r   Z#google.ai.generativelanguage_v1betar   r)  Z)google.ai.generativelanguage_v1beta.typesr   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r9  Z langchain_core.callbacks.managerr"   r#   Zlangchain_core.language_modelsr$   Z*langchain_core.language_models.chat_modelsr%   r&   Zlangchain_core.messagesr'   r(   r)   r*   r+   r,   r-   Zlangchain_core.messages.air.   Zlangchain_core.messages.toolr/   r0   r1   Z"langchain_core.output_parsers.baser2   Z*langchain_core.output_parsers.openai_toolsr3   r4   r5   Zlangchain_core.outputsr6   r7   r8   Zlangchain_core.runnablesr9   r:   r;   Zlangchain_core.toolsr<   Z%langchain_core.utils.function_callingr>   Zpydanticr?   r@   rA   rB   rC   tenacityrD   rE   rF   rG   rH   Ztyping_extensionsrI   rJ   Zlangchain_google_genai._commonrK   rL   rM   rN   Z&langchain_google_genai._function_utilsrO   rP   rQ   rR   rS   rT   rU   Z#langchain_google_genai._image_utilsrV   rW   r   rY   r'  r  	getLoggerr[   ro   r   r   Z_FunctionDeclarationTyperZ   rs   r   r   r   r   r   r   r   r   r   r  r  r  r_   r_   r_   r`   <module>   s    <D$	$	






)
!
E
H 
L      =