
    qiAC                    <   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ZddlmZm	Z	 ddl
mZ ddlmZmZmZmZmZ ddlmZ ddlmZ ddlmZmZ dd	lm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,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9 ddl:m;Z; ddl<m=Z= ddl>m?Z?m@Z@ ddlAmBZB ddlCmDZDmEZE ddlFmGZG ddlHmIZImJZJmKZK ddlLmMZM ddlNmOZOmPZP ddlQmRZRmSZS ddlTmUZUmVZVmWZWmXZX ddlYmZZZm[Z[ ddl\m]Z] ddl^m_Z_ ddl`maZambZb ddlcmdZd 	 ddlemfZf ddlgmhZh ddlimjZjmkZkmlZlmmZmmnZnmoZompZpmqZqmrZrmsZsmtZtmuZumvZvmwZwmxZxmyZymzZzm{Z{m|Z|m}Z}m~Z~mZmZmZ d#Zd$Zd%eZd&ee   fd'Z G d( d)eD      Z G d* d+eS      Z G d, d-eR      Ze G d. d/             Z G d0 d1e      Z G d2 d3ee      Z G d4 d5e      Z G d6 d7e      Z G d8 d9e      Ze G d: d;eV             Z G d< d=eP      Zy# e$ r9Z ej                  d e         ej                  d!        ed"e       dZ[ww xY w)>zGoogle Gemini Live API service implementation.

This module provides real-time conversational AI capabilities using Google's
Gemini Live API, supporting both text and audio modalities with
voice transcription, streaming responses, and tool usage.
    N)	dataclassfield)Enum)AnyDictListOptionalUnion)logger)Image)	BaseModelField)ToolsSchema)GeminiLLMAdapter)AggregationTypeBotStartedSpeakingFrameBotStoppedSpeakingFrameCancelFrameEndFrameFrameInputAudioRawFrameInputImageRawFrameInputTextRawFrameInterruptionFrameLLMContextFrameLLMFullResponseEndFrameLLMFullResponseStartFrameLLMMessagesAppendFrameLLMSetToolsFrameLLMTextFrameLLMThoughtEndFrameLLMThoughtStartFrameLLMThoughtTextFrame
StartFrameTranscriptionFrameTTSAudioRawFrameTTSStartedFrameTTSStoppedFrameTTSTextFrameUserImageRawFrameUserStartedSpeakingFrameUserStoppedSpeakingFrame)LLMTokenUsage)
LLMContext)LLMAssistantAggregatorParamsLLMUserAggregatorParams)LLMContextAggregatorPair)OpenAILLMContextOpenAILLMContextFrame)FrameDirection)LLMSearchOriginLLMSearchResponseFrameLLMSearchResult)!update_google_client_http_options)FunctionCallFromLLM
LLMService) OpenAIAssistantContextAggregatorOpenAIUserContextAggregator)	NOT_GIVENLLMSettings	_NotGiven_warn_deprecated_param)Languageresolve_language)match_endofsentence)time_now_iso8601)traced_gemini_live
traced_stt   )GeminiFileAPI)Client)AsyncSession)AudioTranscriptionConfigAutomaticActivityDetectionBlobContentContextWindowCompressionConfigEndSensitivityFileDataFunctionResponseGenerationConfigGroundingMetadataHttpOptionsLiveConnectConfigLiveServerMessageMediaResolutionModalityPartProactivityConfigRealtimeInputConfigSessionResumptionConfigSlidingWindowSpeechConfigStartSensitivityThinkingConfigVoiceConfigzException: zHIn order to use Google AI, you need to `pip install pipecat-ai[google]`.zMissing module:    g      $@languagereturnc                 T   i t         j                  dt         j                  dt         j                  dt         j                  dt         j
                  dt         j                  dt         j                  dt         j                  dt         j                  dt         j                  dt         j                  dt         j                  dt         j                  dt         j                  d	t         j                  d	t         j                   d
t         j"                  di t         j$                  dt         j&                  dt         j(                  dt         j*                  dt         j,                  dt         j.                  dt         j0                  dt         j2                  dt         j4                  dt         j6                  dt         j8                  dt         j:                  dt         j<                  dt         j>                  dt         j@                  dt         jB                  dt         jD                  di t         jF                  dt         jH                  dt         jJ                  dt         jL                  dt         jN                  dt         jP                  dt         jR                  dt         jT                  dt         jV                  dt         jX                  dt         jZ                  dt         j\                  dt         j^                  dt         j`                  dt         jb                  dt         jd                  dt         jf                  dt         jh                  dt         jj                  dt         jl                  di}to        | |d       S )!a7  Maps a Language enum value to a Gemini Live supported language code.

    Source:
    https://ai.google.dev/api/generate-content#MediaResolution

    Args:
        language: The language enum value to convert.

    Returns:
        The Gemini language code string, or None if the language is not supported.
    zar-XAzbn-INzcmn-CNzde-DEen-USzen-AUzen-GBzen-INzes-ESzes-USzfr-FRzfr-CAzgu-INzhi-INzid-IDzit-ITzja-JPzkn-INzko-KRzml-INzmr-INznl-NLzpl-PLzpt-BRzru-RUzta-INzte-INzth-THztr-TRzvi-VNF)use_base_code)8rA   ARBN_INCMNCMN_CNZHZH_CNDEDE_DEENEN_USEN_AUEN_GBEN_INESES_ESES_USFRFR_FRFR_CAGUGU_INHIHI_INIDID_IDITIT_ITJAJA_JPKNKN_INKOKO_KRMLML_INMRMR_INNLNL_NLPLPL_PLPT_BRRURU_RUTATA_INTETE_INTHTH_THTRTR_TRVIVI_VNrB   )rd   LANGUAGE_MAPs     Y/opt/pipecat/venv/lib/python3.12/site-packages/pipecat/services/google/gemini_live/llm.pylanguage_to_gemini_languager      s   PWP 		P 	hP 	P 	XP 	P 	WP 	P 	WP 	P  	!P" 	#P$ 	%P( 	W)P* 	+P, 	-P0 	W1P2 	3P4 	5P8 	W9P: 	;P> 	W?P@ 	APD 	WEPF 	GPJ 	WKPL 	MPP 	WQPR 	SPV 	WWPX 	YP\ 	W]P^ 	_Pb 	WcPd 	ePh 	WiPj 	kPn 	WoPp 	qPt 	WuPv 	wPz 	{P~ 	WP@ 	APD 	WEPF 	GPJ 	WKPL 	MPP 	WQPR 	SPV 	WWPX 	W_PLd Hl%HH    c                   d    e Zd ZdZededd fd       Zd Zd Zdde	d	e	d
e
e	   fdZdee   fdZy)GeminiLiveContextaC  Extended OpenAI context for Gemini Live API.

    Provides Gemini-specific context management including system instruction
    extraction and message format conversion for the Live API.

    .. deprecated:: 0.0.92
        Gemini Live no longer uses `GeminiLiveContext` under the hood.
        It now uses `LLMContext`.
    objre   c                 `   t        j                         5  t        j                  d       t        j                  dt        d       ddd       t        | t              rCt        | t              s3t        j                  d|         t        | _
        | j                          | S # 1 sw Y   ^xY w)zUpgrade an OpenAI context to Gemini context.

        Args:
            obj: The OpenAI context to upgrade.

        Returns:
            The upgraded Gemini context instance.
        alwayszuGeminiLiveContext is deprecated. Gemini Live no longer uses GeminiLiveContext under the hood. It now uses LLMContext.   
stacklevelNz"Upgrading to Gemini Live Context: )warningscatch_warningssimplefilterwarnDeprecationWarning
isinstancer2   r   r   debug	__class__!_restructure_from_openai_messages)r   s    r   upgradezGeminiLiveContext.upgrade   s      $$& 	!!(+MM* #	 c+,ZEV5WLL=cUCD-CM113
	 	s   2B$$B-c                      y N selfs    r   r   z3GeminiLiveContext._restructure_from_openai_messages  s    r   c                     d}| j                   D ]R  }|j                  d      dk(  s|j                  dd      }|s-|r|j                  d      s|dz  }|t        |      z  }T |S )zExtract system instructions from context messages.

        Returns:
            Combined system instruction text from all system messages.
         rolesystemcontent
)messagesgetendswithstr)r   system_instructionitemr   s       r   extract_system_instructionsz-GeminiLiveContext.extract_system_instructions  st      MM 	7Dxx8+((9b1)2D2M2Md2S*d2*&#g,6&	7 "!r   Nfile_uri	mime_typetextc                     g }|r|j                  d|d       |j                  d||dd       d|d}| j                  j                  |       t        j                  d|        y	)
a>  Add a file reference to the context.

        This adds a user message with a file reference that will be sent during context initialization.

        Args:
            file_uri: URI of the uploaded file
            mime_type: MIME type of the file
            text: Optional text prompt to accompany the file
        r   )typer   	file_datar   r   )r   r   userr   r   z!Added file reference to context: N)appendr   r   info)r   r   r   r   partsmessages         r   add_file_referencez$GeminiLiveContext.add_file_reference  sk     LL&$78 	 YT\/]^	

 "e4W%7zBCr   c                    g }| j                   D ]y  }|j                  d      }|dk(  r|dk(  rd}|j                  d      }g }t        |t              rt	        |      g}n
t        |t
              r|D ]  }|j                  d      dk(  r+|j                  t	        |j                  d                   B|j                  d      d	k(  rW|j                  d	i       }|j                  t	        t        |j                  d
      |j                  d                         t        j                  dt        |      dd          n$t        j                  dt        |      dd         |j                  t        ||             | |S )zGet messages formatted for Gemini history initialization.

        Returns:
            List of messages in Gemini format for conversation history.
        r   r   	assistantmodelr   r   r   r   r   r   r   r   )r   zUnsupported content type: NP   )r   r   )r   r   r   r   rZ   listr   rQ   r   warningrN   )r   r   r   r   r   r   partr   s           r   %get_messages_for_initializing_historyz7GeminiLiveContext.get_messages_for_initializing_history7  se    #%MM 	=D88F#Dx$hhy)G "E'3'7+,GT*# VDxx'61Ttxx/?%@A&)[8$(HH["$=	 *2.7mmK.H-6]]:-F+" )CCIcrNCS'TUV  !;CL"<M;NOPOOGU;<?	=@ r   r   )__name__
__module____qualname____doc__staticmethodr2   r   r   r   r   r	   r   r   rN   r   r   r   r   r   r      sg     % *=  >" D3 D3 Dhsm D2'tG} 'r   r   c                   ,     e Zd ZdZ fdZ fdZ xZS )GeminiLiveUserContextAggregatora\  User context aggregator for Gemini Live.

    Extends OpenAI user aggregator to handle Gemini-specific message passing
    while maintaining compatibility with the standard aggregation pipeline.

    .. deprecated:: 0.0.92
        Gemini Live no longer expects a `GeminiLiveUserContextAggregator`.
        It now expects a `LLMUserAggregator`.
    c                     t        j                         5  t        j                  d       t        j                  dt        d       ddd       t        |   |i | y# 1 sw Y   xY w)z/Initialize Gemini Live user context aggregator.r   zGeminiLiveUserContextAggregator is deprecated. Gemini Live no longer expects a GeminiLiveUserContextAggregator. It now expects a LLMUserAggregator.r   r   Nr   r   r   r   r   super__init__r   argskwargsr   s      r   r   z(GeminiLiveUserContextAggregator.__init__l  a    
 $$& 	!!(+MM6 #	 	$)&)	 	   2A  A)c                    K   t         |   ||       d{    t        |t              r| j	                  ||       d{    yy7 07 w)zProcess incoming frames for user context aggregation.

        Args:
            frame: The frame to process.
            direction: The frame processing direction.
        N)r   process_framer   r   
push_framer   frame	directionr   s      r   r   z-GeminiLiveUserContextAggregator.process_frame|  sM      g#E9555e34//%333 5 	6 4s!   AA)AA
A
A)r   r   r   r   r   r   __classcell__r   s   @r   r   r   a  s    * 
4 
4r   r   c                   B     e Zd ZdZ fdZdedef fdZdefdZ	 xZ
S )$GeminiLiveAssistantContextAggregatora  Assistant context aggregator for Gemini Live.

    Handles assistant response aggregation while filtering out LLMTextFrames
    to prevent duplicate context entries, as Gemini Live pushes both
    LLMTextFrames and TTSTextFrames.

    .. deprecated:: 0.0.92
        Gemini Live no longer uses `GeminiLiveAssistantContextAggregator` under the hood.
        It now uses `LLMAssistantAggregator`.
    c                     t        j                         5  t        j                  d       t        j                  dt        d       ddd       t        |   |i | y# 1 sw Y   xY w)z4Initialize Gemini Live assistant context aggregator.r   zGeminiLiveAssistantContextAggregator is deprecated. Gemini Live no longer uses GeminiLiveAssistantContextAggregator under the hood. It now uses LLMAssistantAggregator.r   r   Nr   r   s      r   r   z-GeminiLiveAssistantContextAggregator.__init__  r   r   r   r   c                 d   K   t        |t              st        |   ||       d{    yy7 w)zProcess incoming frames for assistant context aggregation.

        Args:
            frame: The frame to process.
            direction: The frame processing direction.
        N)r   r    r   r   r   s      r   r   z2GeminiLiveAssistantContextAggregator.process_frame  s0      %.''y999 /9s   $0.0c                    K   yw)zdHandle user image frames.

        Args:
            frame: The user image frame to handle.
        Nr   r   r   s     r   handle_user_image_framez<GeminiLiveAssistantContextAggregator.handle_user_image_frame  s      	   )r   r   r   r   r   r   r4   r   r*   r   r   r   s   @r   r   r     s-    	* : :> :3D r   r   c                   D    e Zd ZU dZeed<   eed<   d ZdefdZdefdZ	y)	GeminiLiveContextAggregatorPairaN  Pair of user and assistant context aggregators for Gemini Live.

    .. deprecated:: 0.0.92
        `GeminiLiveContextAggregatorPair` is deprecated.
        Use `LLMContextAggregatorPair` instead.

    Parameters:
        _user: The user context aggregator instance.
        _assistant: The assistant context aggregator instance.
    _user
_assistantc                     t        j                         5  t        j                  d       t        j                  dt        d       d d d        y # 1 sw Y   y xY w)Nr   zTGeminiLiveContextAggregatorPair is deprecated. Use LLMContextAggregatorPair instead.r   r   )r   r   r   r   r   r   s    r   __post_init__z-GeminiLiveContextAggregatorPair.__post_init__  sJ     $$& 	!!(+MM8"		 	 	s   2AAre   c                     | j                   S )zmGet the user context aggregator.

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

        Returns:
            The assistant context aggregator instance.
        )r  r   s    r   r   z)GeminiLiveContextAggregatorPair.assistant  s     r   N)
r   r   r   r   r   __annotations__r   r  r   r   r   r   r   r   r     s4    	 +*445 ? r   r   c                       e Zd ZdZdZdZy)GeminiModalitieszySupported modalities for Gemini Live.

    Parameters:
        TEXT: Text responses.
        AUDIO: Audio responses.
    TEXTAUDION)r   r   r   r   r	  r
  r   r   r   r  r    s     DEr   r  c                        e Zd ZdZdZdZdZdZy)GeminiMediaResolutiona  Media resolution options for Gemini Live.

    Parameters:
        UNSPECIFIED: Use default resolution setting.
        LOW: Low resolution with 64 tokens.
        MEDIUM: Medium resolution with 256 tokens.
        HIGH: High resolution with zoomed reframing and 256 tokens.
    MEDIA_RESOLUTION_UNSPECIFIEDMEDIA_RESOLUTION_LOWMEDIA_RESOLUTION_MEDIUMMEDIA_RESOLUTION_HIGHN)r   r   r   r   UNSPECIFIEDLOWMEDIUMHIGHr   r   r   r  r    s     1K
 C&F"Dr   r  c                       e Zd ZU dZ ed      Zee   ed<    ed      Z	ee
   ed<    ed      Zee   ed<    ed      Zee   ed<    ed      Zee   ed<   y)	GeminiVADParamsa  Voice Activity Detection parameters for Gemini Live.

    Parameters:
        disabled: Whether to disable VAD. Defaults to None.
        start_sensitivity: Sensitivity for speech start detection. Defaults to None.
        end_sensitivity: Sensitivity for speech end detection. Defaults to None.
        prefix_padding_ms: Prefix padding in milliseconds. Defaults to None.
        silence_duration_ms: Silence duration threshold in milliseconds. Defaults to None.
    Ndefaultdisabledstart_sensitivityend_sensitivityprefix_padding_mssilence_duration_ms)r   r   r   r   r   r  r	   boolr  r  r`   r  rP   r  intr  r   r   r   r  r    sn      %T2Hhtn249$4Gx 01G05d0COXn-C',T':x}:).t)<#<r   r  c                   P    e Zd ZU dZ ed      Zeed<    ed      Ze	e
   ed<   y)ContextWindowCompressionParamszParameters for context window compression in Gemini Live.

    Parameters:
        enabled: Whether compression is enabled. Defaults to False.
        trigger_tokens: Token count to trigger compression. None uses 80% of context window.
    Fr  enabledNtrigger_tokens)r   r   r   r   r   r"  r  r  r#  r	   r  r   r   r   r!  r!    s0     %(GT($)%NHSM r   r!  c                   j   e Zd ZU dZ 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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ej                         Zee   ed<    eej&                        Zee   ed<    eej,                        Zee   ed<    ed      Zee   ed<    ed      Zee   ed<    ed      Zee   ed<    ed      Zee   ed<    ed      Z ee!   ed<    ee"      Z#ee$e%e&f      ed<   y)InputParamsa  Input parameters for Gemini Live generation.

    .. deprecated:: 0.0.105
        Use ``GeminiLiveLLMSettings`` instead.

    Parameters:
        frequency_penalty: Frequency penalty for generation (0.0-2.0). Defaults to None.
        max_tokens: Maximum tokens to generate. Must be >= 1. Defaults to 4096.
        presence_penalty: Presence penalty for generation (0.0-2.0). Defaults to None.
        temperature: Sampling temperature (0.0-2.0). Defaults to None.
        top_k: Top-k sampling parameter. Must be >= 0. Defaults to None.
        top_p: Top-p sampling parameter (0.0-1.0). Defaults to None.
        modalities: Response modalities. Defaults to AUDIO.
        language: Language for generation. Defaults to EN_US.
        media_resolution: Media resolution setting. Defaults to UNSPECIFIED.
        vad: Voice activity detection parameters. Defaults to None.
        context_window_compression: Context compression settings. Defaults to None.
        thinking: Thinking settings. Defaults to None.
            Note that these settings may require specifying a model that
            supports them, e.g. "gemini-2.5-flash-native-audio-preview-12-2025".
        enable_affective_dialog: Enable affective dialog, which allows Gemini
            to adapt to expression and tone. Defaults to None.
            Note that these settings may require specifying a model that
            supports them, e.g. "gemini-2.5-flash-native-audio-preview-12-2025".
            Also note that this setting may require specifying an API version that
            supports it, e.g. HttpOptions(api_version="v1alpha").
        proactivity: Proactivity settings, which allows Gemini to proactively
            decide how to behave, such as whether to avoid responding to
            content that is not relevant. Defaults to None.
            Note that these settings may require specifying a model that
            supports them, e.g. "gemini-2.5-flash-native-audio-preview-12-2025".
            Also note that this setting may require specifying an API version that
            supports it, e.g. HttpOptions(api_version="v1alpha").
        extra: Additional parameters. Defaults to empty dict.
    Ng        g       @)r  gelefrequency_penalty   rG   )r  r&  
max_tokenspresence_penaltytemperaturer   top_k      ?top_pr  
modalitiesrd   media_resolutionvadcontext_window_compressionthinkingenable_affective_dialogproactivitydefault_factoryextra)'r   r   r   r   r   r(  r	   floatr  r*  r  r+  r,  r-  r/  r  r
  r0  rA   rr   rd   r  r  r1  r2  r  r3  r!  r4  ra   r5  r  r6  r[   dictr9  r   r   r   r   r   r   r%  r%  (  sm   "H */t)LxL %dq 9J9(-dss(KhuoK#(###FK%F !4E8C=4"4CC@E8E?@-2;K;Q;Q-RJ)*R#(#@Hhx @8=%119h45  &+4%8C/	"8KPY]K^)G H^).t)<Hh~&<.3D.AXd^A/4T/BK+,B&+D&AE8DcN#Ar   r%  c                   n   e Zd ZU dZ ed       Zeez  ed<    ed       Z	e
ez  ed<    ed       Zeez  ez  ed<    ed	       Zeez  ed
<    ed       Zeez  ed<    ed       Zeez  ez  ed<    ed       Zeez  ez  ed<    ed       Zeez  ed<    ed       Zeez  ez  ed<   y)GeminiLiveLLMSettingsa  Settings for GeminiLiveLLMService.

    Parameters:
        voice: TTS voice identifier (e.g. ``"Charon"``).
        modalities: Response modalities.
        language: Language for generation.
        media_resolution: Media resolution setting.
        vad: Voice activity detection parameters.
        context_window_compression: Context window compression configuration.
        thinking: Thinking configuration.
        enable_affective_dialog: Whether to enable affective dialog.
        proactivity: Proactivity configuration.
    c                      t         S r   r=   r   r   r   <lambda>zGeminiLiveLLMSettings.<lambda>p  s    9 r   r7  voicec                      t         S r   r?  r   r   r   r@  zGeminiLiveLLMSettings.<lambda>q  s    Y r   r0  c                      t         S r   r?  r   r   r   r@  zGeminiLiveLLMSettings.<lambda>r  s     r   rd   c                      t         S r   r?  r   r   r   r@  zGeminiLiveLLMSettings.<lambda>s  s    Xa r   r1  c                      t         S r   r?  r   r   r   r@  zGeminiLiveLLMSettings.<lambda>t  s    Y r   r2  c                      t         S r   r?  r   r   r   r@  zGeminiLiveLLMSettings.<lambda>v  s    	 r   r3  c                      t         S r   r?  r   r   r   r@  zGeminiLiveLLMSettings.<lambda>x  s    PY r   r4  c                      t         S r   r?  r   r   r   r@  zGeminiLiveLLMSettings.<lambda>y  s    i r   r5  c                      t         S r   r?  r   r   r   r@  zGeminiLiveLLMSettings.<lambda>z  s    V_ r   r6  N)r   r   r   r   r   rA  r   r?   r  r0  r  rd   rA   r1  r  r2  r  r3  r!  r;  r4  ra   r5  r  r6  r[   r   r   r   r=  r=  `  s     #3DEE3?E/4EV/WJ 9,W+0AR+SHhny(S:?Pa:b+i7b',=N'OC9	$OTY)U > E	 Q  38HY2ZHnt#i/Z05FW0XTI-X8=N_8`K"T)I5`r   r=  c                       e Zd ZU dZeZeed<   eZdddddddddddddd	e	d
e
e	   de
e	   de	dedede
e	   de
eee   ef      de
e   de
e   dede	de
e   f fdZd Zedefd       ZdefdZdedee	ef   f fdZdefdZdefdZd efd!Zd"efd#Z d$e!fd%Z"d&e#f fd'Z$d&e%f fd(Z&d&e'f fd)Z(d* Z)d+ Z*d, Z+d&e,d-e-f fd.Z.d$e/fd/Z0d0efd1Z1d2efd3Z2dgd4e
e	   fd5Z3d6e4fd7Z5d8 Z6d9e7defd:Z8d; Z9d< Z:d= Z;d>e	fd?Z<d@ Z=dA Z>dB Z? e@dCD      dEe	dFe	dGeAe	ef   fdH       ZB e@dID      dJeCfdK       ZDdLeEfdMZF e@dND      dOeEfdP       ZG e@dQD      dOeEfdR       ZHeI	 dgdSe	dTed"e
e   fdU       ZJdgd>e	dVe
eE   fdWZKdX ZLdOeEfdYZMdOeEfdZZNd>e	fd[ZOdOeEfd\ZP	 dhd]eQd^e	fd_ZRdOeEfd`ZSdOeEfdaZTd9e7fdbZU eV        eW       dcd$e!ddeVdeeWdeXfdfZY xZZS )iGeminiLiveLLMServicezProvides access to Google's Gemini Live API.

    This service enables real-time conversations with Gemini, supporting both
    text and audio modalities. It handles voice transcription, streaming audio
    responses, and tool usage.
    	_settingsNCharonFTz6https://generativelanguage.googleapis.com/v1beta/files)base_urlr   voice_idstart_audio_pausedstart_video_pausedr   toolsparamssettings#inference_on_context_initializationfile_api_base_urlhttp_optionsapi_keyrN  r   rO  rP  rQ  r   rR  rS  rT  rU  rV  rW  c                4   |Iddl } |j                         5   |j                  d        |j                  dt        d       ddd       t        d&i ddd	|d
ddddddddddddddddddddt        j                  dddt        j                  dddi di dddi d i }|t        dt
        d       ||_        |dk7  rt        d!t
        d
       ||_        |	kt        d"t
               |
sX|	j                  |_        |	j                  |_        |	j                  |_        |	j                   |_        |	j"                  |_        |	j$                  |_        |	j&                  |_        |	j(                  rt+        |	j(                        nd|_        |	j,                  |_        |	j.                  |_        |	j0                  r|	j0                  j3                         ni |_        |	j4                  xs i |_        |	j6                  xs d|_        |	j8                  xs i |_        t;        |	j<                  t>              r|	j<                  |_        |
|jA                  |
       tC        |   d&||d#| d| _#        || _$        || _%        || _&        || _'        d| _(        || _)        || _*        d| _+        || _,        t[        |      | _.        d| _/        d| _0        d| _1        d| _2        d| _3        d| _4        tk               | _6        d$| _7        d$| _8        tk               | _9        d$| _:        d$| _;        d| _<        d%| _=        | j|                  j(                  | _?        | j|                  j(                  rt+        | j|                  j(                        nd| _@        | j|                  j.                  | _A        d| _B        d| _C        || _D        d| _E        d$| _F        d| _G        d| _H        d| _I        | j                          t               | _L        y# 1 sw Y   xY w)'a6  Initialize the Gemini Live LLM service.

        Args:
            api_key: Google AI API key for authentication.
            base_url: API endpoint base URL. Defaults to the official Gemini Live endpoint.

                .. deprecated:: 0.0.90
                    This parameter is deprecated and no longer has any effect.
                    Please use `http_options` to customize requests made by the
                    API client.

            model: Model identifier to use.

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

            voice_id: TTS voice identifier. Defaults to "Charon".

                .. deprecated:: 0.0.105
                    Use ``settings=GeminiLiveLLMSettings(voice=...)`` instead.
            start_audio_paused: Whether to start with audio input paused. Defaults to False.
            start_video_paused: Whether to start with video input paused. Defaults to False.
            system_instruction: System prompt for the model. Defaults to None.
            tools: Tools/functions available to the model. Defaults to None.
            params: Configuration parameters for the model.

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

            settings: Gemini Live LLM settings. If provided together with deprecated
                top-level parameters, the ``settings`` values take precedence.
            inference_on_context_initialization: Whether to generate a response when context
                is first set. Defaults to True.
            file_api_base_url: Base URL for the Gemini File API. Defaults to the official endpoint.
            http_options: HTTP options for the client.
            **kwargs: Additional arguments passed to parent LLMService.
        Nr   r   zParameter 'base_url' is deprecated and no longer has any effect. Please use 'http_options' to customize requests made by the API client.r   r   r   z4models/gemini-2.5-flash-native-audio-preview-12-2025r   rA  rM  r(  r*  r)  r+  r,  r-  r/  seedfilter_incomplete_user_turnsFuser_turn_completion_configr0  rd   rg   r1  r2  r3  r4  r5  r6  r9  rO  rS  )rN  rT  r   i]  r   )Mr   r   r   r   r   r=  r  r
  r  r  r@   r   rA  r(  r*  r+  r,  r-  r/  r0  rd   r   r1  r2  r3  
model_dumpr4  r5  r6  r   r9  r;  apply_updater   r   _last_sent_time	_base_url_system_instruction_from_init_tools_from_init$_inference_on_context_initialization_needs_turn_complete_message_audio_input_paused_video_input_paused_context_api_keyr8   _http_options_session_connection_task_disconnecting_run_llm_when_session_ready_user_is_speaking_bot_is_responding	bytearray_user_audio_buffer_user_transcription_buffer_last_transcription_sent_bot_audio_buffer_bot_text_buffer_llm_output_buffer_transcription_timeout_task_sample_raterL  	_language_language_code_vad_params_consecutive_failures_connection_start_time_file_api_base_url	_file_api_search_result_buffer_accumulated_grounding_metadata_session_resumption_handle$_end_frame_pending_bot_turn_finishedcreate_clientset_completed_tool_calls)r   rX  rN  r   rO  rP  rQ  r   rR  rS  rT  rU  rV  rW  r   r   default_settingsr   s                    r   r   zGeminiLiveLLMService.__init__  sv   p (((* %%%h/ _&  1 
H
1
 
 #	

 
 "
 
 
 
 
 */
 )-
 (--
 
 3>>
  !
" (*#
$ %
& %*'
( )
* +
2 "7,A7K%*"x":/DgN%-" "8-BC5;5M5M 2.4.?.? +4:4K4K 1/5/A/A ,)/ &)/ &.4.?.? +DJOO/@Y` !) 5;4K4K 1'-zz $ 88 55@@B !;
 -3OO,Ar );A;Y;Y;b]b 8/5/A/A/GR ,fllD1-3\\$* ))(3 	
%	
 	
  !!-?* %4W1,1)#5 #5 >|L&* $#+0(!&"'"++*,'(*%!* ""$+/(!00 ~~&& ((?(?@ 	
  >>-- &'"&*#"326 &("/3, :>' IM1 	 &)U"U s   ,PPc                 P    t        | j                  | j                        | _        y)zDCreate the Gemini API client instance. Subclasses can override this.)rX  rW  N)rI   rh  ri  _clientr   s    r   r  z"GeminiLiveLLMService.create_clientR  s    dmm$BTBTUr   re   c                 ~    | j                   s&t        | j                  | j                        | _         | j                   S )zGet the Gemini File API client instance. Subclasses can override this.

        Returns:
            The Gemini File API client.
        )rX  rN  )r  rH   rh  r~  r   s    r   file_apizGeminiLiveLLMService.file_apiV  s-     ~~*4==4KbKbcDN~~r   c                      y)zCheck if the service can generate usage metrics.

        Returns:
            True as Gemini Live supports token usage metrics.
        Tr   r   s    r   can_generate_metricsz)GeminiLiveLLMService.can_generate_metricsa  s     r   deltac                 l   K   t         |   |       d{   }|s|S | j                  |       |S 7 w)zgApply a settings delta.

        Settings are stored but not applied to the active connection.
        N)r   _update_settings _warn_unhandled_updated_settings)r   r  changedr   s      r   r  z%GeminiLiveLLMService._update_settingsi  s=     
 077N 	--g6 8s   424pausedc                     || _         y)zjSet the audio input pause state.

        Args:
            paused: Whether to pause audio input.
        N)re  r   r  s     r   set_audio_input_pausedz+GeminiLiveLLMService.set_audio_input_paused|       $* r   c                     || _         y)zjSet the video input pause state.

        Args:
            paused: Whether to pause video input.
        N)rf  r  s     r   set_video_input_pausedz+GeminiLiveLLMService.set_video_input_paused  r  r   r0  c                 &    || j                   _        y)zwSet the model response modalities.

        Args:
            modalities: The modalities to use for responses.
        N)rL  r0  )r   r0  s     r   set_model_modalitiesz)GeminiLiveLLMService.set_model_modalities  s     %/!r   rd   c                     || _         t        |      xs d| _        | j                  | j                  _        t        j                  d| j                          y)zrSet the language for generation.

        Args:
            language: The language to use for generation.
        rg   zSet Gemini language to: N)ry  r   rz  rL  rd   r   r   )r   rd   s     r   set_languagez!GeminiLiveLLMService.set_language  sJ     "9(CNw"&"5"5.t/B/B.CDEr   contextc                    K   | j                   rt        j                  d       yt        j	                  |      | _         | j                          d{    y7 w)a>  Set the context explicitly from outside the pipeline.

        This is useful when initializing a conversation because in server-side VAD mode we might not have a
        way to trigger the pipeline. This sends the history to the server. The `inference_on_context_initialization`
        flag controls whether to set the turnComplete flag when we do this. Without that flag, the model will
        not respond. This is often what we want when setting the context at the beginning of a conversation.

        Args:
            context: The OpenAI LLM context to set.
        z>Context already set. Can only set up Gemini Live context once.N)rg  r   errorr   r   _create_initial_response)r   r  s     r   set_contextz GeminiLiveLLMService.set_context  sC      ==LLYZ)11':++---s   AAAAr   c                 t   K   t         |   |       d{    | j                          d{    y7 7 w)zgStart the service and establish connection.

        Args:
            frame: The start frame.
        N)r   start_connectr   r   r   s     r   r  zGeminiLiveLLMService.start  s3      gmE"""mmo 	#   848688c                 t   K   t         |   |       d{    | j                          d{    y7 7 w)zaStop the service and close connections.

        Args:
            frame: The end frame.
        N)r   stop_disconnectr  s     r   r  zGeminiLiveLLMService.stop  s6      gl5!!!    	" r  c                 t   K   t         |   |       d{    | j                          d{    y7 7 w)zfCancel the service and close connections.

        Args:
            frame: The cancel frame.
        N)r   cancelr  r  s     r   r  zGeminiLiveLLMService.cancel  s6      gnU###    	$ r  c                    K   | j                   rc| j                  d       d {    | j                  j                  t        j
                  k(  r"| j                  t                      d {    y y y 7 O7 	w)NF)ro  _set_bot_is_respondingrL  r0  r  r
  r   r(   r   s    r   _handle_interruptionz)GeminiLiveLLMService._handle_interruption  sc     ""--e444~~((,<,B,BBooo&7888 C #48s"   !A7A3AA7+A5,A75A7c                    K   d| _         y w)NT)rn  r   s     r   _handle_user_started_speakingz2GeminiLiveLLMService._handle_user_started_speaking  s     !%s   	c                    K   d| _         t               | _        | j                          d {    | j                  r,d| _        | j
                  j                  d       d {    y y 7 =7 w)NFT)turn_complete)rn  rp  rq  start_ttfb_metricsrd  rj  send_client_contentr   s     r   _handle_user_stopped_speakingz2GeminiLiveLLMService._handle_user_stopped_speaking  si     !&"++%%''',,05D- --33$3GGG	 - 	(
 Hs!   *A.A*6A.#A,$A.,A.r   c                   K   t        |t              r)| j                  rt        j                  d       || _        yt        |   ||       d{    t        |t              r| j                  ||       d{    yt        |t        t        f      rUt        |t              r|j                  nt        j                  |j                        }| j                  |       d{    yt        |t               r>| j#                  |j$                         d{    | j                  ||       d{    yt        |t&              r4| j)                  |       d{    | j                  ||       d{    yt        |t*              r4| j-                  |       d{    | j                  ||       d{    yt        |t.              r3| j1                          d{    | j                  ||       d{    yt        |t2              r4| j5                  |       d{    | j                  ||       d{    yt        |t6              r4| j9                  |       d{    | j                  ||       d{    yt        |t:              r| j                  ||       d{    yt        |t<              r| j                  ||       d{    yt        |t>              r$| jA                  |jB                         d{    yt        |tD              ry| j                  ||       d{    y7 7 7 c7 27 7 7 7 7 7 y7 b7 ;7 $7 7 7 7 7 `7 6w)zProcess incoming frames for the Gemini Live service.

        Args:
            frame: The frame to process.
            direction: The frame processing direction.
        z6Deferring handling EndFrame until bot turn is finishedN)#r   r   ro  r   r   r  r   r   r%   r   r   r3   r  r.   from_openai_context_handle_contextr   _send_user_textr   r   _send_user_audior   _send_user_videor   r  r+   r  r,   r  r   r   r   _create_single_responser   r   )r   r   r   r  r   s       r   r   z"GeminiLiveLLMService.process_frame  s     eX&&&UV<A9g#E9555e/0//%3331FGH e_5 33EMMB 
 &&w///01&&uzz222//%33312''...//%33312''...//%33301++---//%3337844U;;;//%3337844U;;;//%33367//%33367//%33356 ..u~~>>>/0//%333] 	6 4 023.3.3-3;3;3 4 4 ?
 4sW  AM5M)M5:M;A*M5%M&3M5MM53M4)M5MM57M8)M5!M"M5;M<(M5$M%M5>M ?)M5(M#)M5M&)M5,M)-M5M+*M51M-2*M5M/3M5M1+M5<M3=M5M5M5M5M5M5M5M5M5M5 M5#M5&M5)M5+M5-M5/M51M53M5c                   K   | j                   sC|| _         | j                         }|j                  | j                         }|d   }|d   }|r!| j                  rt	        j
                  d       |r!| j                  rt	        j
                  d       |s|r| j                          d {    | j                  d       d {    |d   }|sk| j                  r_| j                  r>t	        j                  d       | j                   j                  d	| j                  d
       nt	        j
                  d       | j                          d {    y || _         | j                  d       d {    y 7 7 7 +7 w)Nr   rR  z[System instruction provided both at init time and in context; using context-provided value.zNTools provided both at init time and in context; using context-provided value.F)send_new_resultsr   z^No messages found in initial context; seeding with system instruction to trigger bot response.r   r   zqNo messages found in initial context; cannot trigger initial bot response without messages or system instruction.T)rg  get_llm_adapterget_llm_invocation_paramsra  r   r   rb  
_reconnect!_process_completed_function_callsrc  r   add_messager  )r   r  adapterrS  r   rR  r   s          r   r  z$GeminiLiveLLMService._handle_context-  sh    }}#DM )-(<(<(>G66t}}EF!'(<!=7OE!d&H&Hq ..d "Uoo''' 88%8PPP j)H I I55LLx MM--!)d6X6XY NN L //111 $DM 88$8OOOQ ( Q* 2 PsI   B'E=)E5*E=E7B	E=E9!E=/E;0E=7E=9E=;E=r  c                 Z  K   | j                         }|j                  | j                        j                  dg       }|D ]  }|j                  s|j                  D ]  }|j
                  s|j
                  j                  }|j
                  j                  }|j
                  j                  }|sU|| j                  vsd|sg|j                  d      dk7  s||r/| j                  |||j
                  j                         d {    | j                  j                  |         y 7 $w)Nr   valueIN_PROGRESS)r  r  rg  r   r   function_responseidnameresponser  _tool_resultadd)	r   r  r  r   r   r   tool_call_id	tool_namer  s	            r   r  z6GeminiLiveLLMService._process_completed_function_callsr  s    $($8$8$:44T]]CGG
TVW 	IG}}#MM ID--'+'='='@'@$($:$:$?$?	#'#9#9#B#B( ,D4N4N N ( (W 5 F  0&*&7&7$0)T=S=S=\=\'" !" !" !66::<H!I	I!"s7   AD+D+,AD+1D+ D+D+,D+D)%D+
respondingc                    K   | j                   |k(  ry || _         | j                   s8| j                  r+| j                  | j                         d {    d | _        y y y 7 wr   )ro  r  queue_frame)r   r  s     r   r  z+GeminiLiveLLMService._set_bot_is_responding  s^     ""j0",&&4+T+T""4#L#LMMM8<D5 ,U&Ms   AA!AA!session_resumption_handlec                   K   | j                   ry|rt        j                  d|        nt        j                  d       	 t        t	        | j
                  j                  | j
                  j                  | j
                  j                  | j
                  j                  | j
                  j                  | j
                  j                  t        | j
                  j                  j                        gt        t!        d| j
                  j"                  i      | j
                  j$                        t'        | j
                  j(                  j                        	      t+               t+               t-        |      	      }| j
                  j.                  xs i }|j1                  d
d      r:t3               }t5               |_        |j1                  d      }|||_        ||_        | j
                  j:                  r| j
                  j:                  |_        | j
                  j>                  r| j
                  j>                  |_        | j
                  j@                  r| j
                  j@                  |_         | j
                  jB                  rtE               }| j
                  jB                  }d}|jF                  |jF                  |_#        d}|jH                  r|jH                  |_%        d}|jL                  r|jL                  |_'        d}|jP                  |jP                  |_(        d}|jR                  |jR                  |_)        d}|rtU        |      |_+        | jY                         }	d}
d}| jZ                  r%|	j]                  | jZ                        }|d   }
|d   }|
s| j^                  }
|s|	ja                  | jb                        }|
rt        jd                  d|
        |
|_3        |rt        jd                  d|        ||_4        | jk                  | jm                  |            | _7        y# tp        $ r)}| js                  d| |       d{  7   Y d}~yd}~ww xY ww)z/Establish client connection to Gemini Live API.Nz=Connecting to Gemini service with session_resumption_handle: zConnecting to Gemini service
voice_name)prebuilt_voice_config)voice_configlanguage_code)	r(  max_output_tokensr+  r,  r-  r/  response_modalitiesspeech_configr1  )handle)generation_configinput_audio_transcriptionoutput_audio_transcriptionsession_resumptionr"  Fr#  T)automatic_activity_detectionr   rR  zSetting system instruction: zSetting tools: )configzInitialization error: 	error_msg	exception):rj  r   r   rV   rS   rL  r(  r*  r+  r,  r-  r/  rY   r0  r  r_   rb   rA  rd   rX   r1  rK   r]   r3  r   rO   r^   sliding_windowr#  r4  thinking_configr5  r6  r2  rL   r  r  start_of_speech_sensitivityr  end_of_speech_sensitivityr  r  r\   realtime_input_configr  rg  r  ra  from_standard_toolsrb  r   r   rR  create_task_connection_task_handlerrk  	Exception
push_error)r   r  r  cwccompression_configr#  
vad_config
vad_paramshas_vad_settingsr  r   rR  rS  es                 r   r  zGeminiLiveLLMService._connect  s    == $KKOPiOjk KK67m	W&"2&*nn&F&F&*nn&?&?%)^^%D%D $ : :........)1$..2K2K2Q2Q)R(S".%03?AUAU2V& '+nn&=&=	# &5T^^5T5T5Z5Z%[#  +C*D+C+E#:B[#\'F. ..;;ArCwwy%(%C%E" 5BO"1 "%)9!:!-8F&54F1 ~~&&)-)@)@& ~~55151W1W. ~~))%)^^%?%?" ~~!!79
!^^//
#(  &&2*4*=*=J''+$//=G=Y=YJ:'+$--;E;U;UJ8'+$//;3=3O3OJ0'+$11=5?5S5SJ2'+$ $3F5?4F0 )-(<(<(>G!%E}} ::4==I%+,@%A"w%%)%G%G"33D4I4IJ!;<N;OPQ,>)ug67$ %)$4$4T5R5RZ`5R5a$bD! 	W//.DQC,HTU/VVV	Ws<   >Q/O8P: 9Q/:	Q,Q'QQ'"Q/'Q,,Q/r  c                   K   | j                   j                  j                  j                  | j                  j
                  |      4 d {   }t        j                  d       t        j                         | _	        | j                  |       d {    	 	 | j                  j                         }|2 3 d {   }| j                          |j                  rD|j                  j                  r.t        j                   d       | j#                          d {    i|j                  r0|j                  j$                  r| j'                  |       d {    |j                  rV|j                  j(                  r@|j*                  r4| j-                  |       d {    | j/                  |       d {    |j                  r1|j                  j0                  r| j3                  |       d {    D|j                  r1|j                  j4                  r| j7                  |       d {    |j                  r1|j                  j8                  r| j;                  |       d {    |j<                  r| j?                  |       d {    |j@                  s| jC                  |       7 p7 ,7 7 7 s7 .7 7 7 7 g7 B6 nm# tD        $ ra}| jF                  sK| jI                  |       d {  7  }|r/| jK                          d {  7   Y d }~d d d       d {  7   y Y d }~n
d }~ww xY wd d d       d {  7   y # 1 d {  7  sw Y   y xY ww)N)r   r  zConnected to Gemini servicez'Gemini VAD: interrupted signal received)&r  aioliveconnectrL  r   r   r   timer}  _handle_session_readyrj  receive _check_and_reset_failure_counterserver_contentinterruptedr   broadcast_interruption
model_turn_handle_msg_model_turnr  usage_metadata_handle_msg_turn_complete_handle_msg_usage_metadatainput_transcription_handle_msg_input_transcriptionoutput_transcription _handle_msg_output_transcriptiongrounding_metadata_handle_msg_grounding_metadata	tool_call_handle_msg_tool_callsession_resumption_update_handle_msg_resumption_updater  rl  _handle_connection_errorr  )r   r  sessionturnr   r  should_reconnects          r   r  z-GeminiLiveLLMService._connection_task_handler  s    <<##((00..&&v 1 
 7	 7	KK56 +/))+D',,W555,==002D)- #H #Hg==?"11g6L6L6X6X #LL)RS"&"="="???$338N8N8Y8Y"&"="=g"FFF#22 ' 6 6 D D ' 6 6"&"@"@"III"&"A"A'"JJJ$338N8N8b8b"&"F"Fw"OOO$338N8N8c8c"&"G"G"PPP$338N8N8a8a"&"E"Eg"NNN$.."&"<"<W"EEE$>> >>wGa7	 6
#H  @F JJOPNEC *.H ! ..151N1Nq1Q+Q+Q(+"&//"333"m7	 7	 7	n O 7	 7	 7	 7	 7	sq  A
M1J<M1AMJ?MK6K:K;K>AKK;KKAKKK6K7<K3K4<K0K1<K-K.&KKK)K<M1?MKKKKKKKKKKM	M$ M LM L" M %M)M14L75M1;M MM
M1MM1M."M%#M.*M1c                     | j                   rk| j                  dkD  r[t        j                         | j                   z
  t        k\  r2t	        j
                  dt         d| j                   d       d| _        yyyy)zCheck if connection has been stable long enough to reset the failure counter.

        If the connection has been active for longer than the established threshold
        and there are accumulated failures, reset the counter to 0.
        r   zConnection stable for z"s, resetting failure counter from z to 0N)r}  r|  r   CONNECTION_ESTABLISHED_THRESHOLDr   r   r   s    r   r  z5GeminiLiveLLMService._check_and_reset_failure_counterJ  s~     ''**Q.		d999=]]KK()I(J K2262L2L1MUT *+D& ^ / (r   r  c                 X  K   | xj                   dz  c_         t        j                  d| j                    dt         d|        | j                   t        k\  r&dt         d}| j	                  ||       d{    y	t        j
                  d
| j                    dt         d       y7 0w)a  Handle a connection error and determine if reconnection should be attempted.

        Args:
            error: The exception that caused the connection error.

        Returns:
            True if reconnection should be attempted, False if a fatal error should be pushed.
        rG   zConnection error (failure /z): zMax consecutive failures (z") reached, treating as fatal errorr  NFzAttempting reconnection ()T)r|  r   r   MAX_CONSECUTIVE_FAILURESr  r   )r   r  r  s      r   r  z-GeminiLiveLLMService._handle_connection_error[  s      	""a'"()C)C(DAF^E__bchbij	
 %%)AA,-E,F G* *  //I/GGGKK+D,F,F+GqIaHbbcd  Hs   A5B*7B(81B*c                    K   | j                          d{    | j                  | j                         d{    y7 )7 w)zReconnect to Gemini Live API.N)r  )r  r  r  r   s    r   r  zGeminiLiveLLMService._reconnectv  s;        mmd6U6UmVVV 	!Vs   AA #AAAAc                 b  K   t        j                  d       	 d| _        | j                          d{    | j                  r,| j                  | j                  d       d{    d| _        | j                  r*| j                  | j                         d{    d| _        | j                  r)| j                  j                          d{    d| _        t               | _
        d| _        y7 7 7 [7 (# t        $ r)}| j                  d| |       d{  7   Y d}~yd}~ww xY ww)	z7Disconnect from Gemini Live API and clean up resources.z!Disconnecting from Gemini serviceTNr.  )timeoutFzError disconnecting: r  )r   r   rl  stop_all_metricsrk  cancel_taskrw  rj  closer  r  r  r  )r   r  s     r   r  z GeminiLiveLLMService._disconnect{  s    78	V"&D'')))$$&&t'<'<c&JJJ(,%//&&t'G'GHHH370}}mm))+++ $),D&"'D *J I ,  	V//.CA3,GST/UUU	Vs   D/C: C20C: $C4%5C: C64C: C8!C: 1D/2C: 4C: 6C: 8C: :	D,D'DD'"D/'D,,D/c                 `  K   | j                   s| j                  s| j                  sy	 | j                  j                  t	        |j
                  d|j                                d{    |j
                  }| j                  r| j                  j                  |       y| j                  j                  |       t        |j                  |j                  z  dz  dz        }| j                  | d | _
        y7 # t        $ r$}| j                  |       d{  7   Y d}~d}~ww xY ww)z)Send user audio frame to Gemini Live API.Naudio/pcm;rate=datar   )audior         ?)re  rl  rj  send_realtime_inputrM   r%  sample_rater  _handle_send_errorrn  rq  extendr  num_channels)r   r   r  r%  lengths        r   r  z%GeminiLiveLLMService._send_user_audio  s    ##t':':$--	---33IZIZH[7\] 4    !!##**51 ##**51%++e.@.@@1DKLF&*&=&=vgh&GD#  	-))!,,,	-sN   &D.AC> *C<+C> /BD.<C> >	D+D&DD&!D.&D++D.r   c                    K   | j                   s| j                  sy	 | j                  j                  |       d{    y7 # t        $ r$}| j	                  |       d{  7   Y d}~yd}~ww xY ww)av  Send user text via Gemini Live API's realtime input stream.

        This method sends text through the realtimeInput stream (via TextInputMessage)
        rather than the clientContent stream. This ensures text input is synchronized
        with audio and video inputs, preventing temporal misalignment that can occur
        when different modalities are processed through separate API pathways.

        For realtimeInput, turn completion is automatically inferred by the API based
        on user activity, so no explicit turnComplete signal is needed.

        Args:
            text: The text to send as user input.
        Nr   )rl  rj  r'  r  r)  )r   r   r  s      r   r  z$GeminiLiveLLMService._send_user_text  s]      dmm	---333>>> 	-))!,,,	-sJ   A4A AA A4A 	A1A,!A$"A,'A4,A11A4c                   K   | j                   s| j                  s| j                  syt        j                         }|| j                  z
  dk  ry|| _        t        j                  d|        t        j                         }t        j                  |j                  |j                  |j                        j                  |d       t        j                   |j#                               j%                  d      }	 | j                  j'                  t)        |d      	       d{    y7 # t*        $ r$}| j-                  |       d{  7   Y d}~yd}~ww xY ww)
z)Send user video frame to Gemini Live API.NrG   zSending video frame to Gemini: JPEG)formatzutf-8z
image/jpegr#  )video)rf  rl  rj  r  r_  r   traceioBytesIOr   	frombytesr0  sizeimagesavebase64	b64encodegetvaluedecoder'  rM   r  r)  )r   r   nowbufferr$  r  s         r   r  z%GeminiLiveLLMService._send_user_video  s    ##t':':$--iik%%%)"6ug>?ejj%++>CCFSYCZ 1299'B	---33$DT`:a3bbb 	-))!,,,	-sN   C8E;*D- %D+&D- *E+D- -	E6E
EEEEEc                   K   | j                   ry| j                  sd| _        y| j                         }|j	                  | j
                        j                  dg       }|syt        j                  d|        | j                          d{    	 | j                  j                  || j                         d{    | j                  sd| _        yy7 I7 # t        $ r$}| j                  |       d{  7   Y d}~Ad}~ww xY ww)z1Create initial response based on context history.NTr   zCreating initial response: turnsr  )rl  rj  rm  r  r  rg  r   r   r   r  r  rc  r  r)  rd  )r   r  r   r  s       r   r  z-GeminiLiveLLMService._create_initial_response  s     }}/3D,$($8$8$:44T]]CGG
TVW28*=>%%'''	---33d.W.W 4    8804D- 9 	(  	-))!,,,	-sZ   BDCD*C =C>C DC 	D$D8C;9D>DDDc                   K   | j                   s| j                  syt        |      }| j                         }|j	                  |      j                  dg       }|syt        j                  d|        | j                          d{    	 | j                  j                  |d       d{    y7 +7 # t        $ r$}| j                  |       d{  7   Y d}~yd}~ww xY ww)z1Create a single response from a list of messages.N)r   r   zCreating response: Tr@  )rl  rj  r.   r  r  r   r   r   r  r  r  r)  )r   messages_listr  r  r   r  s         r   r  z,GeminiLiveLLMService._create_single_response  s     dmm m4$($8$8$:44W=AA*bQ*8*56%%'''	---33(RV3WWW 	( X 	-))!,,,	-sZ   BC'B3C' B7 -B5.B7 2C'5B7 7	C$ CCCC'C$$C'llm_tool_result)	operationr  r  tool_result_messagec                   K   | j                   s| j                  syt        |||      }	 | j                  j                  |       d{    y7 # t        $ r$}| j                  |       d{  7   Y d}~yd}~ww xY ww)z!Send tool result back to the API.N)r  r  r  )function_responses)rl  rj  rR   send_tool_responser  r)  )r   r  r  rF  r  r  s         r   r  z!GeminiLiveLLMService._tool_result  sn     
 dmm $|Nab	---22h2OOO 	-))!,,,	-sL   (BA 
AA BA 	A?A:/A20A:5B:A??B	llm_setupr  c                 v   K   || _         | j                  r d| _        | j                          d{    yy7 w)zHandle the session being ready.FN)rj  rm  r  )r   r  s     r   r  z*GeminiLiveLLMService._handle_session_ready  s<        ++/4D,//111 ,1s   .979msgc                 0  K   |j                   j                  j                  d   }|sy| j                          d{    |j                  }|r| j
                  s:| j                  d       d{    | j                  t                      d{    |j                  re| j                  t                      d{    | j                  t        |             d{    | j                  t                      d{    nO| xj                  |z  c_        | xj                  |z  c_        t        |      }| j                  |       d{    |j                   r1|j                   j                   r|j                   j                   | _        |j$                  }|syd| j&                   }|j(                  |k(  rnu|j(                  dk(  rCt+        | d      sZt-        j.                  d|j(                   d	| j&                          d| _        n#t-        j.                  d
|j(                          y|j2                  }|sy| j
                  s[| j                  d       d{    | j                  t5                      d{    | j                  t                      d{    | j6                  j9                  |       t;        || j&                  d      }| j                  |       d{    y7 7 7 n7 D7 %7 7 7 7 7 j7  w)zHandle the model turn message.r   NTr   r"  z	audio/pcm_sample_rate_warning_loggedz'Sample rate not provided in mime type 'z', assuming rate of z#Unrecognized server_content format rG   )r%  r(  r+  )r  r  r   stop_ttfb_metricsr   ro  r  r   r   thoughtr"   r#   r!   ru  r  r    r  r  inline_datarx  r   hasattrr   r   rN  r$  r'   rt  r*  r&   )r   rL  r   r   r   rQ  expected_mime_typer%  s           r   r  z+GeminiLiveLLMService._handle_msg_model_turn"  s    !!,,2215$$&&& yy** 11$777oo&?&ABBB || oo&:&<===oo&9$&?@@@oo&8&:;;; %%-%**d2*$$/ooe,,, #"4"4"G"G363E3E3X3XD0 &&  /t/@/@.AB  $66""k14!>?=k>S>S=TThimizizh{| 480 NN@AVAV@WXY   &&--d333///"3444//";"=>>>%%e, ))

 ooe$$$K 	' 8B >@; -H 44> 	%s   :LK93L0K<1 LK?,L>L?!L L! LLALLDL%L& LL L'L(AL3L4L<L?LLLLLLLLLllm_tool_callr   c           
        K   |j                   j                  }|sy| j                  st        j                  d       |D cg c]X  }t        | j                  |j                  xs t        t        j                               |j                  |j                        Z }}| j                  |       d{    yc c}w 7 
w)zHandle tool call messages.Nz:Function calls are not supported without a context object.)r  r  function_name	arguments)r  function_callsrg  r   r  r9   r  r   uuiduuid4r  r   run_function_calls)r   r   rX  ffunction_calls_llms        r   r  z*GeminiLiveLLMService._handle_msg_tool_callo  s      !**99}}LLUV $
    DD-C

-ff&&	
 
 %%&8999
 	:s   ?CAB:C4B?5Cllm_responsec                   K   | j                   }d| _         d| _        | j                  r.| j                  | j                  | j                         d{    d| _        d| _        | j
                  r| j                  d       d{    |sC| j                  t                      d{    | j                  t                      d{    y| j                  t                      d{    yy7 7 n7 M7 .7 w)z!Handle the turn complete message.r   NF)
ru  rv  r  _process_grounding_metadatar  ro  r  r   r(   r   r   r   r   s      r   r  z.GeminiLiveLLMService._handle_msg_turn_complete  s      $$
 !#"$ //2244d6P6P  
 &("/3,""--e444ooo&7888oo&=&?@@@ oo&=&?@@@ # 5 9@ AsZ   AC<C22C<C4"C<(C6) C<	C8
!C<+C:,C<4C<6C<8C<:C<
transcriptis_finalc                    K   yw)z+Handle a transcription result with tracing.Nr   )r   rb  rc  rd   s       r   _handle_user_transcriptionz/GeminiLiveLLMService._handle_user_transcription  s     
 	r   resultc                    K   | j                  |d| j                  j                         d{    | j                  t	        |dt               |      t        j                         d{    y7 B7 w)aL  Push a user transcription frame upstream.

        Helper method to ensure consistent handling of user transcriptions
        from both punctuation-based and timeout-based paths.

        Args:
            text: The transcription text to push
            result: Optional LiveServerMessage that triggered this transcription
        TNr   )r   user_id	timestamprf  )re  rL  rd   r   r%   rD   r4   UPSTREAM)r   r   rf  s      r   _push_user_transcriptionz-GeminiLiveLLMService._push_user_transcription  sn      --dD$..:Q:QRRRoo*,	 ##
 	
 	
 	S	
s!   +A4A0<A4*A2+A42A4c                 f  K   	 t        j                  d       d{    | j                  rRt        j                  d| j                   d       | j                  }d| _        | j                  |d       d{    yy7 c7 # t         j                  $ r t        j                  d        w xY ww)zHandle timeout for user transcription buffer.

        If no new transcription messages arrive within the timeout period,
        flush any remaining text in the buffer as a complete sentence.
        r&  Nz/[Transcription:user:timeout] Flushing buffer: []r   rf  z7Transcription timeout task cancelled (new text arrived))asynciosleeprr  r   r2  rk  CancelledError)r   complete_sentences     r   _transcription_timeout_handlerz3GeminiLiveLLMService._transcription_timeout_handler  s     	--$$$ ..EdFeFeEffgh %)$C$C!24/334Ed3SSS / % T%% 	 LLRS		s?   B1B B AB 9B:B >B1 B B *B..B1c                   K   |j                   j                  sy|j                   j                  j                  }|sy| j                  r*| j	                  | j                         d{    d| _        |j                  d      r| j                  s|j                         }| xj                  |z  c_        	 t        | j                        }|snX| j                  d| }| j                  |d | _        t        j                  d| d       | j                  ||       d{    p| j                  rB| j                  | j                               | _        t        j                  d       d{    yy7 7 W7 w)a  Handle the input transcription message.

        Gemini Live sends user transcriptions in either single words or multi-word
        phrases. As a result, we have to aggregate the input transcription. This handler
        aggregates into sentences, splitting on the end of sentence markers. If no
        punctuation arrives within a timeout period, the buffer is flushed automatically.
        N z[Transcription:user] [rm  rn  r   )r  r  r   rw  r  
startswithrr  lstriprC   r   r   rk  r  rs  ro  rp  )r   r   r   eos_end_markerrr  s        r   r  z4GeminiLiveLLMService._handle_msg_input_transcription  sl     %%99%%99>> ++""4#C#CDDD/3D, ??3(G(G;;=D 	''4/' 01P1PQN! !% ? ? P.2.M.Mno.^D+ LL12C1DAFG//0A'/RRR   **/3/?/?3350D, --""" +7 E. S #s8   A%E<'E5(B8E< E8!AE<.E:/E<8E<:E<c                 ^  K   |j                   j                  sy|j                   j                  j                  }|sy| xj                  |z  c_        |j                   r1|j                   j                  r|j                   j                  | _        | xj                  |z  c_        | j                  s[| j                  d       d{    | j                  t                      d{    | j                  t                      d{    | j                  |       d{    y7 `7 A7 "7 w)z(Handle the output transcription message.NT)r  r	  r   r  r  r  rv  ro  r  r   r'   r   &_push_output_transcription_text_framesra  s      r   r
  z5GeminiLiveLLMService._handle_msg_output_transcription  s     %%::
 %%::?? 	""d*" !!g&<&<&O&O3:3I3I3\3\D04' &&--d333///"3444//";"=>>>99$???	 44>?sH   CD-D% D-%D'& D-D)D-D+ D-'D-)D-+D-c                    K   t        |      }d|_        | j                  |       d {    t        |t        j
                        }d|_        | j                  |       d {    y 7 @7 w)NF)aggregated_byT)r    append_to_contextr   r)   r   SENTENCEincludes_inter_frame_spaces)r   r   llm_text_frametts_text_frames       r   rz  z;GeminiLiveLLMService._push_output_transcription_text_frames3  se      &d++0(oon--- &d/:R:RS592oon--- 	.
 	.s!   'A.A*:A.$A,%A.,A.c                    K   |j                   rR|j                   j                  r;|j                   j                  }| j                  || j                         d{    yyy7 w)z-Handle dedicated grounding metadata messages.N)r  r  r`  r  )r   r   r  s      r   r  z3GeminiLiveLLMService._handle_msg_grounding_metadataF  s[     !!g&<&<&O&O!(!7!7!J!J223EtGaGabbb 'P! cs   AA$A"A$r  search_resultc                 ,  K   |syd}|j                   r,|j                   j                  r|j                   j                  }g }|j                  r|j                  ri }t	        |j                        D ]^  \  }}|j
                  st        |j
                  j                  |j
                  j                  g       }|||<   |j                  |       ` |j                  D ]  }	|	j                  s|	j                  s|	j                  j                  xs d}
|	j                  xs g }|	j                  D ]2  }||v st        |
|      }||   j                  j                  |       4  t!        |||      }| j#                  |       d{    y7 w)z;Process grounding metadata and emit LLMSearchResponseFrame.N)site_uri
site_titleresultsr   )r   
confidence)r  originsrendered_content)search_entry_pointr  grounding_chunksgrounding_supports	enumeratewebr5   urititler   segmentgrounding_chunk_indicesr   confidence_scoresr7   r  r6   r   )r   r  r  r  r  chunk_to_originindexchunkoriginsupportr   r  chunk_indexrf  search_frames                  r   r`  z0GeminiLiveLLMService._process_grounding_metadataM  sz     "  11"55FF1DDUU ..3E3X3X:<O )*<*M*M N +u99,!&599??TVF .4OE*NN6*+ .@@ 	P??w'F'F"??//52D(/(A(A(GR% (/'F'F P&/9%4$K\%]F+K8@@GGOP	P .'K[
 ool+++s,   BFA)F0F==F;AFFFc                 "  K   |j                   sy|j                   }|j                  xs d}|j                  xs d}|j                  xs ||z   }t	        ||||j
                  |j                        }| j                  |       d{    y7 w)z"Handle the usage metadata message.Nr   )prompt_tokenscompletion_tokenstotal_tokenscache_read_input_tokensreasoning_tokens)r  prompt_token_countresponse_token_counttotal_token_countr-   cached_content_token_countthoughts_token_countstart_llm_usage_metrics)r   r   usager  r  r  tokenss          r   r  z/GeminiLiveLLMService._handle_msg_usage_metadata~  s     %%&& 005A!66;!..U=CT3T'/%$)$D$D"77
 **6222s   BBBBc                 r    |j                   }|j                  r|j                  r|j                  | _        y y y r   )r  	resumable
new_handler  )r   r   updates      r   r  z2GeminiLiveLLMService._handle_msg_resumption_update  s4    22 1 1.4.?.?D+ !2r   c                 |   K   | j                   s| j                  sy | j                  d|        d {    y 7 w)NzSend error: )r  )rl  rj  r  )r   r  s     r   r)  z'GeminiLiveLLMService._handle_send_error  s7      dmm oo,ug(>o???s   2<:<user_paramsassistant_paramsr  r  c                V    t        j                  |      }d|_        t        |||      S )a  Create an instance of GeminiLiveContextAggregatorPair from an OpenAILLMContext.

        Constructor keyword arguments for both the user and assistant aggregators can be provided.

        NOTE: this method exists only for backward compatibility. New code
        should instead do::

            context = LLMContext(...)
            context_aggregator = LLMContextAggregatorPair(context)

        Args:
            context: The LLM context to use.
            user_params: User aggregator parameters. Defaults to LLMUserAggregatorParams().
            assistant_params: Assistant aggregator parameters. Defaults to LLMAssistantAggregatorParams().

        Returns:
            A pair of user and assistant context aggregators.

        .. 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.
        Fr  )r.   r  expect_stripped_wordsr1   )r   r  r  r  s       r   create_context_aggregatorz.GeminiLiveLLMService.create_context_aggregator  s2    > 00916.'?O
 	
r   r   )r   )[r   r   r   r   r=  Settingsr  r   adapter_classr   r	   r  r
   r   r;  r   r%  rU   r   r  propertyrH   r  r  r>   r   r  r  r  r  r  rA   r  r2   r  r$   r  r   r  r   r  r  r  r  r   r4   r   r.   r  r  r  r  rV   r  r  r  r  r  r  r  r  r  r  r  rE   r   r  rJ   r  rW   r  r  r  rF   re  rk  rs  r  r
  rz  r  rT   r`  r  r  r)  r0   r/   r1   r  r   r   s   @r   rK  rK  }  s&    %H$$ %M #'# #(#(,0:>(,4848!Y.2E+ E+ 3-	E+
 }E+ E+ !E+ !E+ %SME+ d4j+567E+ %E+ 01E+ .2E+ E+ {+E+NV -  d K DcN &*T **T *//? /	FX 	F.)9 .* ! !!+ !9H<4 <4> <4|CPZ CPJI I0=t =zW zWx85F 8t+"I $ 6W
V(H.-# -,-*5>-. "34--,/-FJ3PS8n- 5-  +.2< 2 /2K%0A K%Z /2:3D : 3:0 .1A7H A 2A< NR)-9A(9K 
3 
IZ@[ 
*22#=N 2#h!@>O !@F. .&c<M c KM/,"3/,DG/,b38I 3,@5F @
@i @" 0G/H9U9W#
!#
 -	#

 7#
 
"#
r   rK  )r   ro  r9  r3  r  rY  r   dataclassesr   r   enumr   typingr   r   r   r	   r
   logurur   PILr   pydanticr   r   %pipecat.adapters.schemas.tools_schemar   (pipecat.adapters.services.gemini_adapterr   pipecat.frames.framesr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   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/   r0   5pipecat.processors.aggregators.llm_response_universalr1   1pipecat.processors.aggregators.openai_llm_contextr2   r3   "pipecat.processors.frame_processorr4   pipecat.services.google.framesr5   r6   r7   pipecat.services.google.utilsr8   pipecat.services.llm_servicer9   r:   pipecat.services.openai.llmr;   r<   pipecat.services.settingsr=   r>   r?   r@   pipecat.transcriptions.languagerA   rB   pipecat.utils.stringrC   pipecat.utils.timerD   (pipecat.utils.tracing.service_decoratorsrE   rF   r  rH   google.genairI   google.genai.liverJ   google.genai.typesrK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r\   r]   r^   r_   r`   ra   rb   ModuleNotFoundErrorr  r  r  r  r  r   r   r   r   r   r   r  r  r  r!  r%  r=  rK  r   r   r   <module>r     s     	    (  3 3   % = E       < 2 A [ > c c K H ` _ F 4 / S # ,#.      B  #'  ^I( ^Ix} ^IB~( ~B%4&A %4P2+K 2j * * *Z	t 	#C # =i =$Y 5B) 5Bp aK a a8L
: L
S  ,FLL;qc"#FLL[\
&qc*
++,s   
A G H"4HH