+
    lHàjèM  ã                  óâ  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t
^ RIt^ RIt^ RIHt ^ RIHt ^ RIHtHtHtHtHt ^ RIHt ^ RIHtHtHtHt ]P<                  ! R4      tR	 t R
 R lt!Rt"RRRRRRRRRRRRRRRRRRRR/
t#R]$R&   RRR RR!RR"RR#RR$RR%R&R'R(/t%R]$R)&   R* R+ lt&RaR, R- llt'R.^^ut(t)t*. RbOt+]! R/R07       ! R1 R24      4       t,R3R4RcR5R6/R7R4RdR5R6/R8R4RcR5R6//t-R9]$R:&   RaR; R< llt.R=R>/R? R@ llt/RA RB lt0RC RD lt1RE RF lt2RG^RHR>RIR//RJ RK llt3RL RM lt4RN RO lt5RP RQ lt6](])]*3RR RS llt7RT RU lt8RV RW lt9RX RY lt:RZ R[ lt;R\R>/R] R^ llt<R\R>/R_ R` llt=R# )ea±  Long-form chunking, ffmpeg encoding, container repair and delivery packing (``tools.tts_tool``).

Provider-agnostic post-processing: split text under a per-request cap, wrap raw PCM as WAV,
convert WAV/MP3 to the target container, sniff/repair mislabelled ``.ogg`` files, and combine
final-encoded chunks under a destination platform's upload limit. Also home of the sibling
helpers ``_origin`` / ``_section`` / ``_remove_quietly``.
)ÚannotationsN)Ú	dataclass)ÚPath)ÚAnyÚDictÚListÚOptionalÚTuple)Úwindows_hide_flags)ÚBUILTIN_TTS_PROVIDERSÚ#DEFAULT_COMMAND_TTS_MAX_TEXT_LENGTHÚ_get_named_provider_configÚ_is_command_provider_configztools.tts_toolc                 ó   € ^ RI Hp  V # )zO``tools.tts_tool``, resolved per call so seams monkeypatched there still apply.©Útts_tool)Útoolsr   r   s    Ú</home/ubuntu/.hermes/hermes-agent/tools/tts_tool_delivery.pyÚ_originr       s
   € åØ€Oó    c               ó$   € V ^8„  d   QhRRRRRR/# )é   Ú
tts_configr   ÚkeyÚstrÚreturnzdict[str, Any]© )Úformats   "r   Ú__annotate__r   &   s!   € ÷ 8ñ 8˜ð 8 3ð 8¨>ñ 8r   c                óˆ   € \        V \        4      '       d   V P                  V4      MRp\        V\        4      '       d   V# / # )zC``tts.<key>`` as a dict (``null``/non-dict sections read as empty).N)Ú
isinstanceÚdictÚget)r   r   Úsections   && r   Ú_sectionr$   &   s5   € ä%/°
¼D×%AÒ%Aˆj�n‰n˜SÔ!Àt€GÜ  ¬$×/Ò/ˆ7Ð7°RÐ7r   i   Úedgeiˆ  Úopenaii   Úxaii˜:  Úminimaxi'  ÚmistralÚgeminii }  Ú
elevenlabsÚneuttsiÐ  Ú	kittenttsÚpiperzdict[str, int]ÚPROVIDER_MAX_TEXT_LENGTHÚ	eleven_v3Úeleven_ttv_v3Úeleven_multilingual_v2Úeleven_multilingual_v1Úeleven_english_sts_v2Úeleven_english_sts_v1Úeleven_flash_v2i0u  Úeleven_flash_v2_5i@œ  Ú ELEVENLABS_MODEL_MAX_TEXT_LENGTHc               ó    € V ^8„  d   QhRRRR/# )r   Úvaluer   r   zOptional[int]r   )r   s   "r   r   r   D   s   € ÷ cñ c˜ð c ñ cr   c                óp   € \        V \        4      '       d    \        V \        4      '       g
   V ^ 8”  d   V # R# )z6*value* when it is a positive non-bool int, else None.N)r    ÚintÚbool)r:   s   &r   Ú_positive_intr>   D   s-   € ä˜u¤c×*Ò*´:¸eÄT×3JÒ3JÈuÐWXÌyˆ5ÐbÐ^bÐbr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   ÚproviderúOptional[str]r   úOptional[dict[str, Any]]r   r<   r   )r   s   "r   r   r   I   s#   € ÷ $ñ $ }ð $ÐBZð $Ðfiñ $r   c                óf  € V '       g   \         # V P                  4       P                  4       pT;'       g    / p\        W24      p\	        VP                  R4      4      pV'       d   V# VR8X  dX   ^ RIHp VP                  R4      ;'       g    Tp\        P                  \        V4      P                  4       4      pV'       d   V# V\        9   d   \        V,          # V\        9  dE   \        W24      p	\        V	4      '       d)   \	        V	P                  R4      4      ;'       g    \        # \         # )aU  Input-character cap for *provider*: ``tts.<provider>.max_text_length`` > ElevenLabs model
table > ``PROVIDER_MAX_TEXT_LENGTH`` > command provider's own ``max_text_length`` (else
``DEFAULT_COMMAND_TTS_MAX_TEXT_LENGTH``) > ``FALLBACK_MAX_TEXT_LENGTH``. Non-positive /
non-int overrides fall through so a broken config can't disable truncation.Úmax_text_lengthr+   )ÚDEFAULT_ELEVENLABS_MODEL_IDÚmodel_id)ÚFALLBACK_MAX_TEXT_LENGTHÚlowerÚstripr$   r>   r"   Útools.tts_tool_providersrE   r8   r   r/   r   r   r   r   )
r@   r   r   ÚcfgÚprov_cfgÚoverriderE   rF   ÚmappedÚnameds
   &&        r   Ú_resolve_max_text_lengthrP   I   sò   € ÷
 Ü'Ð'Ø
�.‰.Ó
×
 Ñ
 Ó
"€CØ
×
Ð
˜€CÜ˜Ó!€HÜ˜XŸ\™\Ð*;Ó<Ó=€HßØˆØ
ˆlÔÝHØ—<‘< 
Ó+×JÐJÐ/JˆÜ1×5Ñ5´c¸(³m×6IÑ6IÓ6KÓLˆßØˆMØ
Ô&Ô&Ü'¨Õ,Ð,Ø
Ô'Ô'Ü*¨3Ó4ˆÜ& u×-Ò-Ü  §¡Ð+<Ó!=Ó>×eÐeÔBeÐeÜ#Ð#r   iÀ]  T)Úfrozenc                  óT   € ] tR t^ot$ RtR]R&   R]R&   RtR]R&   ]R	 R
 l4       tRt	R# )ÚAudioDeliveryProfilez9Destination-platform constraints for generated TTS audio.r   Úplatformr<   Úmax_file_bytesç333333ë?ÚfloatÚsafety_ratioc               ó   € V ^8„  d   QhRR/# )r   r   r<   r   )r   s   "r   r   Ú!AudioDeliveryProfile.__annotate__x   s   € ÷ Dñ D 3ñ Dr   c                ób   € \        ^\        V P                  V P                  ,          4      4      # )z:Conservative packing target below the platform hard limit.)Úmaxr<   rU   rX   )Úselfs   &r   Útarget_file_bytesÚ&AudioDeliveryProfile.target_file_bytesw   s'   € ô �1”c˜$×-Ñ-°×0AÑ0AÕAÓBÓCÐCr   r   N)
Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__annotations__rX   Úpropertyr^   Ú__static_attributes__r   r   r   rS   rS   o   s.   ‡ áCàƒMØÓØ€L�%ÓàôDó ôDr   rS   ÚdiscordrU   rX   rV   ÚtelegramÚdefaultzdict[str, dict[str, Any]]Ú_PLATFORM_AUDIO_DEFAULTSc               ó$   € V ^8„  d   QhRRRRRR/# )r   rT   rA   r   rB   r   rS   r   )r   s   "r   r   r   ƒ   s)   € ÷ oñ oØðoØ)AðoØMañor   c                ó¼  € T ;'       g    RP                  4       P                  4       ;'       g    Rp\        \        P	                  V4      ;'       g    \        R,          4      p\        \        VR4      V4      pTP                  VP                  4        UUu/ uF  w  rVVf   K  WVbK  	  upp4       \        VP	                  R4      4      ;'       g    \        R,          R,          pVP	                  RR4      p\        V\        4      '       g.   \        V\        \        34      '       d   ^ Tu;8  d   ^8:  g   M Rp\        W'\        V4      R7      # u uppi )zSResolve upload constraints, including optional ``tts.delivery_profiles`` overrides.rj   Údelivery_profilesrU   rX   rV   )rT   rU   rX   )rH   rI   r!   rk   r"   r$   ÚupdateÚitemsr>   r    r=   r<   rW   rS   )	rT   r   r   ÚdefaultsÚ	overridesÚkÚvrU   rX   s	   &&       r   Ú_resolve_audio_delivery_profileru   ƒ   s  € ð × Ð �y×
'Ñ
'Ó
)×
/Ñ
/Ó
1×
>Ð
>°Y€CÜÔ,×0Ñ0°Ó5×\Ð\Ô9QÐR[Õ9\Ó]€HÜœ *Ð.AÓBÀCÓH€IØ‡O�O i§o¡oÔ&7ÔIÑ&7™d˜a¸1”T�Q’TÑ&7ÒIÔJÜ# H§L¡LÐ1AÓ$BÓC÷ Oð OÜ1°)Õ<Ð=MÕNð à—<‘< °Ó5€LÜ�<¤×&Ò&¬j¸ÌÌUÀ|×.TÒ.TØ�|Ö( qÖ(ØˆÜ¨ÔZ_Ð`lÓZmÔnÐnùó Js   ÂE
Â'E
Úslice_oversizedFc               ó(   € V ^8„  d   QhRRRRRRRR/# )r   Úpiecesú	list[str]Ú	max_charsr<   rv   r=   r   r   )r   s   "r   r   r   “   s)   € ÷ ñ ˜Ið °#ð È4ð Ð\eñ r   c          
     ó¨  aa€ . pRpV  F¬  oV'       d^   \        S4      S8”  dN   V'       d   VP                  V4       RpVP                  VV3R l\        ^ \        S4      S4       4       4       Kh  V RS 2P	                  4       pV'       d&   \        V4      S8”  d   VP                  V4       SpKª  TpK®  	  V'       d   VP                  V4       V# )zûGreedily join *pieces* with single spaces, starting a new chunk past *max_chars*. With
``slice_oversized`` an over-long piece flushes the running chunk and emits its hard slices as
their own chunks (the tail slice is not merged with following pieces).Ú c              3  ó:   <"  € T F  pSWS,            x € K  	  R # 5i©Nr   )Ú.0Úirz   Úpieces   & €€r   Ú	<genexpr>Ú"_pack_under_cap.<locals>.<genexpr>ž   s   øé € ÐZÑ:Y°Q˜%  i¥-Õ0Ó:Yùs   ƒÚ )ÚlenÚappendÚextendÚrangerI   )rx   rz   rv   ÚchunksÚcurrentÚ	candidater�   s   &f$   @r   Ú_pack_under_caprŒ   “   s°   ù€ ð €FØ€GÛˆßœs 5›z¨IÔ5ßØ—‘˜gÔ&Ø�Ø�M‰MÕZ¼%ÀÄ3ÀuÃ:ÈyÔ:YÓZÔZÙØ�i˜q  Ð(×.Ñ.Ó0ˆ	ß”s˜9“~¨	Ô1Ø�M‰M˜'Ô"ØŠGàŠGñ ÷ Ø�‰�gÔØ€Mr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úsentencer   rz   r<   r   ry   r   )r   s   "r   r   r   «   s&   € ÷ Nñ N¨ð N¸ð NÀ	ñ Nr   c                ó:   € \        V P                  4       VRR7      # )zGSplit one over-limit sentence on word boundaries, then hard boundaries.T)rv   )rŒ   Úsplit)rŽ   rz   s   &&r   Ú_split_oversized_sentencer‘   «   s   € ä˜8Ÿ>™>Ó+¨YÈÔMÐMr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Útextr   rz   r<   r   ry   r   )r   s   "r   r   r   °   s!   € ÷ 0ñ 0˜cð 0¨cð 0°iñ 0r   c                óš  € V^ 8:  d   \         pRP                  T ;'       g    RP                  4       4      pV'       g   . # \        V4      V8:  d   V.# . p\	        RR \
        P                  ! RV4       4       4       F@  p\        V4      V8:  d   VP                  V4       K&  VP                  \        WA4      4       KB  	  \        W14      # )zDSplit text under a provider cap without dropping normalized content.r„   r|   Nc              3  ó@   "  € T F  qP                  4       x € K  	  R # 5ir~   )rI   )r   Úss   & r   r‚   Ú&_split_text_for_tts.<locals>.<genexpr>º   s   é € Ð!_Ñ5^°§'¡'§) )Ó5^ùs   ‚z(?<=[.!?;:,])\s+)
rG   Újoinr�   r…   ÚfilterÚrer†   r‡   r‘   rŒ   )r“   rz   Ú
normalizedÚexpandedrŽ   s   &&   r   Ú_split_text_for_ttsr�   °   s¨   € à�A„~Ü,ˆ	Ø—‘˜4Ÿ:˜: 2×,Ñ,Ó.Ó/€JßØˆ	Ü
ˆ:ƒ˜)Ô#Øˆ|ÐØ€HÜ˜4Ñ!_´R·X²XÐ>QÐS]Ô5^Ó!_Ö`ˆÜˆx‹=˜IÔ%Ø�O‰O˜HÖ%à�O‰OÔ5°hÓJÖKñ	 aô
 ˜8Ó/Ð/r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úaudio_pathsry   ÚprofilerS   r   zlist[list[str]]r   )r   s   "r   r   r   Â   s#   € ÷ 5ñ 5°	ð 5ÐDXð 5Ð]lñ 5r   c                óx  € . p. p^ RrTV  F›  p\        V4      P                  4       P                  \        V4      P                  P	                  4       r‡V'       d2   WG,           VP
                  8”  g   W…8w  d   VP                  V4       . ^ rCVP                  V4       WG,           TrTK�  	  V'       d
   W#.,           # T# )z[Group final-encoded chunks under the size target; never mixes suffixes (can't concat-copy).r|   )r   ÚstatÚst_sizeÚsuffixrH   r^   r†   )	rŸ   r    ÚgroupsrŠ   Úcurrent_sizeÚcurrent_suffixÚpathÚsizer¤   s	   &&       r   Ú_pack_audio_files_for_deliveryrª   Â   s�   € à €FØ€GØ#$ b�.ÛˆÜ˜D“z—‘Ó(×0Ñ0´$°t³*×2CÑ2C×2IÑ2IÓ2Kˆfß˜Õ+¨g×.GÑ.GÔGÈ6ÔKcØ�M‰M˜'Ô"Ø$&¨�\Ø�‰�tÔØ'3Õ':¸F’nñ ÷ ")ˆ6�IÕÐ4¨fÐ4r   ÚtimeoutÚcheckÚcapturec               ó0   € V ^8„  d   QhRRRRRRRRR	RR
R/# )r   Úffmpegr   Úargsry   r«   r<   r¬   r=   r­   r   zsubprocess.CompletedProcessr   )r   s   "r   r   r   Ò   sD   € ÷ Xñ XØðXØ ðXØ.1ðXØ?CðXØVZðXà ñXr   c          	     ój   € \         P                  ! V .VOWCV\         P                  \        4       R7      # )zDRun ``ffmpeg <args>`` headless (no stdin, hidden window on Windows).)Úcapture_outputr¬   r«   ÚstdinÚcreationflags)Ú
subprocessÚrunÚDEVNULLr
   )r¯   r°   r«   r¬   r­   s   &&$$$r   Ú_ffmpeg_runr¸   Ò   s3   € ô �>Š>˜6˜/ D˜/¸'ÐX_Ü *× 2Ñ 2ÔBTÓBVôXð Xr   c               ó    € V ^8„  d   QhRRRR/# )r   r¨   rA   r   ÚNoner   )r   s   "r   r   r   Ú   s   € ÷ ñ ˜-ð ¨Dñ r   c                ól   € V '       d    \         P                  ! V 4       R# R#   \         d     R# i ; i)zGBest-effort unlink (missing/locked files are ignored); None is a no-op.N)ÚosÚremoveÚOSError)r¨   s   &r   Ú_remove_quietlyr¿   Ú   s.   € çð	Ü�IŠI�dŽOñ øô ô 	Úð	ús   Š$ ¤3²3c               ó    € V ^8„  d   QhRRRR/# )r   Úoutput_pathr   r   r   )r   s   "r   r   r   ã   s   € ÷ cñ c 3ð c¨3ñ cr   c                ót   € V P                  R4      '       d   V # V P                  R^4      ^ ,          R,           # )zOPath a WAV-native engine writes to before conversion to *output_path*'s format.ú.wavÚ.)ÚendswithÚrsplit)rÁ   s   &r   Ú_wav_sidecar_pathrÇ   ã   s7   € à%×.Ñ.¨v×6Ò6ˆ;Ðb¸K×<NÑ<NÈsÐTUÓ<VÐWXÕ<YÐ\bÕ<bÐbr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úwav_pathr   rÁ   r   r   )r   s   "r   r   r   è   s!   € ÷ ñ  3ð °Sð ¸Sñ r   c           	     óÂ   € W8X  d   V# \         P                  ! R4      pV'       g   \        P                  ! W4       V# \	        VRV RRRV.RRR7       \        V 4       V# )	z¨Move a WAV-native engine's output into the requested container: ffmpeg-convert when
available, else rename so the tool stays usable (misleading extension, audio plays).r¯   ú-iú-yú	-loglevelÚerrorTF)r¬   r­   )ÚshutilÚwhichr¼   Úrenamer¸   r¿   )rÉ   rÁ   r¯   s   && r   Ú_finalize_wav_outputrÒ   è   s_   € ð ÔØÐÜ�\Š\˜(Ó#€FßÜ
�	Š	�(Ô(ØÐÜ�˜˜x¨¨{¸GÀ[ÐQØ Eõ+ä�HÔØÐr   c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )r   Ú	pcm_bytesÚbytesÚsample_rater<   ÚchannelsÚsample_widthr   r   )r   s   "r   r   r   ÷   s;   € ÷ 
Cñ 
CØð
CØ#&ð
Càð
Cà7:ð
CàY^ñ
Cr   c                óh  € W#,          p\         P                  ! RR^^W!W,          WC^,          4	      p\         P                  ! RR\        V 4      4      p^\        V4      ,           \        V4      ,           \        V 4      ,           p\         P                  ! RRVR4      pW…,           V,           V ,           # )zUWrap raw signed-little-endian PCM (e.g. Gemini's L16) with a minimal WAV RIFF header.z
<4sIHHIIHHs   fmt z<4sIs   dataz<4sI4ss   RIFFs   WAVE)ÚstructÚpackr…   )	rÔ   rÖ   r×   rØ   Úblock_alignÚ	fmt_chunkÚdata_chunk_headerÚ	riff_sizeÚriff_headers	   &&&&     r   Ú_wrap_pcm_as_wavrá   ÷   s”   € ð Õ)€KÜ—’˜L¨'°2°q¸(Ø'Õ5°{ÐSTÕDTóV€IäŸš F¨G´S¸³^ÓDÐØ”C˜	“NÕ"¤SÐ):Ó%;Õ;¼cÀ)»nÕL€IÜ—+’+˜h¨°¸GÓD€KØÕ"Ð%6Õ6¸ÕBÐBr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Ú	wav_bytesrÕ   rÁ   r   r   r   )r   s   "r   r   r     s!   € ÷ ñ  5ð °sð ¸sñ r   c                ól  € VP                  4       P                  R4      '       d1   \        VR4      ;_uu_ 4       pVP                  V 4       RRR4       V# \        P
                  ! RRR7      ;_uu_ 4       pVP                  V 4       VP                  pRRR4        \        P                  ! R4      pV'       dŠ   VP                  4       P                  R4      '       d   \        M. p\        VRX.VOR	NR
NRNVN4      pVP                  ^ 8w  d3   VP                  P                  RRR7      R,          p\        RV 24      hM-\        P!                  RV4       \        P"                  ! XV4       \%        V4       V#   + '       g   i     T# ; i  + '       g   i     EL; i  \%        X4       i ; i)a>  Write in-memory WAV to *output_path*, ffmpeg-converting to its container. ``.ogg`` is forced
to Opus (ffmpeg's .ogg default is Vorbis, which voice bubbles reject). A failed conversion
raises RuntimeError; without ffmpeg the raw WAV is written under the requested name
(misleading extension, but the audio still plays).rÃ   ÚwbNF)r¤   Údeleter¯   ú.oggrË   rÌ   rÍ   rÎ   úutf-8Úignore©Úerrors:Ni,  Nzffmpeg conversion failed: zEffmpeg not found; writing raw WAV to %s (extension may be misleading))rH   rÅ   ÚopenÚwriteÚtempfileÚNamedTemporaryFileÚnamerÏ   rÐ   Ú_OPUS_VOICE_ARGSr¸   Ú
returncodeÚstderrÚdecodeÚRuntimeErrorÚloggerÚwarningÚcopyfiler¿   )	rã   rÁ   ÚfÚtmprÉ   r¯   ÚopusÚresultró   s	   &&       r   Ú_write_wav_bytes_asrý     sp  € ð
 ×ÑÓ×#Ñ# F×+Ò+Ü�+˜t×$Ô$¨Ø�G‰G�IÔ÷ %àÐÜ	×	$Ò	$¨F¸5×	AÕ	AÀSØ�	‰	�)ÔØ—8‘8ˆ÷ 
Bð"Ü—’˜hÓ'ˆßØ'2×'8Ñ'8Ó':×'CÑ'CÀF×'KÒ'KÕ#ÐQSˆDÜ Ø˜˜xÐX¨$ÐX°ÐX°kÐXÀ7ÐXÈKÐXóZˆFà× Ñ  AÔ%ØŸ™×-Ñ-¨g¸hÐ-ÓGÈÕM�Ü"Ð%?À¸xÐ#HÓIÐIð &ô �N‰NÐbÐdoÔpÜ�OŠO˜H kÔ2ä˜Ô!ØÐ÷) %Ö$àÐúß	A×	AÐ	Aûô  	˜Õ!ús0   ºE>Á6FÂF& Â;$F& Ã BF& Å>F	ÆF#	Æ&F3c               ó    € V ^8„  d   QhRRRR/# )r   Úmp3_pathr   r   rA   r   )r   s   "r   r   r   !  s   € ÷ wñ w˜sð w }ñ wr   c           	     ób   € ^ RI Hp V! V R^V P                  R^4      ^ ,          R,           R7      # )zOConvert any ffmpeg-readable audio file to OGG Opus next to it; None on failure.©Útranscode_to_ogg_opusÚ48krÄ   rç   ©Úbitrater«   rÁ   )Úgateway.platforms.baser  rÆ   )rÿ   r  s   & r   Ú_convert_to_opusr  !  s2   € å<Ù  °5À"ÐRZ×RaÑRaÐbeÐghÓRiÐjkÕRlÐouÕRuÔvÐvr   c               ó    € V ^8„  d   QhRRRR/# )r   r¨   r   r   r   )r   s   "r   r   r   ,  s   € ÷ ñ  ð ¨ñ r   c                óÜ   € ^ RI Hp  \        V R4      ;_uu_ 4       pV! VP                  ^4      4      ;'       g    RuuRRR4       #   + '       g   i     R# ; i  \         d     R# i ; i)zFReturn a container id ('ogg', 'wav', 'mp3', 'flac', ...) or 'unknown'.)Úsniff_containerÚrbÚunknownN)Útools.audio_containerr
  rì   Úreadr¾   )r¨   r
  Úfhs   &  r   Ú_sniff_audio_containerr  ,  sQ   € å5ðÜ�$˜×Ô Ù" 2§7¡7¨2£;Ó/×<Ð<°9÷ ××Óûäô Úðús-   ˆA œ!A½
A ÁA	ÁA ÁA ÁA+Á*A+c               ó    € V ^8„  d   QhRRRR/# )r   Úfile_strr   r   r   )r   s   "r   r   r   6  s   € ÷ ñ  Cð ¨Cñ r   c                óX  € V P                  R4      '       d   \        V 4      MRpVR
9   d   V # \        P                  RW4       ^ RIHp V! V R^V R7      pV'       d   V# V RR  RV 2p \        P                  ! W4       \        P                  R	Y4       T#   \         d    T u # i ; i)zªEnsure a ``.ogg`` path really holds Ogg: transcode in place, else rename to the sniffed
real extension so platforms get an honest file instead of a 0-second voice bubble.rç   ÚogguI   TTS wrote %s bytes into a .ogg path (%s) â€” transcoding to real Ogg/Opusr  r  r  NrÄ   ub   Could not transcode %s to Ogg/Opus â€” renamed to %s so the file is delivered with its real format)r  r  éüÿÿÿ)
rÅ   r  rö   Úinfor  r  r¼   Úreplacer¾   r÷   )r  Ú	containerr  ÚrepairedÚhonests   &    r   Ú_repair_ogg_containerr  6  sµ   € ð 5=×4EÑ4EÀf×4MÒ4MÔ& xÔ0ÐSX€IØÐ&Ô&ØˆÜ
‡K�KÐ[Ð]fÔqÝ<Ù$ X°uÀbÐV^Ô_€HßØˆØ˜˜"�ˆ˜a 	˜{Ð+€FðÜ
�
Š
�8Ô$ô ‡N�Nð <Ø=EôOà€Møô	 ô ØŠðús   Á+B ÂB)Â(B)Úvoice_compatiblec               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   rŸ   ry   rÁ   r   r  r=   r   rA   r   )r   s   "r   r   r   L  s*   € ÷ $ñ $ Yð $¸Sð $ÐW[ð $Ðhuñ $r   c               ó¼  € V '       g   \        R4      h\        V 4      ^8X  di   \        P                  P	                  V ^ ,          4      \        P                  P	                  V4      8w  d   \
        P                  ! V ^ ,          V4       V# \
        P                  ! R4      pV'       g   R# \        V4      pVP                  P                  RRR7       VP                  RVP                   R\        P                  ! 4       P                   R24      pVP                  RVP                    R\        P                  ! 4       P                   RVP"                   24      p R	P%                  R
 V  4       4      pVP'                  VRR7       RRRRRRRR\)        V4      R.
pVP"                  P+                  4       p	V'       g   V	R 9   d   V. R!O,          pMLV	R8X  dF   \,        ;QJ d    R V  4       F  '       d   K   RM	  RM! R V  4       4      '       d   VRR.,          p\/        V. VO\)        V4      N^xR7      p
V
P0                  ^ 8X  dl   VP3                  4       '       dV   VP5                  4       P6                  ^ 8”  d7   \        P8                  ! Wd4       \)        V4      WV3 F  p\;        V4       K  	  # \<        P?                  RV
P@                  PC                  RRR7      R,          4       WV3 F  p\;        V4       K  	  R#   \D        \F        PH                  3 d!   p\<        P?                  RT4        Rp?LMRp?ii ; i  YV3 F  p\;        T4       K  	  i ; i)"zúCombine independently encoded chunks with ffmpeg (never byte-joined). OGG/Opus is always
re-encoded (even without voice opt-in); matching MP3 chunks keep their frames (``-c:a copy``).
None when ffmpeg is missing/fails so callers keep the valid parts.zNo audio chunks to combiner¯   NT©ÚparentsÚexist_okrÄ   z.concat.txtz
.combiningr|   c              3  ó�   "  € T F<  pR \         P                  ! \        P                  P	                  V4      4       R2x € K>  	  R# 5i)zfile Ú
N)ÚshlexÚquoter¼   r¨   Úabspath)r   Úps   & r   r‚   Ú&_concat_audio_files.<locals>.<genexpr>^  s0   é € Ð[É{È!˜E¤%§+¢+¬b¯g©g¯o©o¸aÓ.@Ó"AÐ!BÀ"ÕEË{ùs   ‚AArè   )ÚencodingrÌ   rÍ   rÎ   z-fÚconcatz-safeÚ0rË   z-vnú-c:aú.mp3c              3  ón   "  € T F+  p\        V4      P                  P                  4       R 8H  x € K-  	  R# 5i)r-  N)r   r¤   rH   )r   r¨   s   & r   r‚   r(  d  s*   é € Ð%bÑVaÈd¤d¨4£j×&7Ñ&7×&=Ñ&=Ó&?À6Ö&IÓVaùs   ‚35FÚcopy)r«   zffmpeg audio combine failed: %sré   rê   :Niô  N>   rç   ú.opus)r,  Úlibopusú-acÚ1ú-b:aÚ64kú-vbrÚoff)%Ú
ValueErrorr…   r¼   r¨   r&  rÏ   rø   rÐ   r   ÚparentÚmkdirÚ	with_namerð   ÚuuidÚuuid4ÚhexÚstemr¤   r˜   Ú
write_textr   rH   Úallr¸   rò   Úexistsr¢   r£   r  r¿   rö   r÷   ró   rô   r¾   rµ   ÚTimeoutExpired)rŸ   rÁ   r  r¯   ÚdestinationÚconcat_pathÚtemp_outputÚentriesr°   r¤   rü   r¨   Úexcs   &&$          r   Ú_concat_audio_filesrI  L  sÃ  € ÷ ÜÐ5Ó6Ð6Ü
ˆ;Ó˜1ÔÜ�7‰7�?‰?˜; q�>Ó*¬b¯g©g¯o©o¸kÓ.JÔJÜ�OŠO˜K¨�N¨KÔ8ØÐÜ�\Š\˜(Ó#€FßÙÜ�{Ó#€KØ×Ñ×Ñ T°DÐÔ9Ø×'Ñ'¨!¨K×,<Ñ,<Ð+=¸Q¼t¿zºz»|×?OÑ?OÐ>PÐP[Ð(\Ó]€KØ×'Ñ'¨!¨K×,<Ñ,<Ð+=¸Q¼t¿zºz»|×?OÑ?OÐ>PÐPZÐ[f×[mÑ[mÐZnÐ(oÓp€Kð"Ø—'‘'Ñ[É{Ó[Ó[ˆØ×Ñ˜w°ÐÔ9Ø�k 7¨D°(¸GÀSÈ$ÔPSÐT_ÓP`ÐbgÐhˆØ×#Ñ#×)Ñ)Ó+ˆß˜vÐ):Ô:ØÒQÕQ‰DØ�vÔ§#£#Ñ%bÑVaÓ%b§#§#¢#Ñ%bÑVaÓ%b×"bÒ"bØ�V˜VÐ$Õ$ˆDÜ˜VÐ%> tÐ%>¬S°Ó-=Ð%>ÈÔLˆØ×Ñ Ô! k×&8Ñ&8×&:Ò&:¸{×?OÑ?OÓ?Q×?YÑ?YÐ\]Ô?]Ü�JŠJ�{Ô0Ü�{Ó#ð
 !Ó.ˆDÜ˜DÖ!ò /ô	 	�‰Ð8¸&¿-¹-×:NÑ:NÈwÐ_gÐ:NÓ:hÐimÕ:nÔoð !Ó.ˆDÜ˜DÖ!ñ /áøô ”Z×.Ñ.Ð/ô ?Ü�‰Ð8¸#×>Ñ>ûð?ûð !Ó.ˆDÜ˜DÖ!ò /úsJ   ÅBL Ç&L Ç:L ÈAL É"?L Ê78L ÌMÌ!L<Ì7M Ì<MÍM ÍMc          
     ó,   € V ^8„  d   QhRRRRRRRRR	R
/# )r   rŸ   ry   rÁ   r   r    rS   r  r=   r   ztuple[list[str], bool]r   )r   s   "r   r   r   s  s4   € ÷ 6)ñ 6)Øð6)Ø),ð6)Ø7Kð6)Øbfð6)àñ6)r   c               óÂ  aaaaaaa€ V '       g   \        R4      hV  Fb  p\        V4      P                  4       P                  pVSP                  8”  g   K9  \        RSP
                   RV RSP                   RV 24      h	  \        V4      o. oR^ uooR VVVVVVV3R llo\        V S4      pV UUu. uF  pS! V4       F  qDNK  	  K  	  ppp. p	\        V^R	7       EF4  w  r«Sp\        V4      ^8”  dK   SP                  SP                   R
V
R \        V4      P                  ;'       g    SP                   24      p\        P                  P                  V4      \        P                  P                  V4      8w  d4   VP                  P!                  RRR7       \        P"                  ! W¼4       VP                  4       P                  SP                  8”  d   \        RSP
                   RV 24      hV	P%                  \'        V4      4       EK7  	   V	S3S F  pWÙ9  g   K  \)        V4       K  	  # u uppi   S F  pYÙ9  g   K  \)        T4       K  	  i ; i)ae  Pack final-encoded chunks under the hard upload limit -> ``(final_paths, combined_any)``.

Groups are packed against the conservative target, then each combined artifact is checked
at its real size; an over-limit group is split in half and retried. A failed combine
returns the constituent files separately. A single chunk above the hard limit fails closed.z!No final-encoded TTS audio chunksz Final-encoded TTS chunk exceeds z delivery limit (z > z	 bytes): Fc               ó    € V ^8„  d   QhRRRR/# )r   Úgroupry   r   r   )r   s   "r   r   Ú1_build_audio_delivery_files.<locals>.__annotate__‡  s   € ÷ ?ñ ?�Ið ? )ñ ?r   c           	     óN  <€ \        V 4      ^8X  d   \        V 4      # S^,          oSP                  RSP                   RSR R\        P
                  ! 4       P                   SP                   24      p\        V \        V4      S
R7      pV'       g   \        V 4      # S	P                  V4       \        V4      P                  4       P                  SP                  8:  d   RoV.# \        V4       \!        ^\        V 4      ^,          4      pS! V RV 4      S! WR 4      ,           # )é   rÄ   z	.deliveryÚ03d)r  TN)r…   Úlistr;  r?  r<  r=  r>  r¤   rI  r   r†   r   r¢   r£   rU   r¿   r\   )rM  ÚscratchÚcombinedÚmidpointÚbaseÚcombine_indexÚcombined_anyÚemitr    Úscratch_outputsr  s   &   €€€€€€€r   rY  Ú)_build_audio_delivery_files.<locals>.emit‡  sü   ø€ äˆu‹:˜Œ?Ü˜“;ÐØ˜ÕˆØ—.‘. 1 T§Y¡Y K¨y¸ÀsÐ8KÈ1ÌTÏZÊZË\×M]ÑM]ÐL^Ð_c×_jÑ_jÐ^kÐ!lÓmˆÜ& u¬c°'«lÐM]Ô^ˆßÜ˜“;ÐØ×Ñ˜xÔ(Ü�‹>×ÑÓ ×(Ñ(¨G×,BÑ,BÔBØˆLØ�:ÐÜ˜Ô!Ü�qœ#˜e›*¨�/Ó*ˆÙ�E˜)˜8Ð$Ó%©¨U°9Ð-=Ó(>Õ>Ð>r   )Ústartz.partÚ02dTr  zFinal TTS deliverable exceeds z delivery limit: )r8  r   r¢   r£   rU   rT   rª   Ú	enumerater…   r;  r?  r¤   r¼   r¨   r&  r9  r:  r  r†   r   r¿   )rŸ   rÁ   r    r  r¨   r©   r¥   rM  ÚpackedÚfinal_pathsÚindexÚsourcerD  rS  rV  rW  rX  rY  rZ  s   &&fd          @@@@@r   Ú_build_audio_delivery_filesrc  s  s!  þ€ ÷ ÜÐ<Ó=Ð=ÛˆÜ�D‹z�‰Ó ×(Ñ(ˆØ�'×(Ñ(Ö(ÜØ2°7×3CÑ3CÐ2Dð EØ˜˜s 7×#9Ñ#9Ð":¸)ÀDÀ6ðKóLð Lñ ô �Ó€DØ!#€OØ"'¨Ð€L�-÷?ö ?ô  ,¨K¸ÓA€FÙ &Ô?¡�u±4¸¶;¨4Šd±;‰d¡€FÑ?Ø€KÜ" 6°×3Ð3‰ˆØˆÜˆv‹;˜Œ?ØŸ.™.¨D¯I©I¨;°e¸EÀ#¸;ÄtÈFÃ|×GZÑGZ×GiÐGiÐ^b×^iÑ^iÐFjÐ)kÓlˆKÜ�7‰7�?‰?˜6Ó"¤b§g¡g§o¡o°kÓ&BÔBØ×Ñ×$Ñ$¨T¸DÐ$ÔAÜ�JŠJ�vÔ+Ø×ÑÓ×%Ñ%¨×(>Ñ(>Ô>ÜÐ=¸g×>NÑ>NÐ=OÐO`ÐalÐ`mÐnÓoÐoØ×Ñœ3˜{Ó+×,ñ 4ð)Ø˜LÐ(ã&ˆGØÖ)Ü Ö(ò 'ùó @øó 'ˆGØÖ)Ü Ö(ò 'ús   Â5H:ÈI  É 	IÉIr~   )z-acodecr1  r2  r3  r4  r  r6  Úonz-applicationÚvoipz-compression_levelÚ10i    i   )>Ú__conditional_annotations__rd   Ú
__future__r   Úloggingr¼   rš   r$  rÏ   rÚ   rµ   rî   r<  Údataclassesr   Úpathlibr   Útypingr   r   r   r   r	   Úhermes_cli._subprocess_compatr
   Útools.tts_command_providerr   r   r   r   Ú	getLoggerrö   r   r$   rG   r/   re   r8   r>   rP   ÚGEMINI_TTS_SAMPLE_RATEÚGEMINI_TTS_CHANNELSÚGEMINI_TTS_SAMPLE_WIDTHrñ   rS   rk   ru   rŒ   r‘   r�   rª   r¸   r¿   rÇ   rÒ   rá   rý   r  r  r  rI  rc  )rg  s   @r   Ú<module>rs     s  øðôõ #ã Û 	Û 	Û Û Û Û Û Û Ý !Ý ß 3Õ 3å <÷!ó !ð 
×	Ò	Ð+Ó	,€òõ8ð  Ð ð ˆDØˆdØ	ˆ5ØˆuØˆtØˆeØ�%ØˆdØ�ØˆTð,Ð ˜.ó ð ��¨Ø˜eÐ%=¸uØ˜UÐ$;¸UØ�uÐ1°5ð	4:Ð   .ó :õc÷
$ð: HMÈaÐQRÐ DÐ Ð+Ð-Dò8Ð ñ �$Ô÷
Dð 
Dó ð
Dð Ð Ð"2°NÀDÐIØÐ!Ð#3°^ÀTÐJØÐ Ð"2°NÀDÐIð7KÐ Ð3ó K÷oð ÐRW÷ õ0Nõ
0õ$5ð XØ46ðXØFKðXØ]a÷Xõõcõ
ð  *@Ø'Ð=T÷
Cõõ:wõõð,$Ð^c÷ $ðN6)Øin÷6)ñ 6)r   