o
    iT1                  
   @   s8  d Z ddlZddlmZ ddlmZmZmZ ddlm	Z	 ddl
mZmZmZmZmZmZmZ ddlmZ ddlmZ dd	lmZ dd
lmZmZ ddlmZ zddlmZ ddl m!Z! W n  e"y| Z# ze	$de#  e	$d e%de# dZ#[#ww dedee& fddZ'eG dd deZ(G dd deZ)dS )z+LMNT text-to-speech service implementation.    N)	dataclass)AnyAsyncGeneratorOptional)logger)CancelFrameEndFrame
ErrorFrameFrame
StartFrameTTSAudioRawFrameTTSStoppedFrame)FrameDirection)TTSSettings)InterruptibleTTSService)Languageresolve_language)
traced_tts)connect)StatezException: zAIn order to use LMNT, you need to `pip install pipecat-ai[lmnt]`.zMissing module: languagereturnc              	   C   s   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t jdt jdt jdt jdi}t| |ddS )zConvert a Language enum to LMNT language code.

    Args:
        language: The Language enum value to convert.

    Returns:
        The corresponding LMNT language code, or None if not supported.
    ardeenesfrhiiditjakonlplptrusvthtrukurvizhT)use_base_code)r   ARDEENESFRHIIDITJAKONLPLPTRUSVTHTRUKURVIZHr   )r   LANGUAGE_MAP rD   M/home/ubuntu/.local/lib/python3.10/site-packages/pipecat/services/lmnt/tts.pylanguage_to_lmnt_language(   sR   		
rF   c                   @   s   e Zd ZdZdS )LmntTTSSettingszSettings for LmntTTSService.N)__name__
__module____qualname____doc__rD   rD   rD   rE   rG   L   s    rG   c                       sp  e Zd ZU dZeZeed< ddejddddde	de
e	 de
e d	ed
e	de
e	 de
e f fddZdefddZd	ede
e	 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ejfdedef fddZ fddZ fd d!Zd"edee	ef f fd#d$Zd%d& Z d'd( Z!d)d* Z"d3d+e
e	 fd,d-Z#d.d/ Z$e%d0e	d+e	de&edf fd1d2Z'  Z(S )4LmntTTSServicezLMNT real-time text-to-speech service.

    Provides real-time text-to-speech synthesis using LMNT's WebSocket API.
    Supports streaming audio generation with configurable voice models and
    language settings.
    	_settingsN	pcm_s16le)voice_idsample_rater   output_formatmodelsettingsapi_keyrO   rP   r   rQ   rR   rS   c          
         s   | j ddtjd}	|dur| dd ||	_|dur#| dd ||	_|dur0| dd ||	_|dur9|	| t j	d
ddd||	d	| || _
|| _d| _dS )aE  Initialize the LMNT TTS service.

        Args:
            api_key: LMNT API key for authentication.
            voice_id: ID of the voice to use for synthesis.

                .. deprecated:: 0.0.105
                    Use ``settings=LmntTTSService.Settings(voice=...)`` instead.

            sample_rate: Audio sample rate. If None, uses default.
            language: Language for synthesis. Defaults to English.

                .. deprecated:: 0.0.106
                    Use ``settings=LmntTTSService.Settings(language=...)`` instead.

            output_format: Audio output format. One of "pcm_s16le", "pcm_f32le",
                "mp3", "ulaw", "webm". Defaults to "pcm_s16le".
            model: TTS model to use.

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

            settings: Runtime-updatable settings. When provided alongside deprecated
                parameters, ``settings`` values take precedence.
            **kwargs: Additional arguments passed to parent InterruptibleTTSService.
        auroraN)rR   voicer   rO   rV   r   rR   T)push_stop_framespush_start_framepause_frame_processingrP   rS   rD   )Settingsr   r0   "_warn_init_param_moved_to_settingsrV   r   rR   apply_updatesuper__init___api_key_output_format_receive_task)
selfrT   rO   rP   r   rQ   rR   rS   kwargsdefault_settings	__class__rD   rE   r^   ^   s8   '
	
zLmntTTSService.__init__r   c                 C   s   dS )zCheck if this service can generate processing metrics.

        Returns:
            True, as LMNT service supports metrics generation.
        TrD   rb   rD   rD   rE   can_generate_metrics   s   z#LmntTTSService.can_generate_metricsc                 C   s   t |S )zConvert a Language enum to LMNT service language format.

        Args:
            language: The language to convert.

        Returns:
            The LMNT-specific language code, or None if not supported.
        )rF   )rb   r   rD   rD   rE   language_to_service_language   s   	z+LmntTTSService.language_to_service_languageframec                    &   t  |I dH  |  I dH  dS )z|Start the LMNT TTS service.

        Args:
            frame: The start frame containing initialization parameters.
        N)r]   start_connectrb   rj   re   rD   rE   rl         zLmntTTSService.startc                    rk   )zTStop the LMNT TTS service.

        Args:
            frame: The end frame.
        N)r]   stop_disconnectrn   re   rD   rE   rp      ro   zLmntTTSService.stopc                    rk   )zYCancel the LMNT TTS service.

        Args:
            frame: The cancel frame.
        N)r]   cancelrq   rn   re   rD   rE   rr      ro   zLmntTTSService.cancel	directionc                    s   t  ||I dH  dS )zPush a frame downstream with special handling for stop conditions.

        Args:
            frame: The frame to push.
            direction: The direction to push the frame.
        N)r]   
push_frame)rb   rj   rs   re   rD   rE   rt      s   zLmntTTSService.push_framec                    sL   t   I dH  |  I dH  | jr"| js$| | | j| _dS dS dS )z1Connect to LMNT WebSocket and start receive task.N)r]   rm   _connect_websocket
_websocketra   create_task_receive_task_handler_report_errorrg   re   rD   rE   rm      s   zLmntTTSService._connectc                    sB   t   I dH  | jr| | jI dH  d| _|  I dH  dS )z2Disconnect from LMNT WebSocket and clean up tasks.N)r]   rq   ra   cancel_task_disconnect_websocketrg   re   rD   rE   rq      s   zLmntTTSService._disconnectdeltac                    s8   t  |I dH }|r|  I dH  |  I dH  |S )zApply a settings delta.

        Args:
            delta: A :class:`TTSSettings` (or ``LmntTTSService.Settings``) delta.

        Returns:
            Dict mapping changed field names to their previous values.
        N)r]   _update_settingsrq   rm   )rb   r|   changedre   rD   rE   r}      s   	zLmntTTSService._update_settingsc              
      s   zC| j r| j jtju rW dS td | j| jj| j	| j
| jj| jjd}tdI dH | _ | j t|I dH  | dI dH  W dS  tyq } z!| jd| |dI dH  d| _ | d| I dH  W Y d}~dS d}~ww )	zConnect to LMNT websocket.NzConnecting to LMNT)z	X-API-KeyrV   formatrP   r   rR   z&wss://api.lmnt.com/v1/ai/speech/streamon_connectedUnknown error occurred: 	error_msg	exceptionon_connection_error)rv   stater   OPENr   debugr_   rM   rV   r`   rP   r   rR   websocket_connectsendjsondumps_call_event_handler	Exception
push_error)rb   init_msgerD   rD   rE   ru     s*   

"z!LmntTTSService._connect_websocketc              
      s   zUz|   I dH  | jrtd | j I dH  W n ty: } z| jd| |dI dH  W Y d}~nd}~ww W d| _| dI dH  dS W d| _| dI dH  dS d| _| dI dH  w )zDisconnect from LMNT websocket.NzDisconnecting from LMNTzError disconnecting from LMNT: r   on_disconnected)stop_all_metricsrv   r   r   closer   r   r   )rb   r   rD   rD   rE   r{   "  s&   
&z$LmntTTSService._disconnect_websocketc                 C   s   | j r| j S td)z*Get the WebSocket connection if available.zWebsocket not connected)rv   r   rg   rD   rD   rE   _get_websocket3  s   zLmntTTSService._get_websocket
context_idc                    s<   | j r| j jtju rdS |  tddiI dH  dS )z"Flush any pending audio synthesis.NflushT)rv   r   r   CLOSEDr   r   r   r   )rb   r   rD   rD   rE   flush_audio9  s   "zLmntTTSService.flush_audioc              	      s   |   2 ze3 dH W }t|tr+|  I dH  t|| jd|  d}| |I dH  qz-t	|}d|v rW| t
 I dH  |  I dH  | jd|d  dI dH  W  dS W q tjyj   td|  Y qw 6 dS )z%Receive messages from LMNT websocket.N   )audiorP   num_channelsr   errorzError: )r   zInvalid JSON message: )r   
isinstancebytesstop_ttfb_metricsr   rP   get_active_audio_context_idrt   r   loadsr   r   r   JSONDecodeErrorr   r   )rb   messagerj   msgrD   rD   rE   _receive_messages?  s.   

z LmntTTSService._receive_messagestextc              
   C  s4  t |  d| d zq| jr| jjtju r|  I dH  z(|  t	
d|iI dH  |  t	
ddiI dH  | |I dH  W n1 tyw } z%td| dV  t|d	V  |  I dH  |  I dH  W Y d}~W dS d}~ww dV  W dS  ty } ztd| dV  W Y d}~dS d}~ww )
a  Generate TTS audio from text using LMNT's streaming API.

        Args:
            text: The text to synthesize into speech.
            context_id: The context ID for tracking audio frames.

        Yields:
            Frame: Audio frames containing the synthesized speech.
        z: Generating TTS []Nr   r   Tr   )r   )r   )r   r   rv   r   r   r   rm   r   r   r   r   start_tts_usage_metricsr   r	   r   rq   )rb   r   r   r   rD   rD   rE   run_ttsW  s,    zLmntTTSService.run_tts)N))rH   rI   rJ   rK   rG   rZ   __annotations__r   r0   strr   intr^   boolrh   ri   r   rl   r   rp   r   rr   r   
DOWNSTREAMr
   rt   rm   rq   r   dictr   r}   ru   r{   r   r   r   r   r   r   __classcell__rD   rD   re   rE   rL   S   sR   
 	K					
(rL   )*rK   r   dataclassesr   typingr   r   r   logurur   pipecat.frames.framesr   r   r	   r
   r   r   r   "pipecat.processors.frame_processorr   pipecat.services.settingsr   pipecat.services.tts_servicer   pipecat.transcriptions.languager   r   (pipecat.utils.tracing.service_decoratorsr   websockets.asyncio.clientr   r   websockets.protocolr   ModuleNotFoundErrorr   r   r   r   rF   rG   rL   rD   rD   rD   rE   <module>   s0   $	
$