
    qi                     \   d Z ddlZddlZddlZddlZddlmZ ddlmZ 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m Z m!Z!m"Z"m#Z#m$Z$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/ ddl0m1Z1m2Z2 ddl3m4Z4 ddl5m6Z6m7Z7 ddl8m9Z9 ddl:m;Z; ddl<m=Z=m>Z> ddl?m@Z@ ddlAmBZBmCZCmDZD ddlEmFZFmGZG 	 ddlHmIZJ e G d d             ZOe G d de6             ZP G d de2      ZQy# eK$ r7ZL e
j                  deL         e
j                  d        eNdeL       dZL[Lww xY w) zGOpenAI Realtime Beta LLM service implementation with WebSocket support.    N)	dataclass)Optional)logger)OpenAIRealtimeLLMAdapter)AggregationTypeBotStoppedSpeakingFrameCancelFrameEndFrame
ErrorFrameFrameInputAudioRawFrameInterimTranscriptionFrameInterruptionFrameLLMContextFrameLLMFullResponseEndFrameLLMFullResponseStartFrameLLMMessagesAppendFrameLLMSetToolsFrameLLMTextFrameLLMUpdateSettingsFrame
StartFrameTranscriptionFrameTTSAudioRawFrameTTSStartedFrameTTSStoppedFrameTTSTextFrameUserStartedSpeakingFrameUserStoppedSpeakingFrame)LLMTokenUsage)LLMAssistantAggregatorParamsLLMUserAggregatorParams)OpenAILLMContextOpenAILLMContextFrame)FrameDirection)FunctionCallFromLLM
LLMService)OpenAIContextAggregatorPair)LLMSettings_warn_deprecated_param)Language)time_now_iso8601)traced_openai_realtime
traced_stt   )events)(OpenAIRealtimeAssistantContextAggregatorOpenAIRealtimeLLMContext#OpenAIRealtimeUserContextAggregator)RealtimeFunctionCallResultFrameRealtimeMessagesUpdateFrame)connectzException: zEIn order to use OpenAI, you need to `pip install pipecat-ai[openai]`.zMissing module: c                   >    e Zd ZU dZeed<   eed<   eed<   dZeed<   y)CurrentAudioResponseao  Tracks the current audio response from the assistant.

    Parameters:
        item_id: Unique identifier for the audio response item.
        content_index: Index of the audio content within the item.
        start_time_ms: Timestamp when the audio response started in milliseconds.
        total_size: Total size of audio data received in bytes. Defaults to 0.
    item_idcontent_indexstart_time_msr   
total_sizeN)__name__
__module____qualname____doc__str__annotations__intr;        ^/opt/pipecat/venv/lib/python3.12/site-packages/pipecat/services/openai_realtime_beta/openai.pyr7   r7   N   s$     LJrD   r7   c                       e Zd ZdZy)OpenAIRealtimeBetaLLMSettingsz*Settings for OpenAIRealtimeBetaLLMService.N)r<   r=   r>   r?   rC   rD   rE   rG   rG   _   s    4rD   rG   c                       e Zd ZU dZeZeed<   eZdddddddde	d	e
e	   d
e	de
ej                     de
e   dedef fdZdefdZdefdZde	defdZde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  Z	 dTd!ed"ed#edefd$Z d% Z!de"d&e#f fd'Z$d( Z%d) Z&d*ejN                  fd+Z(d, Z)d- Z*d. Z+ fd/Z,d0 Z-d1 Z. e/d23      d4        Z0d5 Z1d6 Z2d7 Z3d8 Z4d9 Z5e6	 dUd:e	d;ed<e
e7   fd=       Z8d> Z9d?ejt                  fd@Z; e/dA3      dB        Z<dC Z=dD Z>dE Z?dF Z@d?ej                  fdGZBdH ZCdI ZDdJ ZEdK ZF e/dL3      dM        ZGdN ZH eI        eJ       dOdPeKdQeIdReJdeLfdSZM xZNS )VOpenAIRealtimeBetaLLMServicea  OpenAI Realtime Beta LLM service providing real-time audio and text communication.

    .. deprecated:: 0.0.84
        `OpenAIRealtimeBetaLLMService` is deprecated, use `OpenAIRealtimeLLMService` instead.
        This class will be removed in version 1.0.0.

    Implements the OpenAI Realtime API Beta with WebSocket communication for low-latency
    bidirectional audio and text interactions. Supports function calling, conversation
    management, and real-time transcription.
    	_settingsNz wss://api.openai.com/v1/realtimeFT)modelbase_urlsession_propertiessettingsstart_audio_pausedsend_transcription_framesapi_keyrK   rL   rM   rN   rO   rP   c                   t        j                         5  t        j                  d       t        j                  dt        d       ddd       t        ddddddddddd      }	|t        d	t
        d	       ||	_        ||	j                  |       | d
|	j                   }
t        | (  d|
|	d| || _        |
| _        |xs t        j                         | _        || _        || _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        i | _        d| _        | j9                  d       | j9                  d       i | _        y# 1 sw Y   xY w)ay  Initialize the OpenAI Realtime Beta LLM service.

        Args:
            api_key: OpenAI API key for authentication.
            model: OpenAI model name.

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

            base_url: WebSocket base URL for the realtime API.
                Defaults to "wss://api.openai.com/v1/realtime".
            session_properties: Configuration properties for the realtime session.
                If None, uses default SessionProperties.
            settings: Runtime-updatable settings for this service.
            start_audio_paused: Whether to start with audio input paused. Defaults to False.
            send_transcription_frames: Whether to emit transcription frames. Defaults to True.
            **kwargs: Additional arguments passed to parent LLMService.
        alwayszvOpenAIRealtimeBetaLLMService is deprecated and will be removed in version 1.0.0. Use OpenAIRealtimeLLMService instead.   )
stacklevelNz"gpt-4o-realtime-preview-2025-06-03F)rK   system_instructiontemperature
max_tokenstop_ptop_kfrequency_penaltypresence_penaltyseedfilter_incomplete_user_turnsuser_turn_completion_configrK   z?model=)rL   rN   on_conversation_item_createdon_conversation_item_updatedrC   )warningscatch_warningssimplefilterwarnDeprecationWarningrG   r)   rK   apply_updatesuper__init__rQ   rL   r/   SessionProperties_session_properties_audio_input_paused_send_transcription_frames
_websocket_receive_task_context_disconnecting_api_session_ready_run_llm_when_api_session_ready_current_assistant_response_current_audio_response_messages_added_manually _user_and_response_message_tuple_register_event_handler#_retrieve_conversation_item_futures)selfrQ   rK   rL   rM   rN   rO   rP   kwargsdefault_settingsfull_url	__class__s              rE   ri   z%OpenAIRealtimeBetaLLMService.__init__x   s   < $$& 	!!(+MM8"		 96#"!).(,
 "7,I7S%*"))(3Zw'7'='=&>? 	
%	
 	
  #5#S9Q9Q9S #5 *C'!#"'/4,+/('+$(*%04-$$%CD$$%CD350y	 	s   2EE)returnc                      y)zCheck if the service can generate usage metrics.

        Returns:
            True if metrics generation is supported.
        TrC   rz   s    rE   can_generate_metricsz1OpenAIRealtimeBetaLLMService.can_generate_metrics   s     rD   pausedc                     || _         y)zzSet whether audio input is paused.

        Args:
            paused: True to pause audio input, False to resume.
        N)rl   )rz   r   s     rE   set_audio_input_pausedz3OpenAIRealtimeBetaLLMService.set_audio_input_paused   s     $* rD   modalityc                 B    | j                   j                  xs ddg}||v S )z;Check if a specific modality is enabled, "text" or "audio".audiotextrk   
modalities)rz   r   r   s      rE   _is_modality_enabledz1OpenAIRealtimeBetaLLMService._is_modality_enabled   s(    --88MWf<M
:%%rD   c                 :    | j                   j                  xs ddgS )z#Get the list of enabled modalities.r   r   r   r   s    rE   _get_enabled_modalitiesz4OpenAIRealtimeBetaLLMService._get_enabled_modalities   s    ''22Gw6GGrD   r8   c                 b  K   | j                         j                         }d}| j                  j                  |      sg | j                  |<   nd}| j                  |   j	                  |       |s1| j                  t        j                  |d|              d{    | d{   S 7 7 w)zRetrieve a conversation item by ID from the server.

        Args:
            item_id: The ID of the conversation item to retrieve.

        Returns:
            The retrieved conversation item.
        FTrci_)r8   event_idN)get_event_loopcreate_futurery   getappendsend_client_eventr/   ConversationItemRetrieveEvent)rz   r8   futureretrieval_in_flights       rE   retrieve_conversation_itemz7OpenAIRealtimeBetaLLMService.retrieve_conversation_item   s      $$&446#77;;GD@BD44W="&009@@H"(( 44WQUV]U^O_`   | s$   BB/B+	B/&B-'B/-B/framec                 t   K   t         |   |       d{    | j                          d{    y7 7 w)zStart the service and establish WebSocket connection.

        Args:
            frame: The start frame triggering service initialization.
        N)rh   start_connectrz   r   r~   s     rE   r   z"OpenAIRealtimeBetaLLMService.start  s3      gmE"""mmo 	#   848688c                 t   K   t         |   |       d{    | j                          d{    y7 7 w)zStop the service and close WebSocket connection.

        Args:
            frame: The end frame triggering service shutdown.
        N)rh   stop_disconnectr   s     rE   r   z!OpenAIRealtimeBetaLLMService.stop  s6      gl5!!!    	" r   c                 t   K   t         |   |       d{    | j                          d{    y7 7 w)zCancel the service and close WebSocket connection.

        Args:
            frame: The cancel frame triggering service cancellation.
        N)rh   cancelr   r   s     rE   r   z#OpenAIRealtimeBetaLLMService.cancel  s6      gnU###    	$ r   c                 "  K   | j                   j                  du rV| j                  t        j                                d {    | j                  t        j
                                d {    | j                          d {    | j                          d {    | j                  rU| j                  t                      d {    | j                  d      r"| j                  t                      d {    y y y 7 7 7 7 l7 A7 w)NFr   )rk   turn_detectionr   r/   InputAudioBufferClearEventResponseCancelEvent _truncate_current_audio_responsestop_all_metricsrt   
push_framer   r   r   r   s    rE   _handle_interruptionz1OpenAIRealtimeBetaLLMService._handle_interruption+  s      ##22e;(()J)J)LMMM(()C)C)EFFF33555##%%%++//"9";<<<((1ooo&7888 2 ,	 NF5%< 9sk   ?DD*D,D-DDDD	,D	D
1D;D<DDD	DDDc                    K   y wNrC   rz   r   s     rE   _handle_user_started_speakingz:OpenAIRealtimeBetaLLMService._handle_user_started_speaking9  s	        c                    K   | j                   j                  du rW| j                  t        j                                d {    | j                  t        j
                                d {    y y 7 17 w)NF)rk   r   r   r/   InputAudioBufferCommitEventResponseCreateEventr   s     rE   _handle_user_stopped_speakingz:OpenAIRealtimeBetaLLMService._handle_user_stopped_speaking<  sb      ##22e;(()K)K)MNNN(()C)C)EFFF <NFs#   ?A7A3*A7,A5-A75A7c                    K   d | _         y wr   )ru   r   s    rE   _handle_bot_stopped_speakingz9OpenAIRealtimeBetaLLMService._handle_bot_stopped_speakingC  s     '+$s   	total_bytessample_ratebytes_per_samplec                 2    ||z  }||z  }t        |dz        S )zGCalculate audio duration in milliseconds based on PCM audio parameters.  )rB   )rz   r   r   r   samplesduration_secondss         rE   _calculate_audio_duration_msz9OpenAIRealtimeBetaLLMService._calculate_audio_duration_msF  s+      00"[0#d*++rD   c           	        K   | j                   sy	 | j                   }d| _         | j                  |j                        }t        t	        j                         dz  |j
                  z
        }t        ||      }t        j                  d| d| d| d       | j                  t        j                  |j                  |j                  |             d{    y7 # t        $ r"}t        j                  d|        Y d}~yd}~ww xY ww)	a  Truncates the current audio response at the appropriate duration.

        Calculates the actual duration of the audio content and truncates at the shorter of
        either the wall clock time or the actual audio duration to prevent invalid truncation
        requests.
        Nr   zTruncating audio: duration=zms, elapsed=zms, truncate=ms)r8   r9   audio_end_msz%Audio truncation failed (non-fatal): )ru   r   r;   rB   timer:   minr   tracer   r/   ConversationItemTruncateEventr8   r9   	Exceptionwarning)rz   currentaudio_duration_ms
elapsed_mstruncate_mses         rE   r   z=OpenAIRealtimeBetaLLMService._truncate_current_audio_responseN  s     ++	H22G+/D( !% A A'BTBT U TYY[4/'2G2GGHJj*;<KLL-.?-@ A%,mK=D
 ((44#OO")"7"7!,    	HNNB1#FGG	HsA   DCC CC DC 	D&D>DDD	directionc                 2  K   t        |t              rc|j                  Wt        j                  di |j
                  | _        | j                          d{    | j                  ||       d{    yt        | )  ||       d{    t        |t              rn6t        |t              rt        j                  |j                        }| j                   s|| _        n7|j                  | j                   ur|| _        | j#                          d{    | j%                          d{    nt        |t&              rt)        d      t        |t*              r(| j,                  sj| j/                  |       d{    nOt        |t0              r| j3                          d{    n%t        |t4              r| j7                  |       d{    nt        |t8              r| j;                  |       d{    nt        |t<              r| j?                          d{    nt        |t@              r| jC                  |       d{    n~t        |tD              r|j                  | _        n\t        |tF              r| j                          d{    n3t        |tH              r#| jK                  |jL                         d{    | j                  ||       d{    y7 7 7 n7 7 7 7 Y7 17 
7 7 7 r7 @7 (w)zProcess incoming frames from the pipeline.

        Args:
            frame: The frame to process.
            direction: The direction of frame flow in the pipeline.
        Nz>Universal LLMContext is not yet supported for OpenAI Realtime.rC   )'
isinstancer   deltar/   rj   rN   rk   _send_session_updater   rh   process_framer   r#   r1   upgrade_to_realtimecontextrp   reset_conversation_create_responser   NotImplementedErrorr   rl   _send_user_audior   r   r   r   r   r   r   r   r   _handle_messages_appendr4   r   r3   _handle_function_call_resultresult_frame)rz   r   r   r   r~   s       rE   r   z*OpenAIRealtimeBetaLLMService.process_framez  sy     e349L'-'?'?'Q%..'QD$++---//%333g#E9555e/0450H0\0\1G == 'dmm3 '--///'')))/%P  12++++E22201++---7844U;;;7844U;;;673355556..u555:;!MMDM/0++--->?33E4F4FGGGooeY///Y .3 	6 0) 3-;;55 .G/s   ALK2L1K52L
K8BLK;L.K>/ALL)L+L,*LL)L L
(L)L*)LLA
LL3LLL,L-L5L8L;L>LLLL
LLLLLLc                 6   K   t        j                  d       y w)Nz%!!! NEED TO IMPLEMENT MESSAGES APPEND)r   errorr   s     rE   r   z4OpenAIRealtimeBetaLLMService._handle_messages_append  s     <=s   c                    K   t        j                  d|j                  t        j                  |j
                              }| j                  t        j                  |             d {    y 7 w)Nfunction_call_output)typecall_idoutputitem)r/   ConversationItemtool_call_idjsondumpsresultr   ConversationItemCreateEvent)rz   r   r   s      rE   r   z9OpenAIRealtimeBetaLLMService._handle_function_call_result  sS     &&'&&::ell+

 $$V%G%GT%RSSSs   A(A2*A0+A2eventc                 b   K   | j                  |j                  d             d{    y7 w)ztSend a client event to the OpenAI Realtime API.

        Args:
            event: The client event to send.
        T)exclude_noneN)_ws_send
model_dump)rz   r   s     rE   r   z.OpenAIRealtimeBetaLLMService.send_client_event  s(      mmE,,$,?@@@s   %/-/c                 T  K   	 | j                   ry t        | j                  d| j                   dd       d {   | _         | j	                  | j                               | _        y 7 .# t        $ r0}| j                  d| |       d {  7   d | _         Y d }~y d }~ww xY ww)NzBearer zrealtime=v1)AuthorizationzOpenAI-Beta)uriadditional_headerszError connecting: 	error_msg	exception)	rn   websocket_connectrL   rQ   create_task_receive_task_handlerro   r   
push_errorrz   r   s     rE   r   z%OpenAIRealtimeBetaLLMService._connect  s     	# $5MM'.t||n%=#0$% DO "&!1!1$2L2L2N!OD  	#//.@,DPQ/RRR"DOO	#sT   B(A, B(*A, A*-A, )B(*A, ,	B%5B BB B( B%%B(c                   K   	 d| _         d| _        | j                          d {    | j                  r)| j                  j	                          d {    d | _        | j
                  r,| j                  | j
                  d       d {    d | _        d| _         y 7 y7 M7 # t        $ r)}| j                  d| |       d {  7   Y d }~y d }~ww xY ww)NTFg      ?)timeoutzError disconnecting: r   )	rq   rr   r   rn   closero   cancel_taskr   r   r   s     rE   r   z(OpenAIRealtimeBetaLLMService._disconnect  s     	V"&D&+D#'')))oo++---"&!!&&t'9'93&GGG%)""'D *- H  	V//.CA3,GST/UUU	Vsn   C!B% B-B% B!7B% B#B% CB% !B% #B% %	C.CC
CCCCc                 $  K   	 | j                   r7| j                   j                  t        j                  |             d {    y y 7 # t        $ r:}| j
                  rY d }~y | j                  d| |       d {  7   Y d }~y d }~ww xY ww)NzError sending client event: r   )rn   sendr   r   r   rq   r   )rz   realtime_messager   s      rE   r   z%OpenAIRealtimeBetaLLMService._ws_send  s{     
	]oo**4::6F+GHHH H 	]""
 //.J1#,NZ[/\\\	]sX   B=A
 AA
 BA
 
	BBB$B=B >BBBBc                    K   t         |   |       d{   }| j                  |j                                |S 7 %w)zApply a settings delta.N)rh   _update_settings _warn_unhandled_updated_settingskeys)rz   r   changedr~   s      rE   r  z-OpenAIRealtimeBetaLLMService._update_settings  s7     077--glln= 8s   ><&>c                 v  K   | j                   }| j                  r1| j                  j                  r| j                  j                  |_        | j                  r1| j                  j                  r| j                  j                  |_        | j                  t        j                  |             d {    y 7 w)N)session)rk   rp   tools_session_instructionsinstructionsr   r/   SessionUpdateEvent)rz   rN   s     rE   r   z1OpenAIRealtimeBetaLLMService._send_session_update   s{     ++==T]]00!]]00HN ==T]]@@$(MM$G$GH!$$V%>%>x%PQQQs   B/B91B72B9c                   K   | j                   2 3 d {   }t        j                  |      }|j                  dk(  r| j	                  |       d {    G|j                  dk(  r| j                  |       d {    p|j                  dk(  r| j                  |       d {    |j                  dk(  r| j                  |       d {    |j                  dk(  r| j                  |       d {    |j                  dk(  r| j                  |       d {    |j                  dk(  r| j                  |       d {    ?|j                  dk(  r| j                  |       d {    i|j                  d	k(  r| j                  |       d {    |j                  d
k(  r| j                  |       d {    |j                  dk(  r| j                  |       d {    |j                  dk(  r| j                  |       d {    |j                  dk(  r| j!                  |       d {    ;|j                  dk(  sL| j#                  |       d {   rg|j$                  j&                  dv r0t)        j*                  |  d|j$                  j,                          | j/                  |       d {     y 7 7 7 f7 @7 7 7 7 7 7 Y7 27 7 7 7 7 06 y w)Nzsession.createdzsession.updatedzresponse.audio.deltazresponse.audio.donezconversation.item.createdz1conversation.item.input_audio_transcription.deltaz5conversation.item.input_audio_transcription.completedzconversation.item.retrievedzresponse.donez!input_audio_buffer.speech_startedz!input_audio_buffer.speech_stoppedzresponse.text.deltazresponse.audio_transcript.deltar   )response_cancel_not_active(conversation_already_has_active_response )rn   r/   parse_server_eventr   _handle_evt_session_created_handle_evt_session_updated_handle_evt_audio_delta_handle_evt_audio_done%_handle_evt_conversation_item_created+_handle_evt_input_audio_transcription_delta.handle_evt_input_audio_transcription_completed#_handle_conversation_item_retrieved_handle_evt_response_done_handle_evt_speech_started_handle_evt_speech_stopped_handle_evt_text_delta"_handle_evt_audio_transcript_delta2_maybe_handle_evt_retrieve_conversation_item_errorr   coder   debugmessage_handle_evt_error)rz   r%  evts      rE   r   z2OpenAIRealtimeBetaLLMService._receive_task_handler  s    !__ &	 &	'++G4Cxx,,66s;;;..66s;;;332237772211#66688@@EEEPPFFsKKKTTII#NNN::>>sCCC_,44S999@@55c:::@@55c:::2211#666>>==cBBBW$!TTUXYYYyy~~ *  vQsyy/@/@.A%BC"44S999M&	 <;76EKNC9::6BY :I -s@  LLKL9LK(L9K:(L"K"#(LK%(L4K(5(LK+)LK.)L1K12)LK4)LK7)L/K:0)LK=)LK?LL/L0L6ALLLLLL"L%L(L+L.L1L4L7L:L=L?LLLL	llm_setup)	operationc                 @   K   | j                          d {    y 7 wr   )r   rz   r'  s     rE   r  z8OpenAIRealtimeBetaLLMService._handle_evt_session_created9  s      '')))s   c                 v   K   d| _         | j                  r d| _        | j                          d {    y y 7 w)NTF)rr   rs   r   r+  s     rE   r  z8OpenAIRealtimeBetaLLMService._handle_evt_session_updated?  s9     "&//38D0''))) 0)s   .979c                   K   | j                          d {    | j                  rT| j                  j                  |j                  k7  r1t        j                  d       t        j
                  d       d | _        | j                  sft        |j                  |j                  t        t        j                         dz              | _        | j                  t                      d {    t        j                  |j                        }| j                  xj                  t!        |      z  c_        t#        |dd      }| j                  |       d {    y 7 F7 v7 
w)NzpReceived a new audio delta for an already completed audio response before receiving the BotStoppedSpeakingFrame.z'Forcing previous audio response to Noner   )r8   r9   r:   ]  r.   )r   r   num_channels)stop_ttfb_metricsru   r8   r   r   r$  r7   r9   rB   r   r   r   base64	b64decoder   r;   lenr   )rz   r'  r   r   s       rE   r  z4OpenAIRealtimeBetaLLMService._handle_evt_audio_deltaG  s     $$&&&''D,H,H,P,PTWT_T_,_NN C LLBC+/D(+++?!//!$))+"45,D(
 ///"3444  +$$//3u:=/ 

 ooe$$$/ 	' 5 	%s5   E#ECE#(E)A-E#E!E#E#!E#c                 l   K   | j                   r"| j                  t                      d {    y y 7 wr   )ru   r   r   r+  s     rE   r  z3OpenAIRealtimeBetaLLMService._handle_evt_audio_donec  s,     ''///"3444 (4s   )424c                    K   | j                  d|j                  j                  |j                         d {    | j                  j	                  |j                  j                        r"| j                  |j                  j                  = y |j                  j
                  dk(  r|j                  dg df| _        y |j                  j
                  dk(  r3|j                  | _        | j                  t                      d {    y y 7 7 w)Nr`   userF)doner   	assistant)
_call_event_handlerr   idrv   r   rolerw   rt   r   r   r+  s     rE   r  zBOpenAIRealtimeBetaLLMService._handle_evt_conversation_item_createdi  s     &&'Esxx{{TWT\T\]]]
 ((,,SXX[[9--chhkk:88==F" 69XXY[?\4]D1XX]]k)/2xxD,//";"=>>> * 	^  ?s"   5DD
CDDDDc                    K   | j                   r9| j                  t        |j                  dt	               |             d {    y y 7 w)N r   )rm   r   r   r   r+   r+  s     rE   r  zHOpenAIRealtimeBetaLLMService._handle_evt_input_audio_transcription_delta|  sF     **//)#))R9I9KTWX   +s   A AA	A
transcriptis_finallanguagec                    K   yw)z+Handle a transcription result with tracing.NrC   )rz   r?  r@  rA  s       rE   _handle_user_transcriptionz7OpenAIRealtimeBetaLLMService._handle_user_transcription  s     
 	r   c                 r  K   | j                  d|j                  d       d{    | j                  rk| j                  t	        |j
                  dt               |             d{    | j                  |j
                  dt        j                         d{    | j                  }|rh|\  }}|j
                  |j                  d   _        |d   r?d| _
        | j                  j                  |       | j                  |d          d{    yyt        j                   d	|        y7 7 7 7 &w)
z{Handle completion of input audio transcription.

        Args:
            evt: The transcription completed event.
        ra   Nr=  r>  Tr   r7  r   z%Transcript for unknown user message: )r9  r8   rm   r   r   r?  r+   rC  r*   ENrw   contentrp    add_user_content_item_as_message_handle_assistant_outputr   r   )rz   r'  pairr6  r8  s        rE   r  zKOpenAIRealtimeBetaLLMService.handle_evt_input_audio_transcription_completed  s     &&'Es{{TXYYY**//"3>>27G7IRUV   11#..$TTT44"OD)),DLLO& 8<5>>tD33Ih4GHHH ! NNB3%HI% 	Z U IsG   !D7D.AD7'D1(2D7D3A3D7D5 D71D73D75D7r'  c                    K   | j                   j                  |j                  j                  d       }|r#|D ]  }|j	                  |j                          y y wr   )ry   popr   r:  
set_result)rz   r'  futuresr   s       rE   r  z@OpenAIRealtimeBetaLLMService._handle_conversation_item_retrieved  sO     ::>>sxx{{DQ! ,!!#((+, s   AAllm_responsec                 N  K   t        |j                  j                  j                  |j                  j                  j                  |j                  j                  j
                        }| j                  |       d {    | j                          d {    | j                  t                      d {    d | _
        |j                  j                  dk(  r>| j                  t        |j                  j                  d   d                d {    y |j                  j                  D ]'  }| j!                  d|j"                  |       d {    ) | j$                  }|r||\  }}d|d<   |j                  j                  |d	<   |j&                  d
   j(                  ?d | _        | j*                  j-                  |       | j/                  |d	          d {    y y | j/                  |j                  j                         d {    y 7 7 7 a7 7 7 B7 w)N)prompt_tokenscompletion_tokenstotal_tokensfailedr   r%  )r   ra   Tr7  r   r   )r   responseusageinput_tokensoutput_tokensrR  start_llm_usage_metricsstop_processing_metricsr   r   rt   statusr   r   status_detailsr   r9  r:  rw   rF  r?  rp   rG  rH  )rz   r'  tokensr   rI  r6  r8  s          rE   r  z6OpenAIRealtimeBetaLLMService._handle_evt_response_done  s     ,,,,99!ll00>>++88

 **6222**,,,oo57888+/(<<(*//*3<<3N3Nw3WXa3b"cdddLL'' 	ZD**+I477TXYYY	Z44"OD) $If"%,,"5"5Ih||A))58<5>>tD33Ih4GHHH 6 //0C0CDDD- 	3,8 e Z I Es   A=H%?H H%H H%8H9AH%H>H%HB	H%H!.H%H#H%H%H%H%H%!H%#H%c                    K   |j                   r-| j                  t        |j                                d {    y y 7 wr   )r   r   r   r+  s     rE   r   z3OpenAIRealtimeBetaLLMService._handle_evt_text_delta  s0     99//,syy"9::: :s   4?=?c                    K   |j                   ri| j                  t        |j                                d {    | j                  t        |j                   t        j
                               d {    y y 7 B7 w)N)aggregated_by)r   r   r   r   r   SENTENCEr+  s     rE   r!  z?OpenAIRealtimeBetaLLMService._handle_evt_audio_transcript_delta  sW     99//,syy"9::://,syyH`H`"abbb :bs!   4A=A9;A=2A;3A=;A=c                    K   | j                          d {    | j                  t               d {    | j                          d {    y 7 :7 7 	wr   )r   broadcast_framer   broadcast_interruptionr+  s     rE   r  z7OpenAIRealtimeBetaLLMService._handle_evt_speech_started  sL     33555""#;<<<))+++ 	6<+s1   AAAAAAAAAc                    K   | j                          d {    | j                          d {    | j                  t               d {    y 7 :7 $7 	wr   )start_ttfb_metricsstart_processing_metricsrb  r   r+  s     rE   r  z7OpenAIRealtimeBetaLLMService._handle_evt_speech_stopped  sL     %%'''++---""#;<<< 	(-<s1   AAAAAAAAAc                 8  K   |j                   j                  dk(  r}|j                   j                  j                  dd      d   }| j                  j                  |d      }|r5|D ]0  }|j                  t        |j                   j                               2 yyw)a7  Maybe handle an error event related to retrieving a conversation item.

        If the given error event is an error retrieving a conversation item:

        - set an exception on the future that retrieve_conversation_item() is waiting on
        - return true
        Otherwise:
        - return false
        item_retrieve_invalid_item_id_r.   NTF)	r   r#  r   splitry   rK  set_exceptionr   r%  )rz   r'  r8   rM  r   s        rE   r"  zOOpenAIRealtimeBetaLLMService._maybe_handle_evt_retrieve_conversation_item_error  s      99>><<ii((..sA6q9G>>BB7DQG% GF((3993D3D)EFGs   BBc                 J   K   | j                  d|        d {    y 7 w)NzError: )r   )r   r+  s     rE   r&  z.OpenAIRealtimeBetaLLMService._handle_evt_error  s      oo'#o888s   #!#c                    K   |D cg c]  }|j                   dk(  s| }}| j                  |       d {    y c c}w 7 
w)Nfunction_call)r   _handle_function_call_items)rz   r   r   function_callss       rE   rH  z5OpenAIRealtimeBetaLLMService._handle_assistant_output  sC     
 ,2R4TYY/5Q$RR..~>>> S>s   A<<AAAc           	      
  K   g }|D ]]  }t        j                  |j                        }|j                  t	        | j
                  |j                  |j                  |             _ | j                  |       d {    y 7 w)N)r   r   function_name	arguments)	r   loadsrs  r   r%   rp   r   namerun_function_calls)rz   itemsrp  r   argss        rE   ro  z8OpenAIRealtimeBetaLLMService._handle_function_call_items  sp      		D::dnn-D!!# MM!%"&))"			 %%n555s   A9B;B<Bc                    K   t        j                  d       | j                          d{    | j                  r"d| j                  _        d| j                  _        | j                          d{    y7 K7 w)zReset the conversation by disconnecting and reconnecting.

        This is the safest way to start a new conversation. Note that this will
        fail if called from the receive task.
        zResetting conversationNT)r   r$  r   rp   llm_needs_settings_updatellm_needs_initial_messagesr   r   s    rE   r   z/OpenAIRealtimeBetaLLMService.reset_conversation  s`      	-.   ==6:DMM37;DMM4mmo	 	! 	s"   )A;A7AA;1A92A;9A;llm_requestc                   K   | j                   sd| _        y | j                  j                  r| j                  j	                         }|D ]T  }t        j                  |      }d| j                  |j                  j                  <   | j                  |       d {    V d| j                  _        | j                  j                  r)| j                          d {    d| j                  _        t        j                  d| j                  j                                 | j!                  t#                      d {    | j%                          d {    | j'                          d {    | j                  t        j(                  t        j*                  | j-                                            d {    y 7 (7 7 7 s7 ]7 w)NTr   FzCreating response: )r   )rT  )rr   rs   rp   r{  %get_messages_for_initializing_historyr/   r   rv   r   r:  r   rz  r   r   r$  get_messages_for_loggingr   r   rf  re  r   ResponsePropertiesr   )rz   messagesr   r'  s       rE   r   z-OpenAIRealtimeBetaLLMService._create_response  su    &&37D0==33}}JJLH  288dC=A--chhkk:,,S1112 8=DMM4==22++---6;DMM3*4==+Q+Q+S*TUVoo79:::++---%%'''$$&&22d>Z>Z>\]
 	
 	
 2 .
 	;-'	
so   BGGA GGA!G<G=GGG,G
-AG;G<GGGG
GGc                    K   t        j                  |j                        j                  d      }| j	                  t        j                  |             d {    y 7 w)Nzutf-8)r   )r1  	b64encoder   decoder   r/   InputAudioBufferAppendEvent)rz   r   payloads      rE   r   z-OpenAIRealtimeBetaLLMService._send_user_audio:  sD     ""5;;/66w?$$V%G%Gg%VWWWs   AA!AA!)user_paramsassistant_paramsr   r  r  c                    |j                  | j                                t        j                  |       t	        ||      }d|_        t        ||      }t        ||      S )a/  Create an instance of OpenAIContextAggregatorPair from an OpenAILLMContext.

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

        Args:
            context: The LLM context.
            user_params: User aggregator parameters.
            assistant_params: Assistant aggregator parameters.

        Returns:
            OpenAIContextAggregatorPair: A pair of context aggregators, one for
            the user and one for the assistant, encapsulated in an
            OpenAIContextAggregatorPair.
        )paramsF)_user
_assistant)set_llm_adapterget_llm_adapterr1   r   r2   expect_stripped_wordsr0   r'   )rz   r   r  r  r6  r8  s         rE   create_context_aggregatorz6OpenAIRealtimeBetaLLMService.create_context_aggregator>  sX    * 	 4 4 67 44W=27;O16.<WM]^	*)LLrD   )r.  rT   r   )Or<   r=   r>   r?   rG   SettingsrA   r   adapter_classr@   r   r/   rj   boolri   r   r   r   listr   r   r   r   r
   r   r	   r   r   r   r   r   rB   r   r   r   r$   r   r   r   ClientEventr   r   r   r   r  r   r   r,   r  r  r  r  r  r  r-   r*   rC  r  ConversationItemRetrievedr  r  r   r!  r  r  
ErrorEventr"  r&  rH  ro  r   r   r   r!   r    r"   r'   r  __classcell__)r~   s   @rE   rI   rI   f   s   	 -H,, -M  $:AE<@#(*.Z6 Z6 }	Z6
 Z6 %V%=%=>Z6 89Z6 !Z6 $(Z6xd *T *&S &T &
Hc H > ! !!+ !9G, ST,,-0,LO,	,$HX90 90> 90v>TAV-?-? A#$V]	R 'R k2* 3*
*%85?& NR)-9A(9K J4,V=]=] , n5E 6E@;c
,
=
FL]L] &9?6& m4
 5
8X 0G/H9U9WM!M -	M
 7M 
%MrD   rI   )Rr?   r1  r   r   rb   dataclassesr   typingr   logurur   2pipecat.adapters.services.open_ai_realtime_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   pipecat.metrics.metricsr   +pipecat.processors.aggregators.llm_responser    r!   1pipecat.processors.aggregators.openai_llm_contextr"   r#   "pipecat.processors.frame_processorr$   pipecat.services.llm_servicer%   r&   pipecat.services.openai.llmr'   pipecat.services.settingsr(   r)   pipecat.transcriptions.languager*   pipecat.utils.timer+   (pipecat.utils.tracing.service_decoratorsr,   r-   r=  r/   r   r0   r1   r2   framesr3   r4   websockets.asyncio.clientr5   r   ModuleNotFoundErrorr   r   r   r7   rG   rI   rC   rD   rE   <module>r     s   N     !   W      4 2 > H C I 4 / W  
 Q,F     	K 	 	tM: tM=  ,FLL;qc"#FLLXY
&qc*
++,s   >C/ /D+42D&&D+