
    qi,                        d Z ddlZddlmZ ddlmZ ddl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 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% e G d de!             Z& G d de      Z'y)zTavus video service implementation for avatar-based video generation.

This module implements Tavus as a sink transport layer, providing video
avatar functionality through Tavus's streaming API.
    N)	dataclass)Optional)	AudioData
VideoFrame)logger)create_stream_resampler)BotStartedSpeakingFrameCancelFrameEndFrameFrameInterruptionFrameOutputAudioRawFrameOutputImageRawFrameOutputTransportReadyFrameSpeechOutputAudioRawFrame
StartFrameTTSAudioRawFrameTTSStartedFrame)FrameDirectionFrameProcessorSetup)	AIService)ServiceSettings)TavusCallbacksTavusParamsTavusTransportClientc                       e Zd ZdZy)TavusVideoSettingsz%Settings for the Tavus video service.N)__name__
__module____qualname____doc__     N/opt/pipecat/venv/lib/python3.12/site-packages/pipecat/services/tavus/video.pyr   r   *   s    /r#   r   c                   H    e Zd ZU dZeZeed<   ddddededed	ej                  d
e
e   ddf fdZdef fdZ fdZd Zd Zd ZdededefdZdede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ed e f fd!Z!d" Z"d# Z#d$ Z$d% Z%de&fd&Z'd' Z( xZ)S )(TavusVideoServicea  Service that proxies audio to Tavus and receives audio and video in return.

    Uses the TavusTransportClient to manage sessions and handle communication.
    When audio is sent, Tavus responds with both audio and video streams, which
    are routed through Pipecat's media pipeline.

    In use cases with DailyTransport, this creates two distinct virtual rooms:

    - Tavus room: Contains the Tavus Avatar and the Pipecat Bot
    - User room: Contains the Pipecat Bot and the user
    	_settingszpipecat-streamN)
persona_idsettingsapi_key
replica_idr(   sessionr)   returnc                $   t        d      }||j                  |       t        |   dd|i| || _        || _        || _        || _        d| _        d| _	        |  t               | _        t               | _        d| _        d| _        d| _        y)a[  Initialize the Tavus video service.

        Args:
            api_key: Tavus API key used for authentication.
            replica_id: ID of the Tavus voice replica to use for speech synthesis.
            persona_id: ID of the Tavus persona. Defaults to "pipecat-stream" for Pipecat TTS voice.
            session: Async HTTP session used for communication with Tavus.
            settings: Runtime-updatable settings. Tavus has no model concept, so this
                is primarily used for the ``extra`` dict.
            **kwargs: Additional arguments passed to the parent AIService class.
        N)modelr)   Fstreamr"   )r   apply_updatesuper__init___api_key_session_replica_id_persona_id_other_participant_has_joined_clientr   
_resampler	bytearray_audio_buffer
_send_task_transport_destination_transport_ready)	selfr*   r+   r(   r,   r)   kwargsdefault_settings	__class__s	           r$   r3   zTavusVideoService.__init__A   s    * +6))(3="2=f=%%-2*7;13&[265=# %r#   setupc                 z  K   t         |   |       d{    t        | j                  | j                  | j
                        }t        d|| j                  | j                  | j                  | j                  t        dddd            | _        | j                  j                  |       d{    y7 7 w)zoSet up the Tavus video service.

        Args:
            setup: Frame processor setup configuration.
        N)	on_joinedon_participant_joinedon_participant_leftPipecatTF)audio_in_enabledvideo_in_enabledaudio_out_enabledmicrophone_out_enabled)bot_name	callbacksr*   r+   r(   r,   params)r2   rD   r   
_on_joined_on_participant_joined_on_participant_leftr   r4   r6   r7   r5   r   r9   )r@   rD   rO   rC   s      r$   rD   zTavusVideoService.setupl   s      gmE""""oo"&"="= $ 9 9
	
 ,MM''''MM!%!%"&',	
 ll  ''') 	#( 	(s"   B;B7BB;1B92B;9B;c                    K   t         |           d{    | j                  j                          d{    d| _        y7 .7 w)z+Clean up the service and release resources.N)r2   cleanupr9   )r@   rC   s    r$   rU   zTavusVideoService.cleanup   s=     goll""$$$ 	 $s   AA!AAAAc                 6   K   t        j                  d       yw)z!Handle bot joined the Daily room.zTavus bot joined Daily roomNr   info)r@   datas     r$   rQ   zTavusVideoService._on_joined   s     12s   c                 L   K   |d   }t        j                  d| d|        yw)z'Handle participant leaving the session.idzParticipant left z
, reason: NrW   )r@   participantreasonparticipant_ids       r$   rS   z&TavusVideoService._on_participant_left   s+     $T*''7z&JKs   "$c                 \  K   |d   }t        j                  d|        | j                  s{d| _        | j                  j	                  || j
                  d       d{    | j                  j                  || j                  | j                  j                         d{    yy7 J7 w)z'Handle participant joining the session.r[   zParticipant joined T   N)r^   callbacksample_rate)	r   rX   r8   r9   capture_participant_video_on_participant_video_framecapture_participant_audio_on_participant_audio_dataout_sample_rate)r@   r\   r^   s      r$   rR   z(TavusVideoService._on_participant_joined   s     $T*).)9:;1115D.,,88 @ @"   ,,88-88 LL88 9    2s%   AB,B(AB,!B*"B,*B,r^   video_framevideo_sourcec                    K   t        |j                  |j                  |j                  f|j                        }||_        | j                  r| j                  |       d{    yy7 w)z/Handle incoming video frames from participants.)imagesizeformatN)r   bufferwidthheightcolor_formattransport_sourcer?   
push_frame)r@   r^   rh   ri   frames        r$   rd   z-TavusVideoService._on_participant_video_frame   se      $$$##[%7%78++

 ".  //%((( !(s   A A+"A)#A+audioaudio_sourcec                    K   t        |j                  |j                  |j                        }||_        | j
                  r| j                  |       d{    yy7 w)z-Handle incoming audio data from participants.)ru   rb   num_channelsN)r   audio_framesrb   rx   rr   r?   rs   )r@   r^   ru   rv   rt   s        r$   rf   z,TavusVideoService._on_participant_audio_data   sZ      *$$))++

 ".  //%((( !(s   AAAAc                      y)zCheck if this service can generate processing metrics.

        Returns:
            True, as Tavus service supports metrics generation.
        Tr"   r@   s    r$   can_generate_metricsz&TavusVideoService.can_generate_metrics   s     r#   c                 R   K   | j                   j                          d{   S 7 w)zsGet the name of the current persona.

        Returns:
            The persona name from the Tavus client.
        N)r9   get_persona_namer{   s    r$   r~   z"TavusVideoService.get_persona_name   s!      \\224444s   '%'rt   c                 4  K   t         |   |       d{    | j                  j                  |       d{    | j                  r-| j                  j	                  | j                         d{    | j                          d{    y7 y7 X7 !7 w)zStart the Tavus video service.

        Args:
            frame: The start frame containing initialization parameters.
        N)r2   startr9   r>   register_audio_destination_create_send_taskr@   rt   rC   s     r$   r   zTavusVideoService.start   s}      gmE"""ll  '''&&,,99$:U:UVVV$$&&&	 	#'V&sC   BB"BB8B2B3B
BBBBBc                    K   t         |   |       d{    | j                          d{    | j                          d{    y7 57 7 	w)zWStop the Tavus video service.

        Args:
            frame: The end frame.
        N)r2   stop_end_conversation_cancel_send_taskr   s     r$   r   zTavusVideoService.stop   sL      gl5!!!$$&&&$$&&& 	"&&1   AAAAAAAAAc                    K   t         |   |       d{    | j                          d{    | j                          d{    y7 57 7 	w)z\Cancel the Tavus video service.

        Args:
            frame: The cancel frame.
        N)r2   cancelr   r   r   s     r$   r   zTavusVideoService.cancel   sL      gnU###$$&&&$$&&& 	$&&r   	directionc                 v  K   t         |   ||       d{    t        |t              r3| j	                          d{    | j                  ||       d{    yt        |t              r| j                  |       d{    yt        |t              r"d| _	        | j                  ||       d{    yt        |t              r| j                          d{    yt        |t              r| j                          d{    y| j                  ||       d{    y7 7 7 7 7 {7 T7 -7 w)zProcess frames through the service.

        Args:
            frame: The frame to process.
            direction: The direction of frame processing.
        NT)r2   process_frame
isinstancer   _handle_interruptionsrs   r   _handle_audio_framer   r?   r   start_ttfb_metricsr	   stop_ttfb_metrics)r@   rt   r   rC   s      r$   r   zTavusVideoService.process_frame   s     g#E9555e./,,...//%333/0**511189$(D!//%333/))+++67 ((***//%333% 	6 /31 4+
 +3s   D9D('D9D+ D9D-)D9D/1D95D16(D9D3(D9D5D9"D7#D9+D9-D9/D91D93D95D97D9c                    K   | j                          d{    | j                          d{    | j                  j                          d{    y7 ?7 )7 	w)zHHandle interruption events by resetting send tasks and notifying client.N)r   r   r9   send_interrupt_messager{   s    r$   r   z'TavusVideoService._handle_interruptions  sM     $$&&&$$&&&ll11333 	'&3s1   AAAA!AAAAAc                 b   K   | j                   j                          d{    d| _        y7 w)z-End the current conversation and reset state.NF)r9   r   r8   r{   s    r$   r   z#TavusVideoService._end_conversation  s)     ll!!!-2* 	"s   /-/c                    K   | j                   s>t        j                         | _        | j	                  | j                               | _         yyw)z2Create the audio sending task if it doesn't exist.N)r=   asyncioQueue_queuecreate_task_send_task_handlerr{   s    r$   r   z#TavusVideoService._create_send_task  s:     !--/DK"..t/F/F/HIDO s   AAc                 ~   K   | j                   r+| j                  | j                          d{    d| _         yy7 w)z+Cancel the audio sending task if it exists.N)r=   cancel_taskr{   s    r$   r   z#TavusVideoService._cancel_send_task  s4     ??""4??333"DO 3s   +=;=c                 Z  K   | j                   j                  }t        |dz  dz        }| j                  j	                  |j
                  |j                  |       d{   }| j                  j                  |       t        | j                        |k\  rt        t        | j                  d|       ||j                        }| j                  |_        | j                  j!                  |       d{    | j                  |d | _        t        | j                        |k\  ryy7 7 5w)z*Process audio frames for sending to Tavus.      N)rb   rx   )r9   rg   intr:   resampleru   rb   r<   extendlenr   bytesrx   r>   transport_destinationr   put)r@   rt   rb   
chunk_size	resampledchunks         r$   r   z%TavusVideoService._handle_audio_frame"  s     ll22+/R/0
 //225;;@Q@QS^__	!!),$$$%3'd((*56'"//E
 +/*E*EE'++//%(((!%!3!3JK!@D $$$%3 ` )s+   AD+D'BD+3D)40D+%D+)D+c                   K   	 | j                   j                          d{   }t        |t              r/| j                  r#| j                  j                  |       d{    | j                   j                          |7 ^7 !w)z0Handle sending audio frames to the Tavus client.N)r   getr   r   r9   write_audio_frame	task_done)r@   rt   s     r$   r   z$TavusVideoService._send_task_handler5  sa     ++//++E%!45$,,ll44U;;;KK!!#	 +;s!   BB >B B! BB)*r   r   r    r!   r   Settings__annotations__straiohttpClientSessionr   r3   r   rD   rU   rQ   rS   rR   r   rd   r   rf   boolr|   r~   r   r   r   r   r
   r   r   r   r   r   r   r   r   r   r   r   __classcell__)rC   s   @r$   r&   r&   1   s?   
 "H!! +15)& )& 	)&
 )& &&)& -.)& 
)&V(!4 (83L
)!)0:)JM))!)*3)CF)d 5 5
' 
'' ''+ '4 4> 4643
J#A/B A&$r#   r&   )(r!   r   dataclassesr   typingr   r   daily.dailyr   r   logurur   pipecat.audio.utilsr   pipecat.frames.framesr	   r
   r   r   r   r   r   r   r   r   r   r   "pipecat.processors.frame_processorr   r   pipecat.services.ai_servicer   pipecat.services.settingsr   "pipecat.transports.tavus.transportr   r   r   r   r&   r"   r#   r$   <module>r      sp     !   -  7    S 1 5 ` ` 	 	 	J$	 J$r#   