o
    i7`                  
   @   s|  d Z ddlZddlZddlZddlmZ ddl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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mZmZ ddlm Z m!Z! ddl"m#Z# zddl$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Z0G dd deZ1G dd deZ2dS )z-Async text-to-speech service implementations.    N)	dataclass)AnyAsyncGeneratorOptional)logger)	BaseModel)CancelFrameEndFrame
ErrorFrameFrame
StartFrameTTSAudioRawFrameTTSStoppedFrame)FrameDirection)TTSSettings)TextAggregationMode
TTSServiceWebsocketTTSService)Languageresolve_language)
traced_tts)connect)StatezException: zEIn order to use Async, you need to `pip install pipecat-ai[asyncai]`.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| |ddS )zConvert a Language enum to Async language code.

    Args:
        language: The Language enum value to convert.

    Returns:
        The corresponding Async language code, or None if not supported.
    enfresdeitptnlarrurojahehytrhizhT)use_base_code)r   ENFRESDEITPTNLARRUROJAHEHYTRHIZHr   )r   LANGUAGE_MAP r=   P/home/ubuntu/.local/lib/python3.10/site-packages/pipecat/services/asyncai/tts.pylanguage_to_async_language,   sD   		
r?   c                   @   s   e Zd ZdZdS )AsyncAITTSSettingsz9Settings for AsyncAITTSService and AsyncAIHttpTTSService.N)__name__
__module____qualname____doc__r=   r=   r=   r>   r@   K   s    r@   c                       s  e Zd ZU dZeZeed< G dd deZddddddd	ddddd
de	de
e	 de	de	de
e	 de
e de	de	de
e de
e de
e de
e f fddZdedee	ef f fddZdefddZdede
e	 fd d!ZdKd$e	d%e	d&ed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 fd0d1Z fd2d3Zd4d5 Zd6d7 Z d8d9 Z!dLd%e
e	 fd:d;Z"e#j$fd)e%d<e#f fd=d>Z&d?d@ Z'dAdB Z(d%e	fdCdDZ)d%e	fdEdFZ*d%e	fdGdHZ+e,d$e	d%e	de-e%df fdIdJZ.  Z/S )MAsyncAITTSServiceztAsync TTS service with WebSocket streaming.

    Provides text-to-speech using Async's streaming WebSocket API.
    	_settingsc                   @   "   e Zd ZU dZdZee ed< dS )zAsyncAITTSService.InputParamsa  Input parameters for Async TTS configuration.

        .. deprecated:: 0.0.105
            Use ``AsyncAITTSService.Settings`` directly via the ``settings`` parameter instead.

        Parameters:
            language: Language to use for synthesis.
        Nr   rA   rB   rC   rD   r   r   r   __annotations__r=   r=   r=   r>   InputParams[      
 	rJ   Nv1z/wss://api.async.com/text_to_speech/websocket/ws	pcm_s16leraw)voice_idversionurlmodelsample_rateencoding	containerparamssettingsaggregate_sentencestext_aggregation_modeapi_keyrO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rY   c             
      s   | j dddd}|dur| dd ||_|dur"| dd ||_|	dur1| d |
s1|	j|_|
dur:||
 t jd||d|dd|d	| || _|| _	|| _
|| _|| _d
| _d| _d| _dS )a  Initialize the Async TTS service.

        Args:
            api_key: Async API key.
            voice_id: UUID of the voice to use for synthesis. See docs for a full list:
                https://docs.async.com/list-voices-16699698e0

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

            version: Async API version.
            url: WebSocket URL for Async TTS API.
            model: TTS model to use (e.g., "async_flash_v1.0").

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

            sample_rate: Audio sample rate.
            encoding: Audio encoding format.
            container: Audio container format.
            params: Additional input parameters for voice customization.

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

            settings: Runtime-updatable settings. When provided alongside deprecated
                parameters, ``settings`` values take precedence.
            aggregate_sentences: Deprecated. Use text_aggregation_mode instead.

                .. deprecated:: 0.0.104
                    Use ``text_aggregation_mode`` instead.

            text_aggregation_mode: How to aggregate text before synthesis.
            **kwargs: Additional arguments passed to the parent service.
        async_flash_v1.0NrR   voicer   rO   r]   rR   rV   T)rX   rY   pause_frame_processingrS   push_start_framepush_stop_framesrW   r   r=   )Settings"_warn_init_param_moved_to_settingsr]   rR   r   apply_updatesuper__init___api_key_api_version_url_output_container_output_encoding_output_sample_rate_receive_task_keepalive_task)selfrZ   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rY   kwargsdefault_settings	__class__r=   r>   re   g   sH   5


zAsyncAITTSService.__init__deltar   c                    s*   t  |I dH }|s|S | | |S )zgApply a settings delta.

        Settings are stored but not applied to the active connection.
        N)rd   _update_settings _warn_unhandled_updated_settings)rn   rs   changedrq   r=   r>   rt      s   
z"AsyncAITTSService._update_settingsc                 C      dS )zCheck if this service can generate processing metrics.

        Returns:
            True, as Async service supports metrics generation.
        Tr=   rn   r=   r=   r>   can_generate_metrics      z&AsyncAITTSService.can_generate_metricsr   c                 C      t |S zConvert a Language enum to Async language format.

        Args:
            language: The language to convert.

        Returns:
            The Async-specific language code, or None if not supported.
        r?   rn   r   r=   r=   r>   language_to_service_language      	z.AsyncAITTSService.language_to_service_language Ftext
context_idforcec                 C   s   |||d}t |S )N)
transcriptr   r   )jsondumps)rn   r   r   r   msgr=   r=   r>   
_build_msg   s   
zAsyncAITTSService._build_msgframec                    s.   t  |I dH  | j| _|  I dH  dS )z}Start the Async TTS service.

        Args:
            frame: The start frame containing initialization parameters.
        N)rd   startrS   rk   _connectrn   r   rq   r=   r>   r      s   zAsyncAITTSService.startc                    &   t  |I dH  |  I dH  dS )zUStop the Async TTS service.

        Args:
            frame: The end frame.
        N)rd   stop_disconnectr   rq   r=   r>   r         zAsyncAITTSService.stopc                    r   )zZCancel the Async TTS service.

        Args:
            frame: The cancel frame.
        N)rd   cancelr   r   rq   r=   r>   r     r   zAsyncAITTSService.cancelc                    sh   t   I d H  |  I d H  | jr | js | | | j| _| jr0| js2| | 	 | _d S d S d S N)
rd   r   _connect_websocket
_websocketrl   create_task_receive_task_handler_report_errorrm   _keepalive_task_handlerrx   rq   r=   r>   r     s   zAsyncAITTSService._connectc                    s`   t   I d H  | jr| | jI d H  d | _| jr'| | jI d H  d | _|  I d H  d S r   )rd   r   rl   cancel_taskrm   _disconnect_websocketrx   rq   r=   r>   r     s   zAsyncAITTSService._disconnectc              
      s  zT| j r| j jtju rW d S td t| j d| j d| j	 I d H | _ | j
jd| j
jd| j| j| jd| j
jd}|  t|I d H  | dI d H  W d S  ty } z!| jd	| |d
I d H  d | _ | d| I d H  W Y d }~d S d }~ww )NzConnecting to Asyncz	?api_key=z	&version=idmoder   rU   rT   rS   )model_idr]   output_formatr   on_connectedUnknown error occurred: 	error_msg	exceptionon_connection_error)r   stater   OPENr   debugwebsocket_connectrh   rf   rg   rF   rR   r]   ri   rj   rk   r   _get_websocketsendr   r   _call_event_handler	Exception
push_error)rn   init_msger=   r=   r>   r   $  s0   
"z$AsyncAITTSService._connect_websocketc              
      s  zzz0|   I d H  | jr1td |  r$| jtddiI d H  | j I d H  td W n t	yQ } z| j
d| |dI d H  W Y d }~nd }~ww W d | _|  I d H  | dI d H  d S W d | _|  I d H  | dI d H  d S d | _|  I d H  | dI d H  w )NzDisconnecting from Async	terminateTzDisconnected from Asyncr   r   on_disconnected)stop_all_metricsr   r   r   has_active_audio_contextr   r   r   closer   r   remove_active_audio_contextr   )rn   r   r=   r=   r>   r   ?  s2   

&z'AsyncAITTSService._disconnect_websocketc                 C   s   | j r| j S td)NzWebsocket not connected)r   r   rx   r=   r=   r>   r   Q  s   z AsyncAITTSService._get_websocketc                    sR   |p|   }|r| jsdS t|  d | jd|dd}| j|I dH  dS )zFlush any pending audio.

        Args:
            context_id: The specific context to flush. If None, falls back to the
                currently active context.
        Nz: flushing audio T)r   r   r   )get_active_audio_context_idr   r   tracer   r   )rn   r   flush_idr   r=   r=   r>   flush_audioV  s   
zAsyncAITTSService.flush_audio	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)rd   
push_frame)rn   r   r   rq   r=   r>   r   d  s   zAsyncAITTSService.push_framec                    s   |   2 zm3 d H W }t|}|sq|d}|ddu r(td|  q| |sM|  |krDtd|  | 	|I d H  n	td|  q|drr| 
 I d H  t|d }t|| jd|d	}| ||I d H  q6 d S )
Nr   finalTz#Received final message for context z4Received a delayed message, recreating the context: z+Ignoring message from unavailable context: audio   r   )r   r   loadsgetr   r   audio_context_availabler   r   create_audio_contextstop_ttfb_metricsbase64	b64decoder   rS   append_to_audio_context)rn   messager   received_ctx_idr   r   r=   r=   r>   _receive_messagesm  s0   



z#AsyncAITTSService._receive_messagesc              
      s   d}	 t |I dH  z2| jr=| jjtju r=|  }|r(d|d}td n	ddi}td | j	t
|I dH  W n tjy\ } zt|  d	|  W Y d}~dS d}~ww q)
zBSend periodic keepalive messages to maintain WebSocket connection.
   TNr   )r   r   zSending keepalive messager   z!Sending keepalive without contextz keepalive error: )asynciosleepr   r   r   r   r   r   r   r   r   r   
websocketsConnectionClosedwarning)rn   KEEPALIVE_SLEEPr   keepalive_messager   r=   r=   r>   r     s,   
z)AsyncAITTSService._keepalive_task_handlerc              
      s|   |r:| j r<z| j t|dddI d H  W d S  ty9 } zt|  d| d|  W Y d }~d S d }~ww d S d S )NTr   )r   close_contextr   z: Error closing context : )r   r   r   r   r   r   error)rn   r   r   r=   r=   r>   _close_context  s   
(z AsyncAITTSService._close_contextc                       |  |I dH  dS )z7Close the Async AI context when the bot is interrupted.Nr   rn   r   r=   r=   r>   on_audio_context_interrupted  s   z.AsyncAITTSService.on_audio_context_interruptedc                    r   )a  Close the Async AI context after all audio has been played.

        Async AI does not send a server-side signal when a context is
        exhausted, so Pipecat must explicitly close it with
        ``close_context: True`` to free server-side resources.
        Nr   r   r=   r=   r>   on_audio_context_completed  s   z,AsyncAITTSService.on_audio_context_completedc              
   C  s   t |  d| d zW| jr| jjtju r|  I dH  z| j|d|d}|  	|I dH  | 
|I dH  W n# ty] } ztd| dV  t|dV  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 speech from text using Async API websocket endpoint.

        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.
        : Generating TTS []NT)r   r   r   r   )r   r   )r   r   r   r   r   CLOSEDr   r   r   r   start_tts_usage_metricsr   r
   r   )rn   r   r   r   r   r=   r=   r>   run_tts  s(    zAsyncAITTSService.run_tts)r   r   Fr   )0rA   rB   rC   rD   r@   ra   rI   r   rJ   strr   intboolr   re   r   dictr   rt   ry   r   r   r   r   r   r	   r   r   r   r   r   r   r   r   r   r   
DOWNSTREAMr   r   r   r   r   r   r   r   r   r   __classcell__r=   r=   rq   r>   rE   R   s|   
 	
d
			"	(rE   c                       s   e Zd ZU dZeZeed< G dd deZddddddd	ddd
	de	de
e	 dejde
e	 de	d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ed!e	d"e	deedf fd#d$Z  ZS )%AsyncAIHttpTTSServicezHTTP-based Async TTS service.

    Provides text-to-speech using Async's HTTP streaming API for simpler,
    non-WebSocket integration. Suitable for use cases where streaming WebSocket
    connection is not required or desired.
    rF   c                   @   rG   )z!AsyncAIHttpTTSService.InputParamszInput parameters for Async API.

        .. deprecated:: 0.0.105
            Use ``AsyncAIHttpTTSService.Settings`` directly via the ``settings`` parameter instead.

        Parameters:
            language: Language to use for synthesis.
        Nr   rH   r=   r=   r=   r>   rJ     rK   rJ   Nzhttps://api.async.comrL   rM   rN   )	rO   rR   rQ   rP   rS   rT   rU   rV   rW   rZ   rO   aiohttp_sessionrR   rQ   rP   rS   rT   rU   rV   rW   c                   s   | j dddd}|dur| dd ||_|dur"| dd ||_|
dur1| d |s1|
j|_|dur:|| t jd|dd|d	| || _|| _	|| _
|	| _|| _d
| _|| _dS )a  Initialize the Async TTS service.

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

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

            aiohttp_session: An aiohttp session for making HTTP requests.
            model: TTS model to use (e.g., "async_flash_v1.0").

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

            url: Base URL for Async API.
            version: API version string for Async API.
            sample_rate: Audio sample rate.
            encoding: Audio encoding format.
            container: Audio container format.
            params: Additional input parameters for voice customization.

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

            settings: Runtime-updatable settings. When provided alongside deprecated
                parameters, ``settings`` values take precedence.
            **kwargs: Additional arguments passed to the parent TTSService.
        r[   Nr\   rO   r]   rR   rV   T)rS   r_   r`   rW   r   r=   )ra   rb   r]   rR   r   rc   rd   re   rf   	_base_urlrg   ri   rj   rk   _session)rn   rZ   rO   r   rR   rQ   rP   rS   rT   rU   rV   rW   ro   rp   rq   r=   r>   re     s@   .


zAsyncAIHttpTTSService.__init__r   c                 C   rw   )zCheck if this service can generate processing metrics.

        Returns:
            True, as Async HTTP service supports metrics generation.
        Tr=   rx   r=   r=   r>   ry   O  rz   z*AsyncAIHttpTTSService.can_generate_metricsr   c                 C   r{   r|   r}   r~   r=   r=   r>   r   W  r   z2AsyncAIHttpTTSService.language_to_service_languager   c                    s    t  |I dH  | j| _dS )zStart the Async HTTP TTS service.

        Args:
            frame: The start frame containing initialization parameters.
        N)rd   r   rS   rk   r   rq   r=   r>   r   b  s   zAsyncAIHttpTTSService.startr   r   c              
   C  s  t |  d| d zzd| jjd}| jj||| j| j| jd| jjd}| j	| j
dd}| j d	}| jj|||d
4 I dH R}|jdkrg| I dH }| jd| dI dH  td|j d| t }	|jd2 z3 dH W }
|
syqp|  I dH  |	|
 qp6 t|	}W d  I dH  n1 I dH sw   Y  | |I dH  t|| jd|d}|V  W n ty } z| jd| |dI dH  W Y d}~nd}~ww W |  I dH  dS W |  I dH  dS |  I dH  w )a  Generate speech from text using Async's HTTP 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.
        r   r   r   r   r   )r   r   r]   r   r   zapplication/json)rP   z	x-api-keyzContent-Typez/text_to_speech/streaming)r   headersN   zAsync API error: )r   zAsync API returned status r   i   r   )r   rS   num_channelsr   r   r   )r   r   rF   r]   rR   ri   rj   rk   r   rg   rf   r   r   poststatusr   r   r   	bytearraycontentiter_chunkedr   extendbytesr   r   rS   )rn   r   r   voice_configpayloadr   rQ   response
error_textbufferchunk
audio_datar   r   r=   r=   r>   r   k  s`   

(
&"zAsyncAIHttpTTSService.run_tts)rA   rB   rC   rD   r@   ra   rI   r   rJ   r   r   aiohttpClientSessionr   re   r   ry   r   r   r   r   r   r   r   r   r   r=   r=   rq   r>   r     sT   
 	
Y	(r   )3rD   r   r   r   dataclassesr   typingr   r   r   r   logurur   pydanticr   pipecat.frames.framesr   r	   r
   r   r   r   r   "pipecat.processors.frame_processorr   pipecat.services.settingsr   pipecat.services.tts_servicer   r   r   pipecat.transcriptions.languager   r   (pipecat.utils.tracing.service_decoratorsr   r   websockets.asyncio.clientr   r   websockets.protocolr   ModuleNotFoundErrorr   r   r   r   r?   r@   rE   r   r=   r=   r=   r>   <module>   sB   $	
   