
    qi B                        d Z ddlmZmZ ddl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mZmZmZmZmZ ddlmZ ddl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%Z%ddl&m'Z( ddl)m*Z* ed   Z/e G d de             Z0 G d de       Z1y# e+$ r7Z, ejZ                  de,         ejZ                  d        e.de,       dZ,[,ww xY w)zFish Audio text-to-speech service implementation.

This module provides integration with Fish Audio's real-time TTS WebSocket API
for streaming text-to-speech synthesis with customizable voice parameters.
    )	dataclassfield)AnyAsyncGeneratorLiteralMappingOptionalSelf)logger)	BaseModel)CancelFrameEndFrame
ErrorFrameFrameInterruptionFrame
StartFrameTTSAudioRawFrameTTSStoppedFrame)FrameDirection)	NOT_GIVENTTSSettings	_NotGiven_warn_deprecated_param)InterruptibleTTSService)Language)
traced_ttsN)connect)StatezException: zGIn order to use Fish Audio, you need to `pip install pipecat-ai[fish]`.zMissing module: )opusmp3pcmwavc                   >    e Zd ZU dZ ed       Zedz  ez  ed<    ed       Z	e
dz  ez  ed<    ed       Zedz  ez  ed	<    ed
       Zedz  ez  ed<    ed       Zedz  ez  ed<    ed       Zedz  ez  ed<   edeeef   def fd       Z xZS )FishAudioTTSSettingsa  Settings for FishAudioTTSService.

    Parameters:
        latency: Latency mode ("normal" or "balanced"). Defaults to "balanced".
        normalize: Whether to normalize audio output. Defaults to True.
        temperature: Controls randomness in speech generation (0.0-1.0).
        top_p: Controls diversity via nucleus sampling (0.0-1.0).
        prosody_speed: Speech speed multiplier (0.5-2.0). Defaults to 1.0.
        prosody_volume: Volume adjustment in dB (-20 to 20). Defaults to 0.
    c                      t         S Nr        K/opt/pipecat/venv/lib/python3.12/site-packages/pipecat/services/fish/tts.py<lambda>zFishAudioTTSSettings.<lambda>=       I r)   )default_factoryNlatencyc                      t         S r&   r'   r(   r)   r*   r+   zFishAudioTTSSettings.<lambda>>   s    y r)   	normalizec                      t         S r&   r'   r(   r)   r*   r+   zFishAudioTTSSettings.<lambda>?   s    ) r)   temperaturec                      t         S r&   r'   r(   r)   r*   r+   zFishAudioTTSSettings.<lambda>@   r,   r)   top_pc                      t         S r&   r'   r(   r)   r*   r+   zFishAudioTTSSettings.<lambda>A   s    I r)   prosody_speedc                      t         S r&   r'   r(   r)   r*   r+   zFishAudioTTSSettings.<lambda>B   s    9 r)   prosody_volumesettingsreturnc                     t        |      }|j                  dd      }t        |t               rB|j                  d|j	                  d             |j                  d|j	                  d             t
        |   |      S )zNConstruct settings from a plain dict, destructuring legacy nested ``prosody``.prosodyNr6   speedr8   volume)dictpop
isinstance
setdefaultgetsuperfrom_mapping)clsr9   flatnested	__class__s       r*   rE   z!FishAudioTTSSettings.from_mappingD   sg     H~)T*fd#OOOVZZ-@AOO,fjj.BCw#D))r)   )__name__
__module____qualname____doc__r   r.   strr   __annotations__r0   boolr2   floatr4   r6   r8   intclassmethodr   r   r
   rE   __classcell__rI   s   @r*   r$   r$   0   s    	 ',<M&NGS4Z)#N).?P)QItd{Y&Q,1BS,TK	)T&+<M&NE54<)#N.3DU.VM54<)+V-2CT-UNC$J*U*GCH$5 *$ * *r)   r$   c                   v    e Zd ZU dZeZeed<    G d de      Zddddddddde	d	e
e	   d
e
e	   de
e	   dede
e   de
e   de
e   f fdZdefdZdedee	ef   f fdZdef fdZdef fdZdef fdZ fdZ fdZd Zd Zd%de
e	   fdZd Zde d e!f fd!Z"d" Z#e$d#e	de	de%e&df   fd$       Z' xZ(S )&FishAudioTTSServicea  Fish Audio text-to-speech service with WebSocket streaming.

    Provides real-time text-to-speech synthesis using Fish Audio's WebSocket API.
    Supports various audio formats, customizable prosody controls, and streaming
    audio generation with interruption handling.
    	_settingsc                       e Zd ZU dZej
                  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
<   y)FishAudioTTSService.InputParamsa%  Input parameters for Fish Audio TTS configuration.

        .. deprecated:: 0.0.105
            Use ``settings=FishAudioTTSSettings(...)`` instead.

        Parameters:
            language: Language for synthesis. Defaults to English.
            latency: Latency mode ("normal" or "balanced"). Defaults to "normal".
            normalize: Whether to normalize audio output. Defaults to True.
            prosody_speed: Speech speed multiplier (0.5-2.0). Defaults to 1.0.
            prosody_volume: Volume adjustment in dB. Defaults to 0.
        languagenormalr.   Tr0         ?r6   r   r8   N)rJ   rK   rL   rM   r   ENr[   r	   rO   r.   rN   r0   rP   r6   rQ   r8   rR   r(   r)   r*   InputParamsrZ   Z   sT    	 (0{{(8$2!)#)$(	8D>(),x,())r)   r_   Nr!   )reference_idmodelmodel_idoutput_formatsample_rateparamsr9   api_keyr`   ra   rb   rc   rd   re   r9   c                   |r|rt        d      |rHddl}
|
j                         5  |
j                  d       |
j	                  dt
        d       ddd       |}t        dddd	d
dddd	      }|t        dt        d       ||_        |t        dt        d       ||_	        |t        dt               |st|j                  |j                  |_
        |j                  |j                  |_        |j                  |j                  |_        |j                  |j                  |_        ||j                  |       t        | @  dd
d
d
||d|	 || _        d| _        d| _        d| _        d| _        || _        y# 1 sw Y   /xY w)aR  Initialize the Fish Audio TTS service.

        Args:
            api_key: Fish Audio API key for authentication.
            reference_id: Reference ID of the voice model to use for synthesis.

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

            model: Deprecated. Reference ID of the voice model to use for synthesis.

                .. deprecated:: 0.0.74
                    The ``model`` parameter is deprecated and will be removed in version 0.1.0.
                    Use ``reference_id`` instead to specify the voice model.

            model_id: Specify which Fish Audio TTS model to use (e.g. "s1").

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

            output_format: Audio output format. Defaults to "pcm".
            sample_rate: Audio sample rate. If None, uses default.
            params: Additional input parameters for voice customization.

                .. deprecated:: 0.0.105
                    Use ``settings=FishAudioTTSSettings(...)`` instead.

            settings: Runtime-updatable settings. When provided alongside deprecated
                parameters, ``settings`` values take precedence.
            **kwargs: Additional arguments passed to the parent service.
        zHCannot specify both 'model' and 'reference_id'. Use 'reference_id' only.r   NalwayszdParameter 'model' is deprecated and will be removed in a future version. Use 'reference_id' instead.   )
stacklevelzs2-probalancedTr]   )	ra   voicer[   r.   r0   r2   r4   r6   r8   r`   rl   rb   ra   re   )push_stop_framespush_start_framepause_frame_processingrd   r9   z wss://api.fish.audio/v1/tts/liver(   )
ValueErrorwarningscatch_warningssimplefilterwarnDeprecationWarningr$   r   rl   ra   r.   r0   r6   r8   apply_updaterD   __init___api_key	_base_url
_websocket_receive_task_fish_sample_rate_output_format)selfrf   r`   ra   rb   rc   rd   re   r9   kwargsrq   default_settingsrI   s               r*   rw   zFishAudioTTSService.__init__n   s   Z \Z  ((* %%h/2& 	   !L 0

 #">3GQ%1"":/CWM%-" "8-AB>>-/5~~$,##/171A1A$.''35;5I5I$2((46<6K6K$3 ))(3 	
!!#'#%	
 	
  ;! "#+A s   *E>>Fr:   c                      y)zCheck if this service can generate processing metrics.

        Returns:
            True, as Fish Audio service supports metrics generation.
        Tr(   r~   s    r*   can_generate_metricsz(FishAudioTTSService.can_generate_metrics   s     r)   deltac                    K   t         |   |       d{   }|r0| j                          d{    | j                          d{    |S 7 87  7 
w)a5  Apply a settings delta and reconnect if needed.

        Any change to voice or model triggers a WebSocket reconnect.

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

        Returns:
            Dict mapping changed field names to their previous values.
        N)rD   _update_settings_disconnect_connect)r~   r   changedrI   s      r*   r   z$FishAudioTTSService._update_settings   sS      077""$$$--/!! 8 %!s1   AAAAAA	AAAframec                    K   t         |   |       d{    | j                  | _        | j	                          d{    y7 .7 w)zStart the Fish Audio TTS service.

        Args:
            frame: The start frame containing initialization parameters.
        N)rD   startrd   r|   r   r~   r   rI   s     r*   r   zFishAudioTTSService.start   sA      gmE"""!%!1!1mmo 	#s    A	A(A	A A	A	c                 t   K   t         |   |       d{    | j                          d{    y7 7 w)zZStop the Fish Audio TTS service.

        Args:
            frame: The end frame.
        N)rD   stopr   r   s     r*   r   zFishAudioTTSService.stop
  s6      gl5!!!    	"    848688c                 t   K   t         |   |       d{    | j                          d{    y7 7 w)z_Cancel the Fish Audio TTS service.

        Args:
            frame: The cancel frame.
        N)rD   cancelr   r   s     r*   r   zFishAudioTTSService.cancel  s6      gnU###    	$ r   c                   K   t         |           d {    | j                          d {    | j                  r=| j                  s0| j                  | j                  | j                              | _        y y y 7 f7 Pwr&   )rD   r   _connect_websocketrz   r{   create_task_receive_task_handler_report_errorr~   rI   s    r*   r   zFishAudioTTSService._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r&   )rD   r   r{   cancel_task_disconnect_websocketr   s    r*   r   zFishAudioTTSService._disconnect$  sf     g!###""4#5#5666!%D((*** 	$ 7 	+s3   A/A).A/A+A/#A-$A/+A/-A/c                   K   	 | j                   r'| j                   j                  t        j                  u ry t	        j
                  d       dd| j                   i}| j                  j                  |d<   t        | j                  |       d {   | _         | j                  | j                  j                  | j                  | j                  j                  | j                  j                  | j                  j                   d| j                  j"                  d}| j                  j$                  | j                  j$                  |d<   | j                  j&                  | j                  j&                  |d	<   d
ddi|d}| j                   j)                  t+        j,                  |             d {    t	        j
                  d       | j/                  d       d {    y 7 Z7 67 
# t0        $ rL}| j3                  d| |       d {  7   d | _         | j/                  d|        d {  7   Y d }~y d }~ww xY ww)NzConnecting to Fish AudioAuthorizationzBearer ra   )additional_headers)r=   r>   )rd   r.   formatr0   r<   r`   r2   r4   r   text )eventrequestz Sent start message to Fish Audioon_connectedUnknown error occurred: 	error_msg	exceptionon_connection_error)rz   stater   OPENr   debugrx   rX   ra   websocket_connectry   r|   r.   r}   r0   r6   r8   rl   r2   r4   send	ormsgpackpackb_call_event_handler	Exception
push_error)r~   headersrequest_settingsstart_messagees        r*   r   z&FishAudioTTSService._connect_websocket-  s    !	J4??#8#8EJJ#FLL34&'$--(ABG#~~33GG$5dnnY`$aaDO  $55>>11--!^^55!^^99"nn;; !% 4 4
  ~~))526..2L2L /~~##/,0NN,@,@ )&-62:ZIY:Z[M//&&y}'EFFFLL;<**>:::- b& G ; 	J//.Fqc,JVW/XXX"DO**+@QCIII	Js   I	2G1 I	AG1 G*D%G1 6G-7-G1 $G/%G1 )I	*G1 -G1 /G1 1	I:IH"I6H97I<I	II	c                 >  K   	 | j                          d {    | j                  rqt        j                  d       ddi}| j                  j	                  t        j                  |             d {    | j                  j                          d {    d | _        | j                  d       d {    y 7 7 I7 )# t        $ r)}| j                  d| |       d {  7   Y d }~Td }~ww xY w7 @# d | _        | j                  d       d {  7   w xY ww)NzDisconnecting from Fish Audior   r   r   r   on_disconnected)stop_all_metricsrz   r   r   r   r   r   closer   r   r   )r~   stop_messager   s      r*   r   z)FishAudioTTSService._disconnect_websocketQ  s     	>'')))<= '0oo**9??<+HIIIoo++--- #DO**+<=== *
 J- 	Y//.Fqc,JVW/XXX	Y > #DO**+<===s   DC  B:AC  2B<3!C  B>C  D4C55D:C  <C  >C   	C2	C-"C%#C-(C7 -C22C7 5D7DDDD
context_idc                 "  K   t        j                  |  d       | j                  r&| j                  j                  t        j
                  u ryddi}| j                         j                  t        j                  |             d{    y7 w)z@Flush any buffered audio by sending a flush event to Fish Audio.z: Flushing audio buffersNr   flush)
r   tracerz   r   r   CLOSED_get_websocketr   r   r   )r~   r   flush_messages      r*   flush_audiozFishAudioTTSService.flush_audio`  si     v567$//"7"75<<"G '*!!#(()GHHHs   BBBBc                 H    | j                   r| j                   S t        d      )NzWebsocket not connected)rz   r   r   s    r*   r   z"FishAudioTTSService._get_websocketh  s    ????"122r)   	directionc                 v   K   t         |   ||       d {    | j                          d {    y 7 7 wr&   )rD   _handle_interruptionr   )r~   r   r   rI   s      r*   r   z(FishAudioTTSService._handle_interruptionm  s7     g*5)<<<##%%% 	=%s   959799c                   K   | j                         2 3 d {   }	 t        |t              rt        j                  |      }t        |t
              r|j                  d      }|dk(  rj|j                  d      }|rt        |      dkD  rt        || j                  d      }| j                  |       d {    | j                          d {    nO|dk(  rJ|j                  dd      }|dk(  r| j                  d	
       d {    nt        j                  d|        7 7 q7 [7 &# t        $ r*}| j                  d| |       d {  7   Y d }~Gd }~ww xY w6 y w)Nr   audioi      finishreasonunknownerrorz(Fish Audio server error during synthesis)r   zFish Audio session finished: r   r   )r   rA   bytesr   unpackbr?   rC   lenr   rd   
push_framestop_ttfb_metricsr   r   r   r   )r~   messagemsgr   
audio_datar   r   r   s           r*   _receive_messagesz%FishAudioTTSService._receive_messagesq  sX    !002 	] 	]']gu-#++G4C!#t, # 0 G+),)9J)c*o.D(8TEUEUWX(Y&*ooe&< < <&*&<&<&> > >"h.%(WWXy%AF%0&*oo.X '6 '" !" !" !'/LVH-U V)	] != >!"  ]oo2J1#0NZ[o\\\]- 3s   E$E"D#E"E$BD,4D&5D,D(6D,D*D,!E$#E"&D,(D,*D,,	E5EEEE$EE$r   c                B  K   t        j                  |  d| d       	 | j                  r&| j                  j                  t        j
                  u r| j                          d{    d|d}	 | j                         j                  t        j                  |             d{    | j                  |       d{    ddi}| j                         j                  t        j                  |             d{    d y7 7 c7 L7 # t        $ r]}t        d| 	       t        |
       | j                          d{  7   | j                          d{  7   Y d}~od}~ww xY w# t        $ r}t        d| 	       Y d}~yd}~ww xY ww)a+  Generate speech from text using Fish Audio's streaming API.

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

        Yields:
            Frame: Audio frames and control frames for the synthesized speech.
        z: Generating Fish TTS: []Nr   )r   r   r   r   r   )r   )r   )r   r   rz   r   r   r   r   r   r   r   r   start_tts_usage_metricsr   r   r   r   )r~   r   r   text_messager   r   s         r*   run_ttszFishAudioTTSService.run_tts  sh     	v5dV1=>	C??doo&;&;u||&Kmmo%%  L&))+001NOOO224888 ")' 2))+001OPPP J) & P8 Q & )A!'EFF%<<&&(((mmo%%	&  	C%=aS#ABBB	Cs   FAE7 $D%	E7 /5D $D%D =D
>=D ;D<D  E7 FE7 D 
D D 	E44E/EE/$E'%E/*E7 /E44E7 7	F FFFFr&   ))rJ   rK   rL   rM   r$   SettingsrO   r   r_   rN   r	   FishAudioOutputFormatrR   rw   rP   r   r   r?   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rT   rU   s   @r*   rW   rW   O   s}    $H##*i *0 '+#"&/4%)(,37u, u, sm	u,
 }u, 3-u, -u, c]u, %u, /0u,nd K DcN & ! !!+ !b+"JH>IHSM I3
&0A &n &]4 $C# $C3 $C>%QU+;V $C $Cr)   rW   )2rM   dataclassesr   r   typingr   r   r   r   r	   r
   logurur   pydanticr   pipecat.frames.framesr   r   r   r   r   r   r   r   "pipecat.processors.frame_processorr   pipecat.services.settingsr   r   r   r   pipecat.services.tts_servicer   pipecat.transcriptions.languager   (pipecat.utils.tracing.service_decoratorsr   r   websockets.asyncio.clientr   r   websockets.protocolr   ModuleNotFoundErrorr   r   r   r   r$   rW   r(   r)   r*   <module>r      s    ) H H  	 	 	 > _ _ @ 4 ?,F)   ;<  *; * *<aC1 aCQ  ,FLL;qc"#FLLZ[
&qc*
++,s    B C2CC