
    %ui|                        d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	  ej                  e      Ze G d d             Z G d d	      Zy)
a  TTS client for CosyVoice3 Singlish TTS server.

Sends text to the TTS HTTP endpoint and returns the streaming WAV response
as raw bytes.  The orchestrator can then forward the audio to the dashboard
for operator-side playback and/or to the robot's speaker on the Ghost PC.
    )annotationsN)	dataclassfield)Optionalc                  >    e Zd ZU dZ ed       Zded<   dZded<   y	)
	TTSConfigzConfiguration for the TTS client.

    Attributes:
        endpoint: Full URL for the TTS REST endpoint.
        timeout_s: Request timeout in seconds (covers full streaming response).
    c                 .    t        j                  dd      S )NTTS_ENDPOINTz!http://kluster.klass.dev:8200/tts)osgetenv     G/home/nelsen/Projects/kognitive/orchestrator/src/services/tts_client.py<lambda>zTTSConfig.<lambda>   s    		?!
 r   )default_factorystrendpoint   int	timeout_sN)__name__
__module____qualname____doc__r   r   __annotations__r   r   r   r   r   r      s+     
Hc 
 Isr   r   c                  ,    e Zd ZdZdddZdd	dZd
dZy)	TTSClienta  Async HTTP client for the CosyVoice3 TTS server.

    Usage::

        client = TTSClient()
        wav_bytes = await client.speak("Hello, are you okay?")
        if wav_bytes:
            # wav_bytes contains the raw WAV audio data
            ...
        await client.close()

    The TTS server (POST /tts) accepts::

        {"text": "...", "sample_rate": 16000}

    and responds with a streaming ``audio/wav`` response.  The client
    collects the full stream and returns it as ``bytes`` (or ``None``
    on failure).
    Nc                8    |xs
 t               | _        d | _        y N)r   config_session)selfr    s     r   __init__zTTSClient.__init__8   s    +	*.r   c                  K   |st         j                  d       y	 ddl}| j
                  |j                         | _        	 |j                  | j                  j                        }| j
                  j                  | j                  j                  ||d|      4 d{   }|j                  dk(  r?t               }|j                  j                         2 3 d{   }|j!                  |       |j)                          d{   }t         j	                  d|j                  |dd        	 ddd      d{    y# t        $ r t         j	                  d       Y yw xY w7 7 6 t         j#                  d	|dd
 t%        |             t'        |      cddd      d{  7   S 7 7 p# 1 d{  7  sw Y   yxY w# t*        $ r }	t         j	                  d|	       Y d}	~	yd}	~	ww xY ww)a	  Send text to TTS server and return the WAV audio bytes.

        Args:
            text: The message to synthesise.
            sample_rate: Audio sample rate in Hz (default 16000).

        Returns:
            Raw WAV bytes on success, None on any error.
        u3   TTSClient.speak called with empty text — skippingNr   uY   aiohttp is not installed — cannot call TTS server. Install it with: pip install aiohttp)total)textsample_rate)jsontimeout   zTTS spoke: %r (%d bytes)P   zTTS server returned %d: %szTTS request failed: %s)loggerwarningaiohttpImportErrorerrorr!   ClientSessionClientTimeoutr    r   postr   status	bytearraycontentiter_anyextendinfolenbytesr&   	Exception)
r"   r&   r'   r.   r)   respchunkschunk
error_bodyexcs
             r   speakzTTSClient.speak<   s     NNPQ	 == #113DM	++$++2G2G+HG}}))$$";? *    ;;#%&[F'+||'<'<'> - -ee, $(99;.
0$++z$3?O #    	LL7 	-'>KK :D"Is6{S =   /   &  	LL137	s   G0E !G0AG !E&"G %4F/E*E(E*!&F/F+)F/1G <F-=G G0E# G0"E##G0&G (E**.F/G $F'%G *G0+F/-G /G5F86G=G  G0G 	G-G(#G0(G--G0c                |   K   | j                   *| j                   j                          d{    d| _         yy7 w)z%Close the underlying aiohttp session.N)r!   close)r"   s    r   rD   zTTSClient.closeo   s5     ==$--%%''' DM %'s   *<:<r   )r    zOptional[TTSConfig]returnNone)i>  )r&   r   r'   r   rE   zOptional[bytes])rE   rF   )r   r   r   r   r#   rB   rD   r   r   r   r   r   #   s    (/1f!r   r   )r   
__future__r   loggingr   dataclassesr   r   typingr   	getLoggerr   r,   r   r   r   r   r   <module>rL      sR    #  	 ( 			8	$    P! P!r   