
    qi                     (   d 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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mZ ddlmZ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( dd
l)m*Z* ddl+m,Z, ddl-m.Z.m/Z/ ddl0m1Z1m2Z2 ddl3m4Z4 ddl5m6Z6 ddl7m8Z8 ddl9m:Z:m;Z; ddl<m=Z=m>Z> ddl?m@Z@mAZAmBZBmCZCmDZD ddlEmFZF dej                  d<   	 ddlHmIZI ddlJmKZK ddlLmMZMmNZNmOZOmPZPmQZQmRZRmSZSmTZT deIj                  _V         G d de>      Z[ G d  d!e=      Z\e G d" d#             Z] G d$ d%e1      Z^ G d& d'e      Z_e G d( d)eA             Z` G d* d+e;      Zay# eW$ r7ZX ej                  deX         ej                  d        eZdeX       dZX[Xww xY w),zGoogle Gemini integration for Pipecat.

This module provides Google Gemini integration for the Pipecat framework,
including LLM services, context management, and message aggregation.
    N)	dataclassfield)AnyAsyncIteratorDictListLiteralOptional)logger)Image)	BaseModelField)GeminiLLMAdapterGeminiLLMInvocationParams)AssistantImageRawFrameAudioRawFrameFrameFunctionCallCancelFrameFunctionCallInProgressFrameFunctionCallResultFrameLLMContextFrameLLMFullResponseEndFrameLLMFullResponseStartFrameLLMMessagesAppendFrameLLMMessagesFrameLLMThoughtEndFrameLLMThoughtStartFrameLLMThoughtTextFrame)LLMTokenUsage)
LLMContext)LLMAssistantAggregatorParamsLLMUserAggregatorParams)OpenAILLMContextOpenAILLMContextFrame)FrameDirection)LLMSearchResponseFrame)!update_google_client_http_options)FunctionCallFromLLM
LLMService) OpenAIAssistantContextAggregatorOpenAIUserContextAggregator)	NOT_GIVENLLMSettings	_NotGiven_warn_deprecated_paramis_given)
traced_llmfalseGRPC_ENABLE_FORK_SUPPORT)genai)DeadlineExceeded)BlobContentFunctionCallFunctionResponseGenerateContentConfigGenerateContentResponseHttpOptionsParti  P zException: zHIn order to use Google AI, you need to `pip install pipecat-ai[google]`.zMissing module: c                       e Zd ZdZdefdZy)GoogleUserContextAggregatora  Google-specific user context aggregator.

    Extends OpenAI user context aggregator to handle Google AI's specific
    Content and Part message format for user messages.

    .. deprecated:: 0.0.99
        `OpenAIUserContextAggregator` is deprecated and will be removed in a future version.
        Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
        See `OpenAILLMContext` docstring for migration guide.
    aggregationc                 n   K   | j                   j                  t        dt        |      g             yw)zAdd the aggregated user text to the context as a Google Content message.

        Args:
            aggregation: The aggregated user text to add as a user message.
        usertextrolepartsN_contextadd_messager7   r=   selfr@   s     M/opt/pipecat/venv/lib/python3.12/site-packages/pipecat/services/google/llm.pyhandle_aggregationz.GoogleUserContextAggregator.handle_aggregationl   s)      	!!'vd>T=U"VW   35N)__name__
__module____qualname____doc__strrN        rM   r?   r?   ^   s    	XC XrV   r?   c                   T    e Zd ZdZdefdZdefdZdefdZ	de
fdZded	ed
efdZy) GoogleAssistantContextAggregatora  Google-specific assistant context aggregator.

    Extends OpenAI assistant context aggregator to handle Google AI's specific
    Content and Part message format for assistant responses and function calls.

    .. deprecated:: 0.0.99
        `GoogleAssistantContextAggregator` is deprecated and will be removed in a future version.
        Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
        See `OpenAILLMContext` docstring for migration guide.
    r@   c                 n   K   | j                   j                  t        dt        |      g             yw)zHandle aggregated assistant text response.

        Args:
            aggregation: The aggregated text response from the assistant.
        modelrC   rE   NrH   rK   s     rM   rN   z3GoogleAssistantContextAggregator.handle_aggregation   s)      	!!'wt?U>V"WXrO   framec                 h  K   | j                   j                  t        dt        t	        |j
                  |j                  |j                              g             | j                   j                  t        dt        t        |j
                  |j                  ddi      	      g             y
w)zzHandle function call in progress frame.

        Args:
            frame: Frame containing function call details.
        rZ   )idnameargsfunction_callrE   rB   responseIN_PROGRESS)r]   r^   rb   function_responseN)	rI   rJ   r7   r=   r8   tool_call_idfunction_name	argumentsr9   rL   r[   s     rM    handle_function_call_in_progresszAGoogleAssistantContextAggregator.handle_function_call_in_progress   s      	!!&2$118K8KRWRaRa'		
 	!!*:$11!&!4!4&0-%@+	
s   B0B2c                    K   |j                   r:| j                  |j                  |j                  |j                          d{    y| j                  |j                  |j                  d       d{    y7 57 w)ztHandle function call result frame.

        Args:
            frame: Frame containing function call result.
        N	COMPLETED)result_update_function_call_resultrg   rf   ri   s     rM   handle_function_call_resultz<GoogleAssistantContextAggregator.handle_function_call_result   sv      <<33##U%7%7   33##U%7%7  	s$   AA=A9/A=3A;4A=;A=c                 n   K   | j                  |j                  |j                  d       d{    y7 w)zHandle function call cancellation frame.

        Args:
            frame: Frame containing function call cancellation details.
        	CANCELLEDN)rn   rg   rf   ri   s     rM   handle_function_call_cancelz<GoogleAssistantContextAggregator.handle_function_call_cancel   s3      //!3!3[
 	
 	
s   +535rg   rf   rm   c                   K   | j                   j                  D ]p  }|j                  dk(  s|j                  D ]O  }|j                  s|j                  j
                  |k(  s*dt        j                  |      i|j                  _        Q r y w)NrB   value)	rI   messagesrF   rG   re   r]   jsondumpsrb   )rL   rg   rf   rm   messageparts         rM   rn   z=GoogleAssistantContextAggregator._update_function_call_result   s|      }}-- 	XG||v%#MM XD--$2H2H2K2K|2[;BDJJvDV:W..7X	Xs   )BBB"+BN)rP   rQ   rR   rS   rT   rN   r   rj   r   ro   r   rr   r   rn   rU   rV   rM   rX   rX   u   s^    	YC Y
<W 
B7N 
7N 
X X03X=@XrV   rX   c                   >    e Zd ZU dZeed<   eed<   defdZdefdZy)GoogleContextAggregatorPaira  Pair of Google context aggregators for user and assistant messages.

    .. deprecated:: 0.0.99
        `GoogleContextAggregatorPair` is deprecated and will be removed in a future version.
        Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
        See `OpenAILLMContext` docstring for migration guide.

    Parameters:
        _user: User context aggregator for handling user messages.
        _assistant: Assistant context aggregator for handling assistant responses.
    _user
_assistantreturnc                     | j                   S )zmGet the user context aggregator.

        Returns:
            The user context aggregator instance.
        )r|   rL   s    rM   rB   z GoogleContextAggregatorPair.user   s     zzrV   c                     | j                   S )zwGet the assistant context aggregator.

        Returns:
            The assistant context aggregator instance.
        )r}   r   s    rM   	assistantz%GoogleContextAggregatorPair.assistant   s     rV   N)	rP   rQ   rR   rS   r?   __annotations__rX   rB   r   rU   rV   rM   r{   r{      s/    
 '&001 ; rV   r{   c            	            e Zd ZdZ	 	 	 ddeee      deee      dee   f fdZede	dd fd	       Z
defd
ZdefdZdeeeef      fdZdddedeeef   dedefdZdddee   defdZd ZdefdZd Z xZS )GoogleLLMContexta  Google AI LLM context that extends OpenAI context for Google-specific formatting.

    This class handles conversion between OpenAI-style messages and Google AI's
    Content/Part format, including system messages, function calls, and media.

    .. deprecated:: 0.0.99
        `GoogleLLMContext` is deprecated and will be removed in a future version.
        Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
        See `OpenAILLMContext` docstring for migration guide.
    Nru   toolstool_choicec                 8    t         |   |||       d| _        y)zInitialize GoogleLLMContext.

        Args:
            messages: Initial messages in OpenAI format.
            tools: Available tools/functions for the model.
            tool_choice: Tool choice configuration.
        )ru   r   r   N)super__init__system_message)rL   ru   r   r   	__class__s       rM   r   zGoogleLLMContext.__init__   s!     	(%[Q"rV   objr~   c                     t        | t              rCt        | t              s3t        j                  d|         t        | _        | j                          | S )zUpgrade an OpenAI context to a Google context.

        Args:
            obj: OpenAI LLM context to upgrade.

        Returns:
            GoogleLLMContext instance with converted messages.
        zUpgrading to Google: )
isinstancer#   r   r   debugr   !_restructure_from_openai_messages)r   s    rM   upgrade_to_googlez"GoogleLLMContext.upgrade_to_google  sE     c+,ZEU5VLL067,CM113
rV   c                 B    || j                   dd | j                          y)z{Set messages and restructure them for Google format.

        Args:
            messages: List of messages to set.
        N)	_messagesr   )rL   ru   s     rM   set_messageszGoogleLLMContext.set_messages  s     %q..0rV   c                     g }|D ]I  }t        |t              r|j                  |       %| j                  |      }|9|j                  |       K | j                  j                  |       y)zAdd messages to the context, converting to Google format as needed.

        Args:
            messages: List of messages to add (can be mixed formats).
        N)r   r7   appendfrom_standard_messager   extend)rL   ru   converted_messagesmsg	converteds        rM   add_messageszGoogleLLMContext.add_messages(  sl       	9C#w'"))#. !66s;	(&--i8	9 	01rV   c                    g }| j                   D ]?  }|j                         }	 d|v r|d   D ]  }d|v sd|d   d<    |j                  |       A |S # t        $ r"}t        j                  d|        Y d}~;d}~ww xY w)zGet messages formatted for logging with sensitive data redacted.

        Returns:
            List of messages in a format ready for logging.
        rG   inline_dataz...datazError: N)ru   to_json_dict	Exceptionr   r   r   )rL   msgsrx   r   ry   es         rM   get_messages_for_loggingz)GoogleLLMContext.get_messages_for_logging=  s     }} 		G&&(C,c> #G @(D0:?D/7@
 KK		   ,wqc]++,s   A
A	A>A99A>rC   formatsizeimagerD   c          	      Z   t        j                         }t        j                  |||      j	                  |d       g }|r|j                  t        |             |j                  t        t        d|j                                            | j                  t        d|             y	)
a  Add an image message to the context.

        Args:
            format: Image format (e.g., 'RGB', 'RGBA').
            size: Image dimensions as (width, height).
            image: Raw image bytes.
            text: Optional text to accompany the image.
        JPEG)r   rC   
image/jpeg	mime_typer   r   rB   rE   N)ioBytesIOr   	frombytessaver   r=   r6   getvaluerJ   r7   )rL   r   r   r   rD   bufferrG   s          rM   add_image_frame_messagez(GoogleLLMContext.add_image_frame_messageP  s{     e,11&1HLL4)Td\HY&Z[\fE:;rV   zAudio followsaudio_framesc                   |sy|d   j                   }|d   j                  }g }dj                  d |D              }|j                  t	        |             |j                  t	        t        dt        | j                  ||dt        |            |z               	             | j                  t        d
|             y)zAdd audio frames as a message to the context.

        Args:
            audio_frames: List of audio frames to add.
            text: Text description of the audio content.
        Nr   rV   c              3   4   K   | ]  }|j                     y wN)audio).0r[   s     rM   	<genexpr>z<GoogleLLMContext.add_audio_frames_message.<locals>.<genexpr>u  s     >>s   rC   z	audio/wav   r   r   rB   rE   )sample_ratenum_channelsjoinr   r=   r6   bytescreate_wav_headerlenrJ   r7   )rL   r   rD   r   r   rG   r   s          rM   add_audio_frames_messagez)GoogleLLMContext.add_audio_frames_messagee  s     "1o11#A33xx>>> 	Tt_% ) 22;bRUVZR[\_cc		
 	fE:;rV   c                    |d   }|j                  dg       }|dk(  rFt        |t              r|| _        yt        |t              rdj                  d |D              | _        y|dk(  rd}g }|j                  d	      rQ|d	   D ]G  }|j                  t        t        |d
   d   t        j                  |d
   d                            I n]|dk(  rYd}	 t        j                  |d         }t        |t              r|}nd|i}|j                  t        t        d|                   nt        |t              r|j                  t        |             nt        |t              r|D ]  }	|	d   dk(  r|j                  t        |	d                *|	d   dk(  s3|	d   d   }
|
j                  d      r&|
j                  d      d   j                  d      d   nd}|j                  t        t!        |t#        j$                  |
j                  d      d                !              t'        ||"      }|S # t        $ r}d|d   i}Y d}~Kd}~ww xY w)#a  Convert standard format message to Google Content object.

        Handles conversion of text, images, and function calls to Google's format.
        System messages are stored separately and return None.

        Args:
            message: Message in standard format.

        Returns:
            Content object with role and parts, or None for system messages.

        Examples:
            Standard text message::

                {
                    "role": "user",
                    "content": "Hello there"
                }

            Converts to Google Content with::

                Content(
                    role="user",
                    parts=[Part(text="Hello there")]
                )

            Standard function call message::

                {
                    "role": "assistant",
                    "tool_calls": [
                        {
                            "function": {
                                "name": "search",
                                "arguments": '{"query": "test"}'
                            }
                        }
                    ]
                }

            Converts to Google Content with::

                Content(
                    role="model",
                    parts=[Part(function_call=FunctionCall(name="search", args={"query": "test"}))]
                )

            System message returns None and stores content in self.system_message.
        rF   contentsystem c              3   P   K   | ]  }|j                  d       dk(  s|d      yw)typerD   N)get)r   ry   s     rM   r   z9GoogleLLMContext.from_standard_message.<locals>.<genexpr>  s)      /%)8HF8RDL/s   &
&Nr   rZ   
tool_callsfunctionr^   rh   )r^   r_   r`   toolrt   tool_call_result)r^   rb   rd   rC   r   rD   	image_urlurldata::   ;r   r   ,r   r   rE   )r   r   rT   r   listr   r   r=   r8   rv   loadsdictr   r9   
startswithsplitr6   base64	b64decoder7   )rL   rx   rF   r   rG   tcrb   response_dictr   cr   r   s               rM   r   z&GoogleLLMContext.from_standard_message  sS   d v++i,8'3'&-#  GT*&)hh /-4/ '# [ D;;|$l+ &2!#J!7!%BzN;,G!H' V^D>::gi&89h-$,M%,h$7M LL&6/!.' %LL7+,& V9&LL1V9!56vY+-K./C;>>>';R		#q)//4Q7Xd  LL(,*3%+%5%5ciinQ6G%H)$ t51C  >!(')*< =>s   /H: :	IIIc           	         |j                   g d}|d   dk(  rd|d<   |j                  D ]  }|j                  r"|d   j                  d|j                  d       2|j                  rlt        j                  |j                  j                        j                  d      }|d   j                  d	d
d|j                  j                   d| id       |j                  rxt        |j                  d      r|j                  j                  ni }|j                  j                  d|j                  j                  t        j                  |      ddg|d<   .|j                   s<d|d<   t        |j                   d      r|j                   j"                  ni }|j                   j                  |d<   t        j                  |      |d<    |d   s|d= |gS )a_  Convert Google Content object to standard structured format.

        Handles text, images, and function calls from Google's Content/Part objects.

        Args:
            obj: Google Content object with role and parts.

        Returns:
            List containing a single message in standard format.

        Examples:
            Google Content with text::

                Content(
                    role="user",
                    parts=[Part(text="Hello")]
                )

            Converts to::

                [
                    {
                        "role": "user",
                        "content": [{"type": "text", "text": "Hello"}]
                    }
                ]

            Google Content with function call::

                Content(
                    role="model",
                    parts=[Part(function_call=FunctionCall(name="search", args={"q": "test"}))]
                )

            Converts to::

                [
                    {
                        "role": "assistant",
                        "tool_calls": [
                            {
                                "id": "search",
                                "type": "function",
                                "function": {
                                    "name": "search",
                                    "arguments": '{"q": "test"}'
                                }
                            }
                        ]
                    }
                ]

            Google Content with image::

                Content(
                    role="user",
                    parts=[Part(inline_data=Blob(mime_type="image/jpeg", data=bytes_data))]
                )

            Converts to::

                [
                    {
                        "role": "user",
                        "content": [
                            {
                                "type": "image_url",
                                "image_url": {"url": "data:image/jpeg;base64,<encoded_data>"}
                            }
                        ]
                    }
                ]
        )rF   r   rF   rZ   r   r   rD   )r   rD   zutf-8r   r   r   z;base64,)r   r   r_   r   )r^   rh   )r]   r   r   r   r   rb   rf   )rF   rG   rD   r   r   r   	b64encoder   decoder   ra   hasattrr_   r^   rv   rw   re   rb   )rL   r   r   ry   encodedr_   resps          rM   to_standard_messagesz%GoogleLLMContext.to_standard_messages   s   T xxB/v;'!%CKII  	2DyyI%%vtyy&IJ!! **4+;+;+@+@AHHQI%% +&+uT5E5E5O5O4PPXY`Xa-b%c ##29$:L:Lf2Ut))..[] #0055 *$($6$6$;$;)-D)9%	%L! ''$F t55zB **33 
 '+&<&<&A&AN#!%D!1IA 	2F 9~IurV   c                    d| _         g }| j                  D ]I  }t        |t              r|j	                  |       %| j                  |      }|9|j	                  |       K || j                  dd t        d | j                  D              }| j                   r=|s;| j                  j	                  t        dt        | j                         g             | j                  D cg c]  }|j                  s| c}| _        yc c}w )a  Restructures messages to ensure proper Google format and message ordering.

        This method handles conversion of OpenAI-formatted messages to Google format,
        with special handling for function calls, function responses, and system messages.
        System messages are added back to the context as user messages when needed.

        The final message order is preserved as:
        1. Function calls (from model)
        2. Function responses (from user)
        3. Text messages (converted from system messages)

        Note:
            System messages are only added back when there are no regular text
            messages in the context, ensuring proper conversation continuity
            after function calls.
        Nc              3      K   | ]r  }t        |j                        d k(  xrT t        |j                  d   dd      xr8 t        |j                  d   dd       xr t        |j                  d   dd        t yw)r   r   rD   Nra   re   )r   rG   getattr)r   r   s     rM   r   zEGoogleLLMContext._restructure_from_openai_messages.<locals>.<genexpr>  s      #

 	 		Na E		!fd3ECIIaL/4@@E CIIaL*=tDDE#
s   A8A:rB   rC   rE   )	r   r   r   r7   r   r   anyr=   rG   )rL   r   rx   r   has_regular_messagesms         rM   r   z2GoogleLLMContext._restructure_from_openai_messagesu  s    " # ~~ 		5G'7+"))'2 227;I$")))4		5 /q  # #

 ~~#
  
 ';NN!!'vdH[H[>\=]"^_ &*^^?qww!??s   $D6DNNN)rP   rQ   rR   rS   r
   r   r   r   staticmethodr#   r   r   r   r   rT   r   r   tupleintr   r   r   r   r   r   r   r   __classcell__r   s   @rM   r   r      s   	 *.&*&*	#4:&# T
## d^	#" / 4F  1T 12T 2*$tCH~*> ( PT<<$)#s(O<<A<IL<, AP <#M2 <:= <Huns4 sj1@rV   r   c                       e Zd ZU dZ ed      Zee   ed<    ed      Z	ee
d   ez     ed<    ed      Zee   ed<   y)GoogleThinkingConfiga  Configuration for controlling the model's internal "thinking" process used before generating a response.

    Gemini 2.5 and 3 series models have this thinking process.

    Parameters:
        thinking_level: Thinking level for Gemini 3 models.
            For Gemini 3 Pro, this can be "low" or "high".
            For Gemini 3 Flash, this can be "minimal", "low", "medium", or "high".
            If not provided, Gemini 3 models default to "high".
            Note: Gemini 2.5 series must use thinking_budget instead.
        thinking_budget: Token budget for thinking, for Gemini 2.5 series.
            -1 for dynamic thinking (model decides), 0 to disable thinking,
            or a specific token count (e.g., 128-32768 for 2.5 Pro).
            If not provided, most models today default to dynamic thinking.
            See https://ai.google.dev/gemini-api/docs/thinking#set-budget
            for default values and allowed ranges.
            Note: Gemini 3 models must use thinking_level instead.
        include_thoughts: Whether to include thought summaries in the response.
            Today's models default to not including thoughts (False).
    Ndefaultthinking_budget)lowhighmediumminimalthinking_levelinclude_thoughts)rP   rQ   rR   rS   r   r   r
   r   r   r   r	   rT   r   boolrU   rV   rM   r   r     s[    * &+4%8OXc]8 SXSNHW%GH3NO  (-T':htn:rV   r   c                   R     e Zd ZU dZ ed       Zeez  ed<   e	 fd       Z
 xZS )GoogleLLMSettingsz^Settings for GoogleLLMService.

    Parameters:
        thinking: Thinking configuration.
    c                      t         S r   )r,   rU   rV   rM   <lambda>zGoogleLLMSettings.<lambda>  s    y rV   default_factorythinkingc                     t         |   |      }t        |j                        r4t	        |j                  t
              rt        di |j                  |_        |S )zConvert a plain dict to settings, coercing thinking dicts.

        For backward compatibility, a ``thinking`` value that is a plain dict
        is converted to a :class:`GoogleThinkingConfig`.
        rU   )r   from_mappingr0   r  r   r   r   )clssettingsinstancer   s      rM   r  zGoogleLLMSettings.from_mapping  sL     7'1H%%&:h6G6G+N 4 Ix7H7H IHrV   )rP   rQ   rR   rS   r   r  r   r.   r   classmethodr  r   r   s   @rM   r  r    s2     27GX1YH"Y.Y	 	rV   r  c                   ,    e Zd ZU dZeZeed<   eZe	Z
 G d de      Zdddddddddedee   d	ee   d
ee   dee   deeeeef         deeeef      dee   f fdZdefdZd Z	 	 d(deez  dee   dee   dee   fdZ	 	 	 d)dee   dee   deeeef      deeef   fdZdeeef   fdZdedee   fdZ dedee   fdZ!dedee   fdZ"e#deez  fd       Z$de%de&f fd Z' fd!Z( fd"Z)d# Z* e+        e,       d$ded%e+d&e,de-fd'Z. xZ/S )*GoogleLLMServicezGoogle AI (Gemini) LLM service implementation.

    This class implements inference with Google's AI models, translating internally
    from an OpenAILLMContext or a universal LLMContext to the messages format
    expected by the Google AI model.
    	_settingsc                       e Zd ZU dZ edd      Zee   ed<    eddd	      Z	ee
   ed
<    edd      Zee   ed<    eddd	      Zee
   ed<    ed      Zee   ed<    ee      Zeeeef      ed<   y)GoogleLLMService.InputParamsa  Input parameters for Google AI models.

        .. deprecated:: 0.0.105
            Use ``settings=GoogleLLMSettings(...)`` instead.

        Parameters:
            max_tokens: Maximum number of tokens to generate.
            temperature: Sampling temperature between 0.0 and 2.0.
            top_k: Top-k sampling parameter.
            top_p: Top-p sampling parameter between 0.0 and 1.0.
            thinking: Thinking configuration with thinking_budget, thinking_level, and include_thoughts.
                Used to control the model's internal "thinking" process used before generating a response.
                Gemini 2.5 series models use thinking_budget; Gemini 3 models use thinking_level.
                If this is not provided, Pipecat disables thinking for all
                models where that's possible (the 2.5 series, except 2.5 Pro),
                to reduce latency.
            extra: Additional parameters as a dictionary.
           r   )r   ge
max_tokensNg        g       @)r   r  letemperaturer   top_kg      ?top_pr   r  r  extra)rP   rQ   rR   rS   r   r  r
   r   r   r  floatr  r  r  r   r   r  r   rT   r   rU   rV   rM   InputParamsr    s    	& %*$1$=
HSM=',Tcc'JXe_J$Ta8x}8!&t!DxD383F(/0F*/*ExS#X'ErV   r  N)rZ   paramsr
  system_instructionr   tool_confighttp_optionsapi_keyrZ   r  r
  r  r   r  r  c                x   t        ddddddddddddi       }
|t        dt         d       ||
_        |t        dt         d       ||
_        |t        dt                |s|j                  |
_        |j
                  |
_        |j                  |
_        |j                  |
_        |j                  |
_        t        |j                  t              r|j                  |
_
        ||
j                  |       t        | 8  d
d	|
i|	 || _        t!        |      | _        || _        || _        | j)                          y)a1  Initialize the Google LLM service.

        Args:
            api_key: Google AI API key for authentication.
            model: Model name to use.

                .. deprecated:: 0.0.105
                    Use ``settings=GoogleLLMSettings(model=...)`` instead.

            params: Optional model parameters for inference.

                .. deprecated:: 0.0.105
                    Use ``settings=GoogleLLMSettings(...)`` instead.

            settings: Runtime-updatable settings for this service.  When both
                deprecated parameters and *settings* are provided, *settings*
                values take precedence.
            system_instruction: System instruction/prompt for the model.

                .. deprecated:: 0.0.105
                    Use ``settings=GoogleLLMSettings(system_instruction=...)`` instead.
            tools: List of available tools/functions.
            tool_config: Configuration for tool usage.
            http_options: HTTP options for the client.
            **kwargs: Additional arguments passed to parent class.
        gemini-2.5-flashNr  F)rZ   r  r  r  r  r  frequency_penaltypresence_penaltyseedfilter_incomplete_user_turnsuser_turn_completion_configr  r  rZ   r  r  r
  rU   )r  r/   rZ   r  r  r  r  r  r  r   r  r   apply_updater   r   _api_keyr'   _http_options_tools_tool_configcreate_client)rL   r   rZ   r  r
  r  r   r  r  kwargsdefault_settingsr   s              rM   r   zGoogleLLMService.__init__  sG   P -$#"!).(,
" "7,=wG%*")"#79JL`a2D/ "8->?.4.?.? +/5/A/A ,)/ &)/ &,2OO )fllD1-3\\$* ))(3="2=f=>|L' 	rV   r~   c                      y)zCheck if the service can generate usage metrics.

        Returns:
            True, as Google AI provides token usage metrics.
        TrU   r   s    rM   can_generate_metricsz%GoogleLLMService.can_generate_metricsg  s     rV   c                 d    t        j                  | j                  | j                        | _        y)z@Create the Gemini client instance. Subclasses can override this.)r   r  N)r4   Clientr)  r*  _clientr   s    rM   r-  zGoogleLLMService.create_cliento  s    ||DMMHZHZ[rV   contextr  c                   K   g }g }g }t        |t              r1| j                         }|j                  |      }|d   }|d   }|d   }n>t        j                  |      }|j                  }t        |dd      }|j                  xs g }||rt        j                  |  d       |}| j                  ||r|nd      }	|||	d<   t        di |	}
| j                  j                  j                  j!                  | j"                  j$                  ||
	       d{   }|j&                  r[|j&                  d
   j(                  rB|j&                  d
   j(                  j*                  D ]  }|j,                  s|j,                  c S  y7 lw)aV  Run a one-shot, out-of-band (i.e. out-of-pipeline) inference with the given LLM context.

        Args:
            context: The LLM context containing conversation history.
            max_tokens: Optional maximum number of tokens to generate. If provided,
                overrides the service's default max_tokens setting.
            system_instruction: Optional system instruction to use for this inference.
                If provided, overrides any system instruction in the context.

        Returns:
            The LLM's response as a string, or None if no response is generated.
        ru   r  r   r   N\: Both system_instruction and a system message in context are set. Using system_instruction.)r  r   max_output_tokensrZ   contentsconfigr   rU   )r   r    get_llm_adapterget_llm_invocation_paramsr   r   ru   r   r   r   warning_build_generation_paramsr:   r4  aiomodelsgenerate_contentr  rZ   
candidatesr   rG   rD   )rL   r5  r  r  ru   r   r   adapterr  generation_paramsgeneration_configrb   ry   s                rM   run_inferencezGoogleLLMService.run_inferences  s    $ gz***,G070Q0QRY0ZFj)H01F7OE&88AG''HW&6=FMM'RE )f 1 1 (F !99%eU : 

 !5?121F4EF ))00AA..&&$ B 
 
 8#6#6q#9#A#A ++A.66<< %9999$% 
s   DFFAF5Fc                     || j                   j                  | j                   j                  | j                   j                  | j                   j                  ||dj                         D ci c]
  \  }}||| }}}| j                   j                  r)| j                   j                  j                  d      |d<   | j                   j                  r%|j                  | j                   j                         |S c c}}w )aW  Build generation parameters for Google AI API.

        Args:
            system_instruction: Optional system instruction to use.
            tools: Optional list of tools to include.
            tool_config: Optional tool configuration.

        Returns:
            Dictionary of generation parameters with None values filtered out.
        )r  r  r  r  r8  r   r  T)exclude_unsetthinking_config)
r  r  r  r  r  itemsr  
model_dumpr  update)rL   r  r   r  kvrE  s          rM   r?  z)GoogleLLMService._build_generation_params  s    ( '9#~~99----%)^^%>%>* eg
1 } qD
 
 >>""37>>3J3J3U3U" 4V 4/0 >>$$T^^%9%9:  /
s   ,C:rE  c                    	 | j                   j                  j                  d      sy d| j                   j                  v ry d|v ry d|j                  di       d<   y # t        $ r"}t        j                  d|        Y d }~y d }~ww xY w)Nr"  r   rJ  r   r   z!Failed to unset thinking budget: )r  rZ   r   
setdefaultr   r   error)rL   rE  r   s      rM   _maybe_unset_thinking_budgetz-GoogleLLMService._maybe_unset_thinking_budget  s    	B >>''223EF$..... $55UV(():B?@QR 	BLL<QC@AA	Bs(   %A A A A 	B%BBparams_from_contextc                 f  K   |d   }| j                   j                  r|d   rt        j                  |  d       | j                   j                  xs |d   }g }|d   r|d   }n| j                  r| j                  }d }| j
                  r| j
                  }| j                  |||      }| j                  |       t        di |}| j                          d {    | j                  j                  j                  j                  | j                   j                  ||       d {   S 7 R7 w)Nru   r  r7  r   )r  r   r  r9  rU   )r  r  r   r>  r+  r,  r?  rS  r:   start_ttfb_metricsr4  r@  rA  generate_content_streamrZ   )rL   rT  ru   r  r   r  rE  rF  s           rM   _stream_contentz GoogleLLMService._stream_content  sF     'z2 >>,,1DEY1ZNN& 2 2
 NN--Z1DEY1Z 	 w''0E[[KKE++K !991# : 
 	))*;<1F4EF%%'''\\%%,,DD..&&$ E 
 
 	
 	(
s%   CD1D-AD1(D/)D1/D1c                   K   t        j                  |  d|j                   d|j                                 t	        |j
                  |j                  |j                        }| j                  |       d {   S 7 w)Nz-: Generating chat from LLM-specific context [] | )ru   r  r   )r   r   r   r   r   ru   r   rX  )rL   r5  r  s      rM    _stream_content_specific_contextz1GoogleLLMService._stream_content_specific_context  s      	fA'BXBXAYY]^e^~^~  _A  ^B  C	
 +%%&55--
 ))&1111s   A6A?8A=9A?c           	         K   | j                         }|j                  |      }t        j                  |  d|d    d|j	                  |              | j                  |       d {   S 7 w)Nz*: Generating chat from universal context [r  rZ  )r<  r=  r   r   r   rX  )rL   r5  rD  r  s       rM   !_stream_content_universal_contextz2GoogleLLMService._stream_content_universal_context,  s      &&(,3,M,Mg,Vf>vFZ?[>\\`ah  bB  bB  CJ  bK  aL  M	
 ))&1111s   A%A.'A,(A.c                   K   | j                  t                      d {    d}d}d}d}d}d }d}	 t        |t              r| j	                  |      n| j                  |       d {   }	g }
|	2 3 d {   }| j                          d {    |j                  r|j                  j                  xs d}|j                  j                  xs d}|j                  j                  xs d}|j                  j                  xs d}|j                  j                  xs d}|j                  s|j                  D ]|  }|j                  r#|j                  j                  r|j                  j                  D ]  }d }|j                   r|j"                  rp| j                  t%                      d {    | j                  t'        |j                                d {    | j                  t)                      d {    n||j                   z  }| j+                  |j                          d {    nd|j,                  r|j,                  }|j.                  xs t1        t3        j4                               }t7        j8                  d|j:                   d|        |
j=                  t?        |||j:                  |j@                  xs i              n|jB                  r|jB                  jD                  rtG        jH                  tK        jL                  |jB                  jD                              }| j                  tO        |jQ                         |jR                  d|jB                  jD                  |jB                  jT                               d {    |jV                  s4i }|j,                  r||d<   nY|jB                  r&|jB                  jD                  r|jB                  |d	<   n'|j                   ||d
<   nt7        jX                  d       |s| j                  t[        | j]                         j_                  d|jV                  |d      g             d {     |j`                  sB|j`                  jb                  sZ|j`                  }|jd                  r|jd                  jf                  nd }ti        |jb                  r|jb                  ng       D cg c]  \  }}|jj                  r|jj                  jl                  nd |jj                  r|jj                  jn                  nd |jp                  r|jp                  ng D cg c]M  }|jr                  r?||jr                  v r1|jt                  r|jt                  j                   nd|jv                  dO c}d }}}}||d} J7 7 V7 L7 77 7 7 7 7 ;7 qc c}w c c}}}w 6 | jy                  |
       d {  7   nY# tz        $ r | j}                  d       d {  7   Y n4t~        $ r)}| j                  d| |       d {  7   Y d }~nd }~ww xY w|r>t        |t              r.t        ||d   |d         }| j                  |       d {  7   | j                  t        |||||             d {  7   | j                  t                      d {  7   y # |r>t        |t              r.t        ||d   |d         }| j                  |       d {  7   | j                  t        |||||             d {  7   | j                  t                      d {  7   w xY ww)Nr    zFunction call: r   )r5  rf   rg   rh   RGB)r   r   r   original_dataoriginal_mime_typera   r   rD   z.Thought signature found on unhandled Part typethought_signature)r   	signaturebookmark)rD   
confidence)site_uri
site_titleresults)rendered_contentoriginson_completion_timeoutzUnknown error occurred: )	error_msg	exceptionrk  rj  )search_resultrk  rj  )prompt_tokenscompletion_tokenstotal_tokenscache_read_input_tokensreasoning_tokens)F
push_framer   r   r#   r[  r]  stop_ttfb_metricsusage_metadataprompt_token_countcandidates_token_counttotal_token_countcached_content_token_countthoughts_token_countrC  r   rG   rD   thoughtr   r   r   _push_llm_textra   r]   rT   uuiduuid4r   r   r^   r   r(   r_   r   r   r   openr   r   r   tobytesr   r   rc  r>  r   r<  create_llm_specific_messagegrounding_metadatagrounding_chunkssearch_entry_pointrj  	enumerateweburititlegrounding_supportsgrounding_chunk_indicessegmentconfidence_scoresrun_function_callsr5   _call_event_handlerr   
push_errorr   r&   start_llm_usage_metricsr   r   )rL   r5  rp  rq  rr  rs  rt  r  accumulated_textrb   function_callschunk	candidatery   function_call_idra   r   re  r   rj  indexgrounding_chunkgrounding_supportrk  r   llm_search_frames                             rM   _process_contextz!GoogleLLMService._process_context8  s    oo79:::"#!s	= g'78 55g>;;GDH  N' Q Qe,,... ''$)$8$8$K$K$PqM(-(<(<(S(S(XWX%#(#7#7#I#I#NQL.3.B.B.].].bab+',';';'P'P'UTU$''!&!1!1 ~I ((Y->->-D-D$-$5$5$;$; U&D/3,#yy#'<< +///:N:P*Q$Q$Q*.//:Mdii:X*Y$Y$Y*.//:L:N*O$O$O$4		$A$4*.*=*=dii*H$H$H!%!3!3040B0B3@3C3C3Xs4::<GX 0 &&5m6H6H5IK[J\$]!" !/ 5 5$7075E6C6H6H2?2D2D2J	%&!" "&!1!1d6F6F6K6K(-

2::d>N>N>S>S3T(U&*oo$:.3mmo-2ZZ/46:6F6F6K6K;?;K;K;U;U%&'" !" !"2  $55
 ,.#'#5#5@PH_$=%)%5%5$:J:J:O:O>B>N>NH]$;%)YY%: 8HHV$4$*NN3c$d#+*.//(>040D0D0F0b0b@SEIE[E[DL5612-.
)*+& %& %&SU&p "44%88II%88EFEYEYA00AA_c )2 ;D676H6H 2 2b;-# #, !7' $3#6#6 -<,?,?,C,C%)#2#6#6 />.A.A.G.G%) AB@T@T(<(<Z\," ): (9'P'P(-1B1Z1Z(Z ,=+D+D 1B0I0I0N0N-/6G6Y6Y	%&,"# #6 1A'..*w~O 	;Q.4 %R$Y$O %I$!"V%&<,"#i  (f )).999 	D**+BCCC 	Y//.Fqc,JVW/XXX	Y "j1CT&J#9"2.y9%78J%K$ 
 oo&6777.."/&7!-,C%5   //"9";<<<# "j1CT&J#9"2.y9%78J%K$ 
 oo&6777.."/&7!-,C%5   //"9";<<<s  ]4V;]45X (V>)X 1W%5W6W%9X WD#X 1W
2+X W

 X >W
?3X 2W
3E%X W
X +A/X A	X %W
&X ;X AX *A*WAW&W-X ;]4>X W%X X 
X X X X X WX :W=;X  [% YX!Y$[% &Y.YY
Y[% Y[% :]4Z']4<Z?=!]4[!]4%;]1 \#!']1]	!]1*]-+]11]4r[   	directionc                   K   t         |   ||       d{    d}t        |t              r t        j                  |j                        }n]t        |t              r|j                  }n@t        |t              rt	        |j                        }n| j                  ||       d{    |r| j                  |       d{    yy7 7 #7 
w)zProcess incoming frames and handle different frame types.

        Args:
            frame: The frame to process.
            direction: Direction of frame processing.
        N)r   process_framer   r$   r   r   r5  r   r   ru   ru  r  )rL   r[   r  r5  r   s       rM   r  zGoogleLLMService.process_frame  s      g#E9555e23&88GG/mmG/0 'u~~6G//%333''000 ! 	6 4 1s4   CCBC&C
'CCC
CCc                 t   K   t         |   |       d{    | j                          d{    y7 7 w)z-Override stop to gracefully close the client.N)r   stop_close_clientrL   r[   r   s     rM   r  zGoogleLLMService.stop  s4     gl5!!!  """ 	""   848688c                 t   K   t         |   |       d{    | j                          d{    y7 7 w)z/Override cancel to gracefully close the client.N)r   cancelr  r  s     rM   r  zGoogleLLMService.cancel  s4     gnU###  """ 	$"r  c                    K   	 | j                   j                  j                          d {    y 7 # t        $ r Y y w xY wwr   )r4  r@  acloser   r   s    rM   r  zGoogleLLMService._close_client  s8     	,,""))+++ 		s,   A'3 13 A3 	?A?A)user_paramsassistant_paramsr  r  c                    |j                  | j                                t        |t              rt        j                  |      }t        ||      }t        ||      }t        ||      S )a  Create Google-specific context aggregators.

        Creates a pair of context aggregators optimized for Google's message format,
        including support for function calls, tool usage, and image handling.

        Args:
            context: The LLM context to create aggregators for.
            user_params: Parameters for user message aggregation.
            assistant_params: Parameters for assistant message aggregation.

        Returns:
            GoogleContextAggregatorPair: A pair of context aggregators, one for
            the user and one for the assistant, encapsulated in an
            GoogleContextAggregatorPair.

        .. deprecated:: 0.0.99
            `create_context_aggregator()` is deprecated and will be removed in a future version.
            Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
            See `OpenAILLMContext` docstring for migration guide.
        )r  )r|   r}   )	set_llm_adapterr<  r   r#   r   r   r?   rX   r{   )rL   r5  r  r  rB   r   s         rM   create_context_aggregatorz*GoogleLLMService.create_context_aggregator%  s^    6 	 4 4 67g/0&88AG +7;G4WEUV	*)LLrV   )NNr   )0rP   rQ   rR   rS   r  Settingsr   r   adapter_classr   ThinkingConfigr   r  rT   r
   r   r   r   r<   r   r   r1  r-  r    r#   r   rG  r?  rS  r   r   r;   rX  r[  r]  r1   r  r   r%   r  r  r  r  r"   r!   r{   r  r   r   s   @rM   r  r    s}    !H   %M *NFi F>  $(,04,00404.2X X }	X
 %X ,-X %SMX T#s(^,-X d38n-X {+Xtd \ %),0	B..B SMB %SM	B
 
#BL -1 $04	(!$SM(! ~(! d38n-	(!
 
c3h(!TBd38n B")
#<)
	.	/)
V2'2	.	/2
2!
2	.	/
2 =.>.K = =B1 1> 14#
#
 0G/H9U9W$M!$M -	$M
 7$M 
%$MrV   r  )brS   r   r   rv   osr  dataclassesr   r   typingr   r   r   r   r	   r
   logurur   PILr   pydanticr   r   (pipecat.adapters.services.gemini_adapterr   r   pipecat.frames.framesr   r   r   r   r   r   r   r   r   r   r   r   r   r   pipecat.metrics.metricsr   *pipecat.processors.aggregators.llm_contextr    +pipecat.processors.aggregators.llm_responser!   r"   1pipecat.processors.aggregators.openai_llm_contextr#   r$   "pipecat.processors.frame_processorr%   pipecat.services.google.framesr&   pipecat.services.google.utilsr'   pipecat.services.llm_servicer(   r)   pipecat.services.openai.llmr*   r+   pipecat.services.settingsr,   r-   r.   r/   r0   (pipecat.utils.tracing.service_decoratorsr1   environgoogler4   google.api_core.exceptionsr5   google.genai.typesr6   r7   r8   r9   r:   r;   r<   r=   _api_clientREAD_BUFFER_SIZEModuleNotFoundErrorr   rR  r   r?   rX   r{   r   r   r  r  rU   rV   rM   <module>r     s    	  	  ( D D   % `     2 A > A K H  @ *1

% &,;	 	 	 *9E&X"= X.WX'G WXt   Dt@' t@n;9 ;B   ,h	Mz h	MS  ,FLL;qc"#FLL[\
&qc*
++,s   1E F2FF