
    qih0                        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mZ dd	lmZ dd
lmZmZ ddlmZ 	 ddlmZ  ddl!m"Z" dedee'   fdZ(e G d de             Z) G d de      Z*y# e#$ r7Z$ e	jJ                  de$         e	jJ                  d        e&de$       dZ$[$ww xY w)z+LMNT text-to-speech service implementation.    N)	dataclass)AnyAsyncGeneratorOptional)logger)CancelFrameEndFrame
ErrorFrameFrame
StartFrameTTSAudioRawFrameTTSStoppedFrame)FrameDirection)TTSSettings_warn_deprecated_param)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           	         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      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_MAPs     K/opt/pipecat/venv/lib/python3.12/site-packages/pipecat/services/lmnt/tts.pylanguage_to_lmnt_languagerH   (   sQ   TT 	T 	T	
 	T 	T 	T 	T 	T 	T 	T 	T 	T 	T 	T  	T!" 	T#$ 	TTTT+L0 Hl$GG    c                       e Zd ZdZy)LmntTTSSettingszSettings for LmntTTSService.N)__name__
__module____qualname____doc__ rI   rG   rK   rK   L   s    &rI   rK   c                       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ZdefdZd	ede
e	   fdZdef fdZdef fdZdef fdZej.                  fdedef fdZ fdZ fdZdedee	ef   f fdZd Z d Z!d Z"d#de
e	   fdZ#d  Z$e%d!e	de	de&edf   fd"       Z' xZ(S )$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_keyrU   rV   r   rW   rX   rY   c          	      "   t        dd| j                  |            }	|t        dt         d       ||	_        |t        dt         d       ||	_        ||	j                  |       t        
|   d	ddd||	d| || _        || _	        d| _
        y)
a  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=LmntTTSSettings(voice=...)`` instead.

            sample_rate: Audio sample rate. If None, uses default.
            language: Language for synthesis. Defaults to English.
            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=LmntTTSSettings(model=...)`` instead.

            settings: Runtime-updatable settings. When provided alongside deprecated
                parameters, ``settings`` values take precedence.
            **kwargs: Additional arguments passed to parent InterruptibleTTSService.
        auroraN)rX   voicer   rU   r]   rX   T)push_stop_framespush_start_framepause_frame_processingrV   rY   rP   )rK   language_to_service_languager   r]   rX   apply_updatesuper__init___api_key_output_format_receive_task)selfrZ   rU   rV   r   rW   rX   rY   kwargsdefault_settings	__class__s             rG   rd   zLmntTTSService.__init__^   s    F +66x@
 ":H%-""7OWE%*"
 ))(3 	
!!#'#%	
 	
  +!rI   r   c                      y)zCheck if this service can generate processing metrics.

        Returns:
            True, as LMNT service supports metrics generation.
        TrP   rh   s    rG   can_generate_metricsz#LmntTTSService.can_generate_metrics   s     rI   c                     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.
        )rH   )rh   r   s     rG   ra   z+LmntTTSService.language_to_service_language   s     )22rI   framec                 t   K   t         |   |       d{    | j                          d{    y7 7 w)z|Start the LMNT TTS service.

        Args:
            frame: The start frame containing initialization parameters.
        N)rc   start_connectrh   rp   rk   s     rG   rr   zLmntTTSService.start   s3      gmE"""mmo 	#   848688c                 t   K   t         |   |       d{    | j                          d{    y7 7 w)zTStop the LMNT TTS service.

        Args:
            frame: The end frame.
        N)rc   stop_disconnectrt   s     rG   rw   zLmntTTSService.stop   s6      gl5!!!    	" ru   c                 t   K   t         |   |       d{    | j                          d{    y7 7 w)zYCancel the LMNT TTS service.

        Args:
            frame: The cancel frame.
        N)rc   cancelrx   rt   s     rG   rz   zLmntTTSService.cancel   s6      gnU###    	$ ru   	directionc                 B   K   t         |   ||       d{    y7 w)zPush a frame downstream with special handling for stop conditions.

        Args:
            frame: The frame to push.
            direction: The direction to push the frame.
        N)rc   
push_frame)rh   rp   r{   rk   s      rG   r}   zLmntTTSService.push_frame   s      g 	222s   c                   K   t         |           d{    | j                          d{    | j                  r=| j                  s0| j                  | j                  | j                              | _        yyy7 f7 Pw)z1Connect to LMNT WebSocket and start receive task.N)rc   rs   _connect_websocket
_websocketrg   create_task_receive_task_handler_report_errorrh   rk   s    rG   rs   zLmntTTSService._connect   sm     g   %%'''??4#5#5!%!1!1$2L2LTM_M_2`!aD $6?	 	!'s    B A<B A>AB >B c                    K   t         |           d{    | j                  r*| j                  | j                         d{    d| _        | j	                          d{    y7 S7 &7 	w)z2Disconnect from LMNT WebSocket and clean up tasks.N)rc   rx   rg   cancel_task_disconnect_websocketr   s    rG   rx   zLmntTTSService._disconnect   sf     g!###""4#5#5666!%D((*** 	$ 7 	+s3   A/A).A/A+A/#A-$A/+A/-A/deltac                    K   t         |   |       d{   }|r0| j                          d{    | j                          d{    |S 7 87  7 
w)zApply a settings delta.

        Args:
            delta: A :class:`TTSSettings` (or ``LmntTTSSettings``) delta.

        Returns:
            Dict mapping changed field names to their previous values.
        N)rc   _update_settingsrx   rs   )rh   r   changedrk   s      rG   r   zLmntTTSService._update_settings   sS      077""$$$--/!! 8 %!s1   AAAAAA	AAAc                   K   	 | j                   r'| j                   j                  t        j                  u ryt	        j
                  d       | j                  | j                  j                  | j                  | j                  | j                  j                  | j                  j                  d}t        d       d{   | _         | j                   j                  t        j                   |             d{    | j#                  d       d{    y7 Y7  7 	# t$        $ rL}| j'                  d| |       d{  7   d| _         | j#                  d|        d{  7   Y d}~yd}~ww xY ww)	zConnect to LMNT websocket.NzConnecting to LMNT)z	X-API-Keyr]   formatrV   r   rX   z&wss://api.lmnt.com/v1/ai/speech/streamon_connectedUnknown error occurred: 	error_msg	exceptionon_connection_error)r   stater   OPENr   debugre   rS   r]   rf   rV   r   rX   websocket_connectsendjsondumps_call_event_handler	Exception
push_error)rh   init_msges      rG   r   z!LmntTTSService._connect_websocket   s*    	J4??#8#8EJJ#FLL-. "]]----#// NN33--H %66^$__DO //&&tzz(';<<<**>::: ` =: 	J//.Fqc,JVW/XXX"DO**+@QCIII	Js   E52D E5BD =D>:D 8D9D DD E5D D D 	E2&E-?E "E-"E%#E-(E5-E22E5c                   K   	 | j                          d{    | j                  r7t        j                  d       | j                  j	                          d{    d| _        | j                  d       d{    y7 h7 '# t
        $ r)}| j                  d| |       d{  7   Y d}~Rd}~ww xY w7 ># d| _        | j                  d       d{  7   w xY ww)zDisconnect from LMNT websocket.NzDisconnecting from LMNTzError disconnecting from LMNT: r   on_disconnected)stop_all_metricsr   r   r   closer   r   r   )rh   r   s     rG   r   z$LmntTTSService._disconnect_websocket  s     	>'')))67 oo++--- #DO**+<=== * . 	`//.MaS,Q]^/___	` > #DO**+<===s   C!B B AB BB C!:B9;C! B B 	B6B1&B)'B1,B; 1B66B; 9C!;CCCC!c                 H    | j                   r| j                   S t        d      )z*Get the WebSocket connection if available.zWebsocket not connected)r   r   rm   s    rG   _get_websocketzLmntTTSService._get_websocket,  s    ????"122rI   
context_idc                    K   | j                   r&| j                   j                  t        j                  u ry| j	                         j                  t        j                  ddi             d{    y7 w)z"Flush any pending audio synthesis.NflushT)r   r   r   CLOSEDr   r   r   r   )rh   r   s     rG   flush_audiozLmntTTSService.flush_audio2  sO     $//"7"75<<"G!!#((WdO)DEEEs   A+A5-A3.A5c                 z  K   | j                         2 3 d{   }t        |t              rY| j                          d{    t	        || j
                  d| j                               }| j                  |       d{    r	 t        j                  |      }d|v r[| j                  t                      d{    | j                          d{    | j                  d|d           d{     y7 7 7 7 E7 /7 # t        j                  $ r t        j                  d|        Y "w xY w6 yw)z%Receive messages from LMNT websocket.N   )audiorV   num_channelsr   errorzError: )r   zInvalid JSON message: )r   
isinstancebytesstop_ttfb_metricsr   rV   get_active_audio_context_idr}   r   loadsr   r   r   JSONDecodeErrorr   r   )rh   messagerp   msgs       rG   _receive_messagesz LmntTTSService._receive_messages8  s/    !002 	E 	E''5),,...(! $ 0 0!"#??A	 ooe,,,E**W-C#~"ooo.?@@@"33555"oo'#g,8PoQQQ	 &	E / -
 A5Q++ ELL#9'!CDE' 3s   D;D9C;D9$D;C= ?D;?C? D;5D;D<DDD3D4D8D;;D9=D;?D;DDD+D62D;5D66D;textc                8  K   t        j                  |  d| d       	 | j                  r&| j                  j                  t        j
                  u r| j                          d{    	 | j                         j                  t        j                  d|i             d{    | j                         j                  t        j                  ddi             d{    | j                  |       d{    d y7 7 a7 '7 # t        $ r]}t        d|        t        |	       | j                          d{  7   | j                          d{  7   Y d}~yd}~ww xY w# t        $ r}t        d|        Y d}~yd}~ww xY 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   r   r   r   r   rs   r   r   r   r   start_tts_usage_metricsr   r
   r   rx   )rh   r   r   r   s       rG   run_ttszLmntTTSService.run_ttsP  sU     	v/vQ78	C??doo&;&;u||&Kmmo%%))+00VTN1KLLL))+00WdO1LMMM224888 J & MM8  )A!'EFF%<<&&(((mmo%%  	C%=aS#ABBB	Cs   FAE2 $D%E2 *7D	 !D";D	 DD	 6D7D	 ;E2  FE2 D	 D	 D	 		E/4E*E	E*E" E*%E2 )F*E//E2 2	F;FFFF)N))rL   rM   rN   rO   rK   Settings__annotations__r   r3   strr   intrd   boolrn   ra   r   rr   r	   rw   r   rz   r   
DOWNSTREAMr   r}   rs   rx   r   dictr   r   r   r   r   r   r   r   r   r   __classcell__)rk   s   @rG   rR   rR   S   s    H #'%)%[[(#.2B" B" 3-	B"
 c]B" B" B" }B" ?+B"Hd 	3X 	3(3- 	3 ! !!+ ! JXIbIb 3e 3 3b+K DcN "J<>"3FHSM FE0 C# C3 C>%QU+;V C CrI   rR   )+rO   r   dataclassesr   typingr   r   r   logurur   pipecat.frames.framesr   r	   r
   r   r   r   r   "pipecat.processors.frame_processorr   pipecat.services.settingsr   r   pipecat.services.tts_servicer   pipecat.transcriptions.languager   r   (pipecat.utils.tracing.service_decoratorsr   websockets.asyncio.clientr   r   websockets.protocolr   ModuleNotFoundErrorr   r   r   r   rH   rK   rR   rP   rI   rG   <module>r      s    2  ! 0 0    > I @ F ?,F)!H !HXc] !HH 	k 	 	\C, \Cc  ,FLL;qc"#FLLTU
&qc*
++,s   B C
2B<<C