o
    it                     @   sZ  d Z ddlmZ ddlmZmZmZmZm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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mZ dd
l m!Z! ddl"m#Z# ddl$m%Z%m&Z& ddl'm(Z(m)Z)m*Z* ddl+m,Z, G dd deZ-G dd deZ.G dd de)Z/G dd dZ0G dd de!Z1G dd de#Z2G dd de%Z3dS )zLemonSlice transport for Pipecat.

This module adds LemonSlice avatars to Daily rooms, enabling
real-time voice conversations with synchronized avatars.
    )partial)Any	AwaitableCallableMappingOptionalN)	AudioData)logger)	BaseModel)BotStartedSpeakingFrameBotStoppedSpeakingFrameCancelFrameEndFrameFrameInputAudioRawFrameInterruptionFrameOutputAudioRawFrameOutputTransportMessageFrame!OutputTransportMessageUrgentFrame
StartFrame)FrameDirectionFrameProcessorFrameProcessorSetup)BaseInputTransport)BaseOutputTransport)BaseTransportTransportParams)DailyCallbacksDailyParamsDailyTransportClient)LemonSliceApic                   @   s   e Zd ZU dZdZee ed< dZee ed< dZ	ee ed< dZ
ee ed< dZee ed< dZee ed< dZee ed	< dS )
LemonSliceNewSessionRequesta  Request model for creating a new LemonSlice session.

    Parameters:
        agent_image_url: URL to an agent image. Provide either agent_id or agent_image_url.
        agent_id: ID of a LemonSlice agent. Provide either agent_id or agent_image_url.
        agent_prompt: A high-level system prompt that subtly influences the avatar's movements,
            expressions, and emotional demeanor.
        idle_timeout: Idle timeout in seconds.
        daily_room_url: Daily room URL to use for the session.
        daily_token: Daily token for authenticating with the room.
        lemonslice_properties: Additional properties to pass to the session.
    Nagent_image_urlagent_idagent_promptidle_timeoutdaily_room_urldaily_tokenlemonslice_properties)__name__
__module____qualname____doc__r"   r   str__annotations__r#   r$   r%   intr&   r'   r(   dict r1   r1   [/home/ubuntu/.local/lib/python3.10/site-packages/pipecat/transports/lemonslice/transport.pyr!   .   s   
 r!   c                   @   sP   e Zd ZU dZeeeef ged f e	d< eeeef eged f e	d< dS )LemonSliceCallbackszCallback handlers for LemonSlice events.

    Parameters:
        on_participant_joined: Called when a participant joins the conversation.
        on_participant_left: Called when a participant leaves the conversation.
    Non_participant_joinedon_participant_left)
r)   r*   r+   r,   r   r   r-   r   r   r.   r1   r1   r1   r2   r3   E   s   
 $r3   c                   @   s6   e Zd ZU dZdZeed< dZeed< dZeed< dS )LemonSliceParamsa-  Configuration parameters for the LemonSlice transport.

    Parameters:
        audio_in_enabled: Whether to enable audio input from participants.
        audio_out_enabled: Whether to enable audio output to participants.
        microphone_out_enabled: Whether to enable microphone output track.
    Taudio_in_enabledaudio_out_enabledFmicrophone_out_enabledN)	r)   r*   r+   r,   r7   boolr.   r8   r9   r1   r1   r1   r2   r6   Q   s
   
 r6   c                   @   sp  e Zd ZdZe dddededededee d	e	j
d
dfddZd
efddZdefddZdd Zdd Zdd Zdd Zd
efddZdefddZdd  Z	!	"	#dFd$ed%ed&ed'ed(ef
d)d*Z	+	,	-dGd$ed%ed.ed/ed0ef
d1d2ZdeeB fd3d4Zed
efd5d6Zed
efd7d8Z dHd9d:Z!dHd;d<Z"dHd=d>Z#dId?d@Z$de%d
e&fdAdBZ'dCefdDdEZ(dS )JLemonSliceTransportClienta  Transport client that integrates Pipecat with the LemonSlice platform.

    A transport client that integrates a Pipecat Bot with the LemonSlice platform by managing
    conversation sessions using the LemonSlice API.

    This client uses `LemonSliceApi` to interact with the LemonSlice backend. LemonSlice either provides
    a room URL where the avatar is already present, or adds the LemonSlice avatar to a Daily room
    the user supplies.
    N)paramssession_requestbot_namer<   	callbacksapi_keyr=   sessionreturnc                C   s@   || _ t||| _|pt | _d| _d| _d| _|| _|| _	dS )a  Initialize the LemonSlice transport client.

        Args:
            bot_name: The name of the Pipecat bot instance.
            params: Optional parameters for LemonSlice operation.
            callbacks: Callback handlers for LemonSlice-related events.
            api_key: API key for authenticating with LemonSlice API.
            session_request: Optional session creation parameters. If not provided, a default
                agent will be used.
            session: The aiohttp session for making async HTTP requests.
        N)
	_bot_namer    _apir!   _session_request_session_id_control_url_daily_transport_client
_callbacks_params)selfr>   r<   r?   r@   r=   rA   r1   r1   r2   __init__j   s   
z"LemonSliceTransportClient.__init__c              	      sZ   | j j| jj| jj| jj| jj| jj| jj| jj	dI dH }|d | _
|d | _|d S )z4Initialize the conversation and return the room URL.)r"   r#   r$   r%   r&   r'   
propertiesN
session_idcontrol_urlroom_url)rD   create_sessionrE   r"   r#   r$   r%   r&   r'   r(   rF   rG   )rK   responser1   r1   r2   _initialize   s   
	
z%LemonSliceTransportClient._initializesetupc              
      s@  | j durtd| j   dS z|  I dH }td!i dt| jdd| jd| jdt| jddt| jddt| jdd	t| jd	d
t| jd
dt| jddt| jddt| jddt| jddt| jddt| jddt| jddt| jddt| jddt| jddt| jdd| j	j
d| j	jdt| jddt| jddt| jddt| jddt| jddt| jddt| jd}t|d| j| j|d| _| j|I dH  W dS  ty } z#td |  | j r| jr| j| j | jI dH  d| _ d| _ d}~ww )"zSetup the client and initialize the conversation.

        Args:
            setup: The frame processor setup configuration.
        NzSession ID already defined: on_active_speaker_changed	on_joinedon_lefton_before_leaveon_erroron_app_messageon_call_state_updatedon_client_connectedon_client_disconnectedon_dialin_connectedon_dialin_readyon_dialin_stoppedon_dialin_erroron_dialin_warningon_dialout_answeredon_dialout_connectedon_dialout_stoppedon_dialout_erroron_dialout_warningr4   r5   on_participant_updatedon_transcription_messageon_recording_startedon_recording_stoppedon_recording_erroron_transcription_stoppedon_transcription_errorLemonSlicePipecatz+Failed to setup LemonSliceTransportClient: r1   )rF   r	   debugrS   r   r   _on_handle_callback
_on_joined_on_leftrI   r4   r5   r   rC   rJ   rH   rT   	ExceptionerrorrG   rD   end_session)rK   rT   rP   daily_callbackser1   r1   r2   rT      s   
	
"$zLemonSliceTransportClient.setupc              
      s\   z| j r| j  I dH  W dS W dS  ty- } ztd|  W Y d}~dS d}~ww )zCleanup client resources.NzException during cleanup: )rH   cleanuprt   r	   ru   )rK   rx   r1   r1   r2   ry      s   z!LemonSliceTransportClient.cleanupc                       t d dS )zHandle joined event.z!LemonSliceTransportClient joined!Nr	   rp   )rK   datar1   r1   r2   rr         z$LemonSliceTransportClient._on_joinedc                    rz   )zHandle left event.zLemonSliceTransportClient left!Nr{   rK   r1   r1   r2   rs      r}   z"LemonSliceTransportClient._on_leftc                    s"   t d| d| d|  dS )zHandle generic callback events.z[Callback] z called with args=z	, kwargs=N)r	   trace)rK   
event_nameargskwargsr1   r1   r2   rq      s    z-LemonSliceTransportClient._on_handle_callbackc                    s   dS )zzGet the name of the LemonSlice participant.

        Returns:
            The name of the LemonSlice participant.
        
LemonSlicer1   r~   r1   r1   r2   get_bot_name   s   z&LemonSliceTransportClient.get_bot_nameframec                    s(   | j |I dH  | j  I dH  dS )zStart the client and join the room.

        Args:
            frame: The start frame containing initialization parameters.
        N)rH   startjoinrK   r   r1   r1   r2   r         zLemonSliceTransportClient.startc                    sF   | j  I dH  | jr| jr| j| j| jI dH  d| _d| _dS )z)Stop the client and end the conversation.N)rH   leaverF   rG   rD   rv   r~   r1   r1   r2   stop   s   
zLemonSliceTransportClient.stop   cameraRGBparticipant_idcallback	frameratevideo_sourcecolor_formatc                        | j |||||I dH  dS )ao  Capture video from a participant.

        Args:
            participant_id: ID of the participant to capture video from.
            callback: Callback function to handle video frames.
            framerate: Desired framerate for video capture.
            video_source: Video source to capture from.
            color_format: Color format for video frames.
        N)rH   capture_participant_video)rK   r   r   r   r   r   r1   r1   r2   r         
z3LemonSliceTransportClient.capture_participant_video
microphone>     audio_sourcesample_ratecallback_interval_msc                    r   )a  Capture audio from a participant.

        Args:
            participant_id: ID of the participant to capture audio from.
            callback: Callback function to handle audio data.
            audio_source: Audio source to capture from.
            sample_rate: Desired sample rate for audio capture.
            callback_interval_ms: Interval between audio callbacks in milliseconds.
        N)rH   capture_participant_audio)rK   r   r   r   r   r   r1   r1   r2   r     r   z3LemonSliceTransportClient.capture_participant_audioc                       | j |I dH  dS )eSend a message to participants.

        Args:
            frame: The message frame to send.
        N)rH   send_messager   r1   r1   r2   r   )  s   z&LemonSliceTransportClient.send_messagec                 C      | j jS )z`Get the output sample rate.

        Returns:
            The output sample rate in Hz.
        )rH   out_sample_rater~   r1   r1   r2   r   3     z)LemonSliceTransportClient.out_sample_ratec                 C   r   )z^Get the input sample rate.

        Returns:
            The input sample rate in Hz.
        )rH   in_sample_rater~   r1   r1   r2   r   <  r   z(LemonSliceTransportClient.in_sample_ratec                    2   t d td| jdd}| |I dH  dS )z4Send an interrupt message to the LemonSlice session.zSending interrupt message	interrupteventrN   messageN)r	   rp   r   rF   r   rK   transport_framer1   r1   r2   send_interrupt_messageE     
z0LemonSliceTransportClient.send_interrupt_messagec                    r   )z:Send a response_started message to the LemonSlice session.z Sending response_started messageresponse_startedr   r   Nr	   r   r   rF   r   r   r1   r1   r2   send_response_started_messageP  r   z7LemonSliceTransportClient.send_response_started_messagec                    r   )z;Send a response_finished message to the LemonSlice session.z!Sending response_finished messageresponse_finishedr   r   Nr   r   r1   r1   r2   send_response_finished_message[  r   z8LemonSliceTransportClient.send_response_finished_messagec                    s&   | j sdS | j j||dI dH  dS )Update subscription settings for participants.

        Args:
            participant_settings: Per-participant subscription settings.
            profile_settings: Global subscription profile settings.
        Nparticipant_settingsprofile_settings)rH   update_subscriptionsrK   r   r   r1   r1   r2   r   f  s   z.LemonSliceTransportClient.update_subscriptionsc                    s   | j sdS | j |I dH S )zWrite an audio frame to the transport.

        Args:
            frame: The audio frame to write.

        Returns:
            True if the audio frame was written successfully, False otherwise.
        FN)rH   write_audio_framer   r1   r1   r2   r   t  s   	z+LemonSliceTransportClient.write_audio_framedestinationc                    s"   | j sdS | j |I dH  dS )zRegister an audio destination for output.

        Args:
            destination: The destination identifier to register.
        N)rH   register_audio_destinationrK   r   r1   r1   r2   r     s   z4LemonSliceTransportClient.register_audio_destination)r   r   r   )r   r   r   )rB   NNN))r)   r*   r+   r,   r6   r-   r3   r   r!   aiohttpClientSessionrL   rS   r   rT   ry   rr   rs   rq   r   r   r   r   r   r/   r   r   r   r   r   propertyr   r   r   r   r   r   r   r:   r   r   r1   r1   r1   r2   r;   _   s    	
;	







r;   c                       s   e Zd ZdZdedef fddZdef fddZ fd	d
Z	de
f fddZdef fddZdef fddZdd ZdededefddZ  ZS )LemonSliceInputTransportzInput transport for receiving audio and events from LemonSlice.

    Handles incoming audio streams from participants and manages audio capture
    from the Daily room connected to LemonSlice.
    clientr<   c                    s*   t  j|fi | || _|| _d| _dS )zInitialize the LemonSlice input transport.

        Args:
            client: The LemonSlice transport client instance.
            params: Transport configuration parameters.
            **kwargs: Additional arguments passed to parent class.
        FN)superrL   _clientrJ   _initializedrK   r   r<   r   	__class__r1   r2   rL     s   
z!LemonSliceInputTransport.__init__rT   c                    *   t  |I dH  | j|I dH  dS )znSetup the input transport.

        Args:
            setup: The frame processor setup configuration.
        Nr   rT   r   rK   rT   r   r1   r2   rT        zLemonSliceInputTransport.setupc                    &   t   I dH  | j I dH  dS )z"Cleanup input transport resources.Nr   ry   r   r~   r   r1   r2   ry        z LemonSliceInputTransport.cleanupr   c                    sJ   t  |I dH  | jrdS d| _| j|I dH  | |I dH  dS )z{Start the input transport.

        Args:
            frame: The start frame containing initialization parameters.
        NT)r   r   r   r   set_transport_readyr   r   r1   r2   r     s   zLemonSliceInputTransport.startc                    (   t  |I dH  | j I dH  dS )zpStop the input transport.

        Args:
            frame: The end frame signaling transport shutdown.
        Nr   r   r   r   r   r1   r2   r     r   zLemonSliceInputTransport.stopc                    (   t  |I dH  | j I dH  dS )zyCancel the input transport.

        Args:
            frame: The cancel frame signaling immediate cancellation.
        Nr   cancelr   r   r   r   r1   r2   r     r   zLemonSliceInputTransport.cancelc                    sH   | j jr"td|d   | jj|d | j| jjdI dH  dS dS )zStart capturing audio from a participant.

        Args:
            participant: The participant to capture audio from.
        z@LemonSliceTransportClient start capturing audio for participant id)r   r   r   N)rJ   r7   r	   rp   r   r   _on_participant_audio_datar   rK   participantr1   r1   r2   start_capturing_audio  s   z.LemonSliceInputTransport.start_capturing_audior   audior   c                    s0   t |j|j|jd}||_| |I dH  dS )a  Handle received participant audio data.

        Args:
            participant_id: ID of the participant who sent the audio.
            audio: The audio data from the participant.
            audio_source: The source of the audio (e.g., microphone).
        )r   r   num_channelsN)r   audio_framesr   r   transport_sourcepush_audio_frame)rK   r   r   r   r   r1   r1   r2   r     s   
z3LemonSliceInputTransport._on_participant_audio_data)r)   r*   r+   r,   r;   r   rL   r   rT   ry   r   r   r   r   r   r   r   r-   r   r   __classcell__r1   r1   r   r2   r     s(    			r   c                       s   e Zd ZdZdedef fddZdef fddZ fd	d
Z	de
f fddZdef fddZdef fddZdeeB fddZejfdedef fddZdedef fddZdd Zdd Zdd Zdedefd d!Zd"efd#d$Z  Z S )%LemonSliceOutputTransportzOutput transport for sending audio and events to LemonSlice.

    Handles outgoing audio streams to participants and manages the custom
    audio track expected by the LemonSlice platform.
    r   r<   c                    s0   t  j|fi | || _|| _d| _d| _dS )zInitialize the LemonSlice output transport.

        Args:
            client: The LemonSlice transport client instance.
            params: Transport configuration parameters.
            **kwargs: Additional arguments passed to parent class.
        FstreamN)r   rL   r   rJ   r   _transport_destinationr   r   r1   r2   rL     s
   
z"LemonSliceOutputTransport.__init__rT   c                    r   )zoSetup the output transport.

        Args:
            setup: The frame processor setup configuration.
        Nr   r   r   r1   r2   rT     r   zLemonSliceOutputTransport.setupc                    r   )z#Cleanup output transport resources.Nr   r~   r   r1   r2   ry   !  r   z!LemonSliceOutputTransport.cleanupr   c                    sd   t  |I dH  | jrdS d| _| j|I dH  | jr(| j| jI dH  | |I dH  dS )z|Start the output transport.

        Args:
            frame: The start frame containing initialization parameters.
        NT)r   r   r   r   r   r   r   r   r   r1   r2   r   &  s   zLemonSliceOutputTransport.startc                    r   )zqStop the output transport.

        Args:
            frame: The end frame signaling transport shutdown.
        Nr   r   r   r1   r2   r   :  r   zLemonSliceOutputTransport.stopc                    r   )zzCancel the output transport.

        Args:
            frame: The cancel frame signaling immediate cancellation.
        Nr   r   r   r1   r2   r   C  r   z LemonSliceOutputTransport.cancelc                    s(   t d|  | j|I dH  dS )r   z$LemonSliceTransport sending message N)r	   r   r   r   r   r1   r1   r2   r   L  s   z&LemonSliceOutputTransport.send_message	directionc                    sT   |t jkrt|tr|  I dH  t|tr|  I dH  t ||I dH  dS )zPush a frame to the next processor in the pipeline.

        Args:
            frame: The frame to push.
            direction: The direction to push the frame.
        N)	r   
DOWNSTREAM
isinstancer   _handle_response_startedr   _handle_response_finishedr   
push_framerK   r   r   r   r1   r2   r   W  s   
	

z$LemonSliceOutputTransport.push_framec                    s6   t  ||I dH  t|tr|  I dH  dS dS )zProcess frames and handle interruptions.

        Args:
            frame: The frame to process.
            direction: The direction of frame flow in the pipeline.
        N)r   process_framer   r   _handle_interruptionsr   r   r1   r2   r   g  s
   
z'LemonSliceOutputTransport.process_framec                       | j  I dH  dS )z8Handle interruption events by sending interrupt message.N)r   r   r~   r1   r1   r2   r   r     z/LemonSliceOutputTransport._handle_interruptionsc                    r   )zGHandle bot started speaking events by sending response_started message.N)r   r   r~   r1   r1   r2   r   v  r   z2LemonSliceOutputTransport._handle_response_startedc                    r   )zHHandle tts response stopped events by sending response_finished message.N)r   r   r~   r1   r1   r2   r   z  r   z3LemonSliceOutputTransport._handle_response_finishedrB   c                    s   | j |_| j|I dH S )zWrite an audio frame to the LemonSlice transport.

        Args:
            frame: The audio frame to write.

        Returns:
            True if the audio frame was written successfully, False otherwise.
        N)r   transport_destinationr   r   r   r1   r1   r2   r   ~  s   
z+LemonSliceOutputTransport.write_audio_framer   c                    r   )zwRegister an audio destination.

        Args:
            destination: The destination identifier to register.
        N)r   r   r   r1   r1   r2   r     s   z4LemonSliceOutputTransport.register_audio_destination)!r)   r*   r+   r,   r;   r   rL   r   rT   ry   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r:   r   r-   r   r   r1   r1   r   r2   r     s,    			
r   c                       s   e Zd ZdZde ddfdedejdedee	 dedee d	ee f fd
dZ
dd Zdd ZdddZdefddZdefddZdefddZdefddZ  ZS )LemonSliceTransporta  Transport implementation to add a LemonSlice avatar to Daily calls.

    When used, the Pipecat bot joins the same virtual room as the LemonSlice Avatar and the user.
    This is achieved by using `LemonSliceTransportClient`, which initiates the conversation via
    `LemonSliceApi` and obtains a room URL that all participants connect to.

    Event handlers available:

    - on_client_connected(transport, participant): Participant connected to the session
    - on_client_disconnected(transport, participant): Participant disconnected from the session

    Example::

        @transport.event_handler("on_client_connected")
        async def on_client_connected(transport, participant):
            ...
    Nr>   rA   r@   r=   r<   
input_nameoutput_namec           	         sf   t  j||d || _t| j| jd}t||||||d| _d| _d| _	d| _
| d | d dS )a;  Initialize the LemonSlice transport.

        Args:
            bot_name: The name of the Pipecat bot.
            session: aiohttp session used for async HTTP requests.
            api_key: LemonSlice API key for authentication.
            session_request: Optional session creation parameters. If not provided, a default
                agent will be used.
            params: Optional LemonSlice-specific configuration parameters.
            input_name: Optional name for the input transport.
            output_name: Optional name for the output transport.
        )r   r   )r4   r5   )r>   r?   r@   r=   rA   r<   Nr\   r]   )r   rL   rJ   r3   _on_participant_joined_on_participant_leftr;   r   _input_output_lemonslice_participant_id_register_event_handler)	rK   r>   rA   r@   r=   r<   r   r   r?   r   r1   r2   rL     s&   
zLemonSliceTransport.__init__c                    sB   | j  I dH }|di dd|kr| |I dH  dS dS )zHandle participant left events.NinfouserName )r   r   get_on_client_disconnected)rK   r   reasonls_bot_namer1   r1   r2   r     s
   z(LemonSliceTransport._on_participant_leftc                    s   | j  I dH }|di dd|kr|d | _dS | |I dH  | jrAtd| j d | j| jdd	d
iiidI dH  | jrO| j	|I dH  dS dS )z!Handle participant joined events.Nr   r   r   r   z	Ignoring z's microphonemediar   unsubscribed)r   )
r   r   r   r   _on_client_connectedr	   rp   r   r   r   )rK   r   r   r1   r1   r2   r     s    z*LemonSliceTransport._on_participant_joinedc                    s   | j j||dI dH  dS )r   r   N)r   r   r   r1   r1   r2   r     s
   z(LemonSliceTransport.update_subscriptionsrB   c                 C      | j st| j| jd| _ | j S )zGet the input transport for receiving media and events.

        Returns:
            The LemonSlice input transport instance.
        r   r<   )r   r   r   rJ   r~   r1   r1   r2   input     zLemonSliceTransport.inputc                 C   r  )zGet the output transport for sending media and events.

        Returns:
            The LemonSlice output transport instance.
        r  )r   r   r   rJ   r~   r1   r1   r2   output  r  zLemonSliceTransport.outputr   c                       |  d|I dH  dS )zHandle client connected events.r\   N_call_event_handlerr   r1   r1   r2   r       z(LemonSliceTransport._on_client_connectedc                    r	  )z"Handle client disconnected events.r]   Nr
  r   r1   r1   r2   r     r  z+LemonSliceTransport._on_client_disconnectedr   )r)   r*   r+   r,   r6   r-   r   r   r   r!   rL   r   r   r   r   r  r  r   r  r   r   r1   r1   r   r2   r     s8    .


r   )4r,   	functoolsr   typingr   r   r   r   r   r   daily.dailyr   logurur	   pydanticr
   pipecat.frames.framesr   r   r   r   r   r   r   r   r   r   r   "pipecat.processors.frame_processorr   r   r   pipecat.transports.base_inputr   pipecat.transports.base_outputr   !pipecat.transports.base_transportr   r   "pipecat.transports.daily.transportr   r   r   !pipecat.transports.lemonslice.apir    r!   r3   r6   r;   r   r   r   r1   r1   r1   r2   <module>   s0   4  1m 