
    Xi~[              	          d Z ddlZddlZddlZddlZddlZddlZddl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mZ ddlZddl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(m)Z)m*Z*m+Z+ d	dlm,Z,m-Z- de.de/deee.e.f   e.f   fdZ0dee1e.f   de1fdZ2de1fdZ3de.de/de/fdZ4de.de/fdZ5de.de/de/fdZ6dee1e.f   de/dee.ddf   fdZ7de$d ee1e.f   de1fd!Z8de1fd"Z9d#e1d$e1d%e1de1fd&Z: G d' d(      Z;y))zCommunicate with the service. Only the Communicate class should be used by
end-users. The other classes and functions are for internal use only.    N)nullcontext)TextIOWrapper)Queue)AsyncGeneratorContextManagerDict	GeneratorListOptionalTupleUnion)escapeunescape)Literal   )DEFAULT_VOICESEC_MS_GEC_VERSIONWSS_HEADERSWSS_URL)	TTSConfig)DRM)NoAudioReceivedUnexpectedResponseUnknownResponseWebSocketError)CommunicateStateTTSChunkdataheader_lengthreturnc                     t        | t              st        d      i }| d| j                  d      D ]  }|j                  dd      \  }}|||<    || |dz   d fS )z
    Returns the headers and data from the given data.

    Args:
        data (bytes): The data to be parsed.
        header_length (int): The length of the header.

    Returns:
        tuple: The headers and data to be used in the request.
    zdata must be bytesNs   
   :r      )
isinstancebytes	TypeErrorsplit)r   r   headerslinekeyvalues         ^/home/obispo/Crisostomo_bridge/mision_env/lib/python3.12/site-packages/edge_tts/communicate.pyget_headers_and_datar-   )   sw     dE",--G^m$**73 ZZa(
U D*,---    stringc                 J   t        | t              r| j                  d      } t        | t              st	        d      t        |       }t        |      D ]>  \  }}t        |      }d|cxk  rdk  sn d|cxk  rdk  sn d|cxk  rdk  s7n :d	||<   @ d
j                  |      S )aS  
    The service does not support a couple character ranges.
    Most important being the vertical tab character which is
    commonly present in OCR-ed PDFs. Not doing this will
    result in an error from the service.

    Args:
        string (str or bytes): The string to be cleaned.

    Returns:
        str: The cleaned string.
    utf-8zstring must be str or bytesr                    )	r$   r%   decodestrr&   list	enumerateordjoin)r/   charsidxcharcodes        r,   remove_incompatible_charactersrC   A   s     &% w'fc"566F|Eu% 	TINNd 0b 0bD6FB6FE#J
 775>r.   c                  >    t        j                         j                  S )zZ
    Returns a UUID without dashes.

    Returns:
        str: A UUID without dashes.
    )uuiduuid4hex r.   r,   
connect_idrI   ]   s     ::<r.   textlimitc                 \    | j                  dd|      }|dk  r| j                  dd|      }|S )a  
    Finds the index of the rightmost preferred split character (newline or space)
    within the initial `limit` bytes of the text.

    This helps find a natural word or sentence boundary for splitting, prioritizing
    newlines over spaces.

    Args:
        text (bytes): The byte string to search within.
        limit (int): The maximum index (exclusive) to search up to.

    Returns:
        int: The index of the last found newline or space within the limit,
             or -1 if neither is found in that range.
       
r       )rfind)rJ   rK   split_ats      r,   (_find_last_newline_or_space_within_limitrQ   g   s4    " zz%E*H!|::dAu-Or.   text_segmentc                     t        |       }|dkD  r	 | d| j                  d       |S |S # t        $ r |dz  }Y nw xY w|dkD  r3)a  
    Finds the rightmost possible byte index such that the
    segment `text_segment[:index]` is a valid UTF-8 sequence.

    This prevents splitting in the middle of a multi-byte UTF-8 character.

    Args:
        text_segment (bytes): The byte segment being considered for splitting.

    Returns:
        int: The index of the safe split point. Returns 0 if no valid split
             point is found (e.g., if the first byte is part of a multi-byte
             sequence longer than the limit allows).
    r   Nr1   r   )lenr9   UnicodeDecodeError)rR   rP   s     r,   _find_safe_utf8_split_pointrV      s_     < H
Q,	(#**73O
 O	 " 	MH	 Q,s   * ;;rP   c                     |dkD  rBd| d| v r;| j                  dd|      }| j                  d||      dk7  r	 |S |}|dkD  rd| d| v r;|S )a  
    Adjusts a proposed split point backward to prevent splitting inside an XML entity.

    For example, if `text` is `b"this &amp; that"` and `split_at` falls between
    `&` and `;`, this function moves `split_at` to the index before `&`.

    Args:
        text (bytes): The text segment being considered.
        split_at (int): The proposed split point index, determined by whitespace
                        or UTF-8 safety.

    Returns:
        int: The adjusted split point index. It will be moved to the '&'
             if an unterminated entity is detected right before the original `split_at`.
             Otherwise, the original `split_at` is returned.
    r      &N   ;)rindexfind)rJ   rP   ampersand_indexs      r,   "_adjust_split_point_for_xml_entityr^      sm    " Q,44	?2++dAx899T?H5;
 O # Q,44	?2 Or.   byte_lengthc              #     K   t        | t              r| j                  d      } t        | t              st	        d      |dk  rt        d      t        |       |kD  rlt        | |      }|dk  rt        |       }t        | |      }|dk  rt        d      | d| j                         }|r| | |dkD  r|ndd } t        |       |kD  rl| j                         }|r| yyw)a  
    Splits text into chunks, each not exceeding a maximum byte length.

    This function prioritizes splitting at natural boundaries (newlines, spaces)
    while ensuring that:
    1. No chunk exceeds `byte_length` bytes.
    2. Chunks do not end with an incomplete UTF-8 multi-byte character.
    3. Chunks do not split XML entities (like `&amp;`) in the middle.

    Args:
        text (str or bytes): The input text. If str, it's encoded to UTF-8.
        byte_length (int): The maximum allowed byte length for any yielded chunk.
                           Must be positive.

    Yields:
        bytes: Text chunks (UTF-8 encoded, stripped of leading/trailing whitespace)
               that conform to the byte length and integrity constraints.

    Raises:
        TypeError: If `text` is not str or bytes.
        ValueError: If `byte_length` is not positive, or if a split point
                    cannot be determined (e.g., due to extremely small byte_length
                    relative to character/entity sizes).
    r1   ztext must be str or bytesr   z"byte_length must be greater than 0zTMaximum byte length is too small or invalid text structure near '&' or invalid UTF-8Nr   )r$   r:   encoder%   r&   
ValueErrorrT   rQ   rV   r^   strip)rJ   r_   rP   chunkremaining_chunks        r,   split_text_by_byte_lengthrf      s     6 ${{7#dE"344a=>>
d)k
!;D+Na<248H 6dHEa< C  Yh%%'K 1H!565 d)k
!: jjlO s   CC!	C!tcescaped_textc                     t        |t              r|j                  d      }d| j                   d| j                   d| j
                   d| j                   d| dS )z
    Creates a SSML string from the given parameters.

    Args:
        tc (TTSConfig): The TTS configuration.
        escaped_text (str or bytes): The escaped text. If bytes, it must be UTF-8 encoded.

    Returns:
        str: The SSML string.
    r1   z_<speak version='1.0' xmlns='http://www.w3.org/2001/10/synthesis' xml:lang='en-US'><voice name='z'><prosody pitch='z' rate='z
' volume='z'>z</prosody></voice></speak>)r$   r%   r9   voicepitchratevolume)rg   rh   s     r,   mkssmlrn      sd     ,&#**73	z "88*HRWWIZ		{".			r.   c                  R    t        j                  dt        j                               S )zg
    Return Javascript-style date string.

    Returns:
        str: Javascript-style date string.
    z:%a %b %d %Y %H:%M:%S GMT+0000 (Coordinated Universal Time))timestrftimegmtimerH   r.   r,   date_to_stringrs     s      ==Ddkkm r.   
request_id	timestampssmlc                     d|  d| d| S )z
    Returns the headers and data to be used in the request.

    Returns:
        str: The headers and data to be used in the request.
    zX-RequestId:z1
Content-Type:application/ssml+xml
X-Timestamp:zZ
Path:ssml

rH   )rt   ru   rv   s      r,   ssml_headers_plus_datarx   '  s)     zl # k "&		r.   c                   B   e Zd ZdZefdddddddddd	ed
ededededed   deej                     dee   dee
   dee
   fdZdedefdZdeedf   fdZdeedf   fdZ	 ddeeef   deeeef      ddfdZdeeddf   fdZ	 ddeeef   deeeef      ddfdZy) Communicatez'
    Communicate with the service.
    z+0%z+0HzSentenceBoundaryN
   <   )rl   rm   rk   boundary	connectorproxyconnect_timeoutreceive_timeoutrJ   rj   rl   rm   rk   r~   WordBoundaryr{   r   r   r   r   c                   t        |||||      | _        t        |t              st	        d      t        t        t        |            d      | _        |t        |t              st	        d      || _	        t        |	t              st	        d      t        |
t              st	        d      t        j                  d d |	|
      | _        |%t        |t        j                        st	        d      || _        dd	d	d
d| _        y )Nztext must be stri   zproxy must be strzconnect_timeout must be intzreceive_timeout must be int)totalconnectsock_connect	sock_readz'connector must be aiohttp.BaseConnectorr.   r   F)partial_textoffset_compensationlast_duration_offsetstream_was_called)r   
tts_configr$   r:   r&   rf   r   rC   textsr   intaiohttpClientTimeoutsession_timeoutBaseConnectorr   state)selfrJ   rj   rl   rm   rk   r~   r   r   r   r   s              r,   __init__zCommunicate.__init__>  s    $E4I $$.// /1$78

 Zs%;/00$)
 /3/9::/3/9::&44(%	 
  Iw?T?T)UEFF:C  #$$%!&	(

r.   r   r    c                     t        j                  |      d   D ]X  }|d   }|dv r;|d   d   | j                  d   z   }|d   d   }|||t        |d   d   d	         d
c S |dv rLt	        d|        t        d      )NMetadataTyper   DataOffsetr   DurationrJ   Text)typeoffsetdurationrJ   )
SessionEndzUnknown metadata type: zNo WordBoundary metadata found)jsonloadsr   r   r   r   )r   r   meta_obj	meta_typecurrent_offsetcurrent_durations         r,   __parse_metadatazCommunicate.__parse_metadataw  s    

4(4 	IH (I@@V$X.<Q1RR  $,F#3J#? %, 0$Xf%5f%=f%EF	  O+!$;I;"GHH	I  !!ABBr.   c           
        K   d( fd}d( fd}d}t        j                  t        j                               }t	        j
                   j                  d j                        4 d {   }|j                  t         dt                dt        j                          d	t         d
 j                  t        j                  t               |      4 d {    |        d {     |        d {    2 3 d {   }|j"                  t        j$                  j&                  k(  r|j(                  j+                  d      }t-        ||j/                  d            \  }}	|j1                  dd       }
|
dk(  r/ j3                  |	      }| |d   |d   z    j4                  d<   |
dk(  r6 j4                  d    j4                  d<    j4                  dxx   dz  cc<    n|
dvst7        d      |j"                  t        j$                  j8                  k(  rt;        |j(                        dk  rt=        d      t>        jA                  |j(                  d d d      }|t;        |j(                        kD  rt=        d      t-        |j(                  |      \  }}	|j1                  d      dk7  rt=        d      |j1                  dd       }|dvrt=        d       |t;        |	      d!k(  rt=        d"      t;        |	      d!k(  rt=        d#      d}d$|	d% &|j"                  t        j$                  jB                  k(  sOtE        |j(                  r|j(                        d&      |stG        d'      d d d       d {    d d d       d {    y 7 67 7 7 7 6 ?7 &# 1 d {  7  sw Y   6xY w7 -# 1 d {  7  sw Y   y xY ww))Nc            	         K   j                   j                  dk(  } | rdnd}| sdnd}j                  dt                d| d| d       d{    y7 w)	z)Sends the command request to the service.r   truefalsezX-Timestamp:z
Content-Type:application/json; charset=utf-8
Path:speech.config

{"context":{"synthesis":{"audio":{"metadataoptions":{"sentenceBoundaryEnabled":"z","wordBoundaryEnabled":"z9"},"outputFormat":"audio-24khz-48kbitrate-mono-mp3"}}}}
N)r   r~   send_strrs   )word_boundarywdsqr   	websockets      r,   send_command_requestz2Communicate.__stream.<locals>.send_command_request  sn      OO44FM(gB,'B$$~/0 1. /1T1J2$ O		 	 	s   AAAAc                     K   j                  t        t               t               t	         j
                   j                  d                      d{    y7 w)z&Sends the SSML request to the service.r   N)r   rx   rI   rs   rn   r   r   )r   r   s   r,   send_ssml_requestz/Communicate.__stream.<locals>.send_ssml_request  sM     $$&L"$

>2	 	 	s   AAAAF)cafileT)r   	trust_envtimeoutz&ConnectionId=z&Sec-MS-GEC=z&Sec-MS-GEC-Version=   )compressr   r(   sslr1   s   

s   Paths   audio.metadatar   r   r   s   turn.endr   i )s   responses
   turn.startzUnknown path receivedr#   zBWe received a binary message, but it is missing the header length.bigz9The header length is greater than the length of the data.s   audioz3Received binary message, but the path is not audio.s   Content-Type)s
   audio/mpegNz=Received binary message, but with an unexpected Content-Type.r   z<Received binary message with no Content-Type, but with data.z:Received binary message, but it is missing the audio data.audio)r   r   zUnknown errorzFNo audio was received. Please verify that your parameters are correct.r    N)$r   create_default_contextcertifiwherer   ClientSessionr   r   
ws_connectr   rI   r   generate_sec_ms_gecr   r   headers_with_muidr   r   	WSMsgTypeTEXTr   ra   r-   r\   get_Communicate__parse_metadatar   r   BINARYrT   r   r   
from_bytesERRORr   r   )r   r   r   audio_was_receivedssl_ctxsessionreceivedencoded_data
parametersr   pathparsed_metadatar   content_typer   s   `             @r,   __streamzCommunicate.__stream  s    	 	  # ,,GMMOD((nn((
 p	 p	 g((i~jl^32245"#5"68 **))+6 ) 
	p	 p	 &(((#%%%"+ Z Zh==G$5$5$:$::*2--*>*>w*GL';$l&7&7&D($J &>>'48D00*.*?*?*E-- ,H5
8SS 

#9: ,<@JJ2=

#89 

#89YF9 %AA-.EFF]]g&7&7&>&>>8==)A-0` 
 %(NN8==!3De$LM$s8=='990W 
 (< }($J
 "~~g.(:0Q  $.>>/4#HL#+@@0[ 
 $+t9>$ 1Z 
 4yA~0X 
 *.&#*D99]]g&7&7&=&==()1 <K  &%\ ]p	 p	 p	 p	 p	 p	 )%Z)#p	 p	 p	 p	 p	 p	 p	 p	s   A)O"-N#.O"1A)ON&ON6)N)*N68N,9N6?N2N/
N2C&N6.EN64N6ON4OO"OO"&O)N6,N6/N22N64O6O	<N?=O	OO"OOOO"c                  K   | j                   d   rt        d      d| j                   d<   | j                  D ].  | j                   d<   	 | j                         2 3 d{   }|  y7 6 6# t        j
                  $ rP}|j                  dk7  r t        j                  |       | j                         2 3 d{  7  }| 6 Y d}~d}~ww xY ww)au  
        Streams audio and metadata from the service.

        Raises:
            NoAudioReceived: If no audio is received from the service.
            UnexpectedResponse: If the response from the service is unexpected.
            UnknownResponse: If the response from the service is unknown.
            WebSocketError: If there is an error with the websocket.
        r   zstream can only be called once.Tr   Ni  )	r   RuntimeErrorr   _Communicate__streamr   ClientResponseErrorstatusr   handle_client_response_error)r   messagees      r,   streamzCommunicate.stream!  s      ::)*@AA*.

&' +/** 
	"DJJ~&	"%)]]_ " "'!M
	""_.. "88s?003%)]]_ " "'!M &5"sr   AC	A.A,A*A,!A.(C*A,,A.-C.C5C6C:B=
;C?CCCCaudio_fnamemetadata_fnamec                   K   |t        |dd      n	t               }|5  t        |d      5 }| j                         2 3 d{   }|d   dk(  r|j                  |d          &t	        |t
              s7|d   d	v s?t        j                  ||       |j                  d
       g7 b6 	 ddd       n# 1 sw Y   nxY wddd       y# 1 sw Y   yxY ww)zE
        Save the audio and metadata to the specified files.
        Nwr1   )encodingwbr   r   r   r   
)openr   r   writer$   r   r   dump)r   r   r   metadatar   r   s         r,   savezCommunicate.save@  s      ) w7 	
  		)tK. 		)%!% ) )g6?g-KK0-8WV_ Q > IIgx0NN4()		) 		) 		) 		) 		) 		)sb   CCB1B&B$
B&.B14B1<(B1$B&&B1(	C1B:	6C=	CCCc              #       K   dt         ddf fd}t               }t        j                  j                         5 }|j	                  ||       	 |j                         }|n| 	 ddd       y# 1 sw Y   yxY ww)z-Synchronous interface for async stream methodqueuer    Nc                      d fd}t        j                         }t        j                  |       |j                   |              |j	                          y )Nc                     K   j                         2 3 d {   } j                  |        7 6 j                  d        y wN)r   put)itemr   r   s    r,   	get_itemszECommunicate.stream_sync.<locals>.fetch_async_items.<locals>.get_items\  s:     "&++- $ $$IIdO$-		$s   A1/1A1Ar   )asyncionew_event_loopset_event_looprun_until_completeclose)r   r   loopr   s   `  r,   fetch_async_itemsz2Communicate.stream_sync.<locals>.fetch_async_items[  s?     
 ))+D""4(##IK0JJLr.   )r   
concurrentfuturesThreadPoolExecutorsubmitr   )r   r   r   executorr   s   `    r,   stream_synczCommunicate.stream_syncX  s     		U 		t 		 w224 	OO-u5yy{<
	  	 	 	s   7A<,A0'	A<0A95A<c                     t         j                  j                         5 }|j                  t        j
                  | j                  ||            }|j                          ddd       y# 1 sw Y   yxY w)z,Synchronous interface for async save method.N)r   r   r   r   r   runr   result)r   r   r   r   futures        r,   	save_synczCommunicate.save_syncq  sZ     224 	__TYY{NCF MMO		 	 	s   AA))A2r   )__name__
__module____qualname____doc__r   r:   r   r   r   r   r   r   r%   r   r   r   r   r   r   r   r	   r   r  rH   r.   r,   rz   rz   8  s    #7

 @R59#)+)+7
7
 7

 7
 7
 7
 <=7
 G1127
 }7
 "#7
 "#7
rCU Cx C&Ux~ > Un"	$	'"D 7;)3:&) !sEz!23) 
	)0Yxt';< 8 7;
3:&
 !sEz!23
 
	
r.   rz   )<r	  r   concurrent.futuresr   r   r   rp   rE   
contextlibr   ior   r   r   typingr   r   r   r	   r
   r   r   r   xml.sax.saxutilsr   r   r   r   typing_extensionsr   	constantsr   r   r   r   data_classesr   drmr   
exceptionsr   r   r   r   r   r   r%   r   r-   r:   rC   rI   rQ   rV   r^   rf   rn   rs   rx   rz   rH   r.   r,   <module>r     s  I    
   "  	 	 	 .   % N N #   /.
. #.
4uu$%.05e+<  8C 5   0e  8U c c <B
U

B*-BudD !BJy c5j(9 c 2  s s # # "C Cr.   