o
    y	iB2                     @   sp   d Z ddlZddlZddlZddlmZmZmZ ddlZddl	Z	ddl
mZ ddlmZ G dd dZe ZdS )z
ElevenLabs TTS Service for Text-to-Speech Conversion
Handles text-to-speech using ElevenLabs AI's TTS API with emotional expressions
    N)OptionalDictAny)Config)Logc                   @   s   e Zd ZdZddefddZddeded	ee fd
dZded	efddZ	ddeded	ee fddZ
ded	eeef fddZded	efddZd	efddZd	eeef fddZded	efddZdS )ElevenLabsTTSServicez
    Service for converting text to speech using ElevenLabs AI's TTS API.
    Provides high-quality voice synthesis with emotional expressions.
    Nvoice_idc                 C   s@   t j| _|pt j| _t j| _d| _t	d| j d| j  d S )Nzhttps://api.elevenlabs.io/v1u1   🎤 ElevenLabs TTS Service initialized - Voice: z	, Model: )
r   ZELEVENLABS_API_KEYapi_keyZELEVENLABS_VOICE_IDr   ZELEVENLABS_MODEL_IDmodel_idbase_urlr   info)selfr    r   "services/elevenlabs_tts_service.py__init__   s
   zElevenLabsTTSService.__init__defaulttextemotionreturnc              
      s   |r|  std dS z3td|dd  d | |}| ||I dH }|r:tdt| d |W S td W dS  t	j
yQ   td	 Y dS  tyk } ztd
|  W Y d}~dS d}~ww )a5  
        Convert text to speech audio with emotional expressions.
        
        Args:
            text: Text to convert to speech (can include emotional tags)
            emotion: Emotion type for voice settings
            
        Returns:
            Audio bytes in MP3 format or None if failed
        u-   ⚠️ Empty text provided for ElevenLabs TTSNu0   🎤 Converting text to speech with ElevenLabs: 2   z...u+   ✅ ElevenLabs TTS conversion successful -  bytesu$   ❌ ElevenLabs TTS conversion failedu'   ❌ ElevenLabs TTS conversion timed outu3   ❌ Error in ElevenLabs text-to-speech conversion: )stripr   Zwarningdebug_maybe_inject_fillers_call_elevenlabs_apir   lenerrorasyncioTimeoutError	Exception)r   r   r   Zprocessed_text
audio_dataer   r   r   text_to_speech   s*   



z#ElevenLabsTTSService.text_to_speechc           	   	   C   s   zZddl }tjs|W S tdtdtttdd}|  |kr"|W S dd ttd	g D }|s2|W S ||}| }|dt	|t	|  }|
d
rNdnd
}| | | | W S  tye   | Y S w )z
        With a low probability, inject a natural filler at the start of a sentence.
        Keeps responses clear and does not increase speaking speed.
        r   Ng        g      ?ZFILLER_PROBABILITYg?c                 S   s   g | ]
}|  r|  qS r   )r   ).0tr   r   r   
<listcomp>Q   s    z>ElevenLabsTTSService._maybe_inject_fillers.<locals>.<listcomp>ZFILLER_TOKENS  )randomr   ZFILLERS_ENABLEDmaxminfloatgetattrchoicelstripr   
startswithr   )	r   r   r(   ZprobabilityZfillersZfillerstrippedprefixZspacerr   r   r   r   E   s$   
z*ElevenLabsTTSService._maybe_inject_fillersc              
      s  zdd| j d}| |}|| j|d}tjdd}tj|d4 I dH }|j| j d	| j ||d
4 I dH X}|j	dkrh|
 I dH }	tdt|	 d |	W  d  I dH  W  d  I dH  W S | I dH }
td|j	 d|
  	 W d  I dH  W d  I dH  W dS 1 I dH sw   Y  W d  I dH  W dS 1 I dH sw   Y  W dS  tjy   td Y dS  tjy } ztd|  W Y d}~dS d}~w ty } ztd|  W Y d}~dS d}~ww )a$  
        Make API call to ElevenLabs TTS service.
        
        Args:
            text: Text to convert (can include emotional tags like [excited], [sad], etc.)
            emotion: Emotion type for voice settings
            
        Returns:
            Audio data bytes or None
        
audio/mpegzapplication/json)ZAcceptzContent-Typez
xi-api-key)r   r
   voice_settings   )total)timeoutNz/text-to-speech/)headersZjson   u   🎤 Received z bytes from ElevenLabs TTSu   ❌ ElevenLabs TTS API error z: u%   ❌ ElevenLabs TTS API call timed outu*   ❌ Network error calling ElevenLabs TTS: u-   ❌ Unexpected error calling ElevenLabs TTS: )r	   _get_voice_settings_for_emotionr
   aiohttpZClientTimeoutZClientSessionZpostr   r   statusreadr   r   r   r   r   r   r   ZClientErrorr   )r   r   r   r7   r3   Zrequest_datar6   ZsessionZresponser    Z
error_textr!   r   r   r   r   ^   sX   

2
z)ElevenLabsTTSService._call_elevenlabs_apic                 C   sv   ddddddddddddd	ddddd
ddddd	ddddddddddddddd
ddd}| ||d S )z
        Get voice settings optimized for different emotions.
        
        Args:
            emotion: Emotion type
            
        Returns:
            Voice settings dictionary
        gffffff?g      ?g?T)Z	stabilityZsimilarity_boostZstyleZuse_speaker_boostg333333?g?g      ?g333333?g?g?g333333?)r   ZexcitedZsadZ	confidentZcalmZ	surprisedZprofessionalZfriendlyr   )get)r   r   Zemotion_settingsr   r   r   r9      sT   3z4ElevenLabsTTSService._get_voice_settings_for_emotionc                    s  |   t fdddD rd| S t fdddD r$d| S t fddd	D r4d
| S t fdddD rDd| S t fdddD rTd| S t fdddD rdd| S t fdddD rtd| S t fdddD rd| S |S )z
        Add emotional tags to text based on content analysis.
        
        Args:
            text: Original text
            
        Returns:
            Text with emotional tags added
        c                 3       | ]}| v V  qd S Nr   r#   ZwordZ
text_lowerr   r   	<genexpr>       z:ElevenLabsTTSService.add_emotional_tags.<locals>.<genexpr>)ZgreatZ	excellentZ	wonderfulZamazingZ	fantasticZawesomez
[excited] c                 3   r>   r?   r   r@   rA   r   r   rB      rC   )ZsorryZunfortunatelyZregretZ	apologizez[sad] c                 3   r>   r?   r   r@   rA   r   r   rB      rC   )sureZ
definitelyZ
absolutelyZ	certainlyz	of coursez[confident] c                 3   r>   r?   r   r@   rA   r   r   rB      rC   )ZwowZreallyZ
incredibleZunbelievablez[surprised] c                 3   r>   r?   r   r@   rA   r   r   rB      rC   )ZokayZalrightrD   z
no problemz[calm] c                 3   r>   r?   r   r@   rA   r   r   rB      rC   )zaccording toZ
documentedZestablishedZ	procedureZprotocolZstandardz[professional] c                 3   r>   r?   r   r@   rA   r   r   rB      rC   )ZgladZhappyZpleasureZwelcomeZenjoyZhopez[friendly] c                 3   r>   r?   r   r@   rA   r   r   rB     rC   )Zhellohizgood morningzgood afternoonzgood evening)lowerany)r   r   r   rA   r   add_emotional_tags   s$   








z'ElevenLabsTTSService.add_emotional_tagsc              
      s~   z"d}|  |I dH }|rt|dkrtd W dS td W dS  ty> } ztd|  W Y d}~dS d}~ww )	z
        Test connection to ElevenLabs TTS API.
        
        Returns:
            True if connection successful, False otherwise
        z0Hello, this is a test of ElevenLabs TTS service.Nr   u-   ✅ ElevenLabs TTS connection test successfulTu)   ❌ ElevenLabs TTS connection test failedFu-   ❌ Error testing ElevenLabs TTS connection: )r"   r   r   r   r   r   )r   Z	test_textr    r!   r   r   r   test_connection  s   

z$ElevenLabsTTSService.test_connectionc                 C   s   d| j | j| jdddS )z
        Get information about the TTS service configuration.
        
        Returns:
            Dictionary with service information
        Zelevenlabs_ttsTr2   )Zservice_typer   r
   r   Zsupports_emotionsZaudio_format)r   r
   r   )r   r   r   r   get_service_info  s   z%ElevenLabsTTSService.get_service_infor    c              
   C   s   z7|r	t |dk rW dS |dd dks|dd dkr*tdt | d	 W d
S tdt | d	 W d
S  tyR } ztd|  W Y d}~dS d}~ww )z
        Validate that the audio data is in correct format.
        
        Args:
            audio_data: Audio bytes to validate
            
        Returns:
            True if valid, False otherwise
        
   FN   s   ID3   s   u&   🎤 Audio format validation passed - r   Tu#   ❌ Error validating audio format: )r   r   r   r   r   )r   r    r!   r   r   r   validate_audio_format,  s   
 z*ElevenLabsTTSService.validate_audio_formatr?   )r   )__name__
__module____qualname____doc__strr   r   bytesr"   r   r   r   r+   r9   rH   boolrI   r   rJ   rN   r   r   r   r   r      s    &9A.r   )rR   r   r:   base64typingr   r   r   ioZwaveZconfigr   Zservices.log_utilsr   r   Zelevenlabs_tts_servicer   r   r   r   <module>   s      
9