+
    lHàjI%  ã                  óz  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIHt ^ RI	H
t
HtHtHt ^ RIHtHtHtHt ]P&                  ! R4      tRtRtR	t]! ]4      P2                  R
,          t^t/ tR]R&   / tR]R&   R]R]/tR]R&   R R lt R R lt!R R lt"R R lt#R R lt$R R lt%R$t&R R lt'R  R! lt(R" R# lt)R# )%aÀ  Local on-device TTS engines for ``tools.tts_tool``: NeuTTS, Piper, KittenTTS.

All three synthesize WAV natively; :func:`_finalize_wav_output` converts/renames to the requested
container. Piper and KittenTTS keep loaded models in small LRU caches registered in
``_LOCAL_TTS_MODEL_CACHES`` so warm/release can pre-load or drop them. ``_import_piper`` /
``_import_kittentts`` are resolved through the origin module at call time (test monkeypatches).
)ÚannotationsN)ÚPath)ÚAnyÚCallableÚDictÚTuple)Ú_finalize_wav_outputÚ_originÚ_sectionÚ_wav_sidecar_pathztools.tts_toolz!KittenML/kitten-tts-nano-0.8-int8ÚJasperzen_US-lessac-mediumÚneutts_samplesúdict[str, Any]Ú_piper_voice_cacheÚ_kittentts_model_cacheÚpiperÚ	kittenttszdict[str, dict[str, Any]]Ú_LOCAL_TTS_MODEL_CACHESc               ó(   € V ^8„  d   QhRRRRRRRR/# )	é   Úcacher   ÚkeyÚstrÚloadzCallable[[], Any]Úreturnr   © )Úformats   "Ú9/home/ubuntu/.hermes/hermes-agent/tools/tts_tool_local.pyÚ__annotate__r   (   s*   € ÷ 
ñ 
 .ð 
°sð 
ÐBSð 
ÐX[ñ 
ó    c                óÒ   € W9   d   V P                  V4      W&   W,          # V! 4       pW0V&   \        V 4      \        8”  d'   V P                  \        \	        V 4      4      R4       K:  V# )z²Get ``key`` from ``cache`` or load it, LRU-bounded at ``_TTS_MODEL_CACHE_MAX`` (a hit refreshes
recency via pop + reinsert; eviction only releases the slot, not live references).N)ÚpopÚlenÚ_TTS_MODEL_CACHE_MAXÚnextÚiter)r   r   r   Úvalues   &&& r   Ú_tts_cache_get_or_loadr'   (   sW   € ð „|Ø—Y‘Y˜s“^ˆ‰
Ø�zÐÙ‹F€EØˆ#�JÜ
ˆe‹*Ô+Ô
+Ø�	‰	”$”t˜E“{Ó# TÖ*Ø€Lr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   ÚcmdÚlistÚtimeoutÚintr   zsubprocess.CompletedProcessr   )r   s   "r   r   r   5   s"   € ÷ ñ �Tð  Cð Ð,Gñ r   c                óZ   € \         P                  ! V R R RRV\         P                  RR7      # )Tzutf-8ÚreplaceF)Úcapture_outputÚtextÚencodingÚerrorsr+   ÚstdinÚcheck)Ú
subprocessÚrunÚDEVNULL)r)   r+   s   &&r   Ú_run_helperr8   5   s-   € Ü�>Š>Ø˜D t°gÀiÐY`Ôhr×hzÑhzØôð r   c               ó(   € V ^8„  d   QhRRRRRRRR/# ©r   r0   r   Úoutput_pathÚ
tts_configr   r   r   )r   s   "r   r   r   =   s)   € ÷ 7ñ 7˜3ð 7¨Sð 7¸nð 7ÐQTñ 7r   c                ó(  € VP                  R 4      ;'       g    / p\        V4      p\        P                  \	        \        \        4      P                  R,          4      RT RTRVP                  RR4      ;'       g    \	        \        R,          4      RVP                  R	R4      ;'       g    \	        \        R
,          4      RVP                  RR4      RVP                  RR4      .p\        V^x4      pVP                  ^ 8w  d€   VP                  P                  4       P                  4        Uu. uF  qwP                  R4      '       d   K  VNK  	  pp\        R\!        ^
4      P#                  V4      ;'       g    R 24      h\%        WA4      # u upi )Úneuttszneutts_synth.pyz--textz--outz--ref-audioÚ	ref_audioÚ zjo.wavz
--ref-textÚref_textzjo.txtz--modelÚmodelzneuphonic/neutts-air-q4-ggufz--deviceÚdeviceÚcpuzOK:zNeuTTS synthesis failed: zunknown error)Úgetr   ÚsysÚ
executabler   r   Ú__file__ÚparentÚ_NEUTTS_SAMPLESr8   Ú
returncodeÚstderrÚstripÚ
splitlinesÚ
startswithÚRuntimeErrorÚchrÚjoinr   )	r0   r;   r<   Úneutts_configÚwav_pathr)   ÚresultÚlÚerror_liness	   &&&      r   Ú_generate_neuttsrX   =   sO  € Ø—N‘N 8Ó,×2Ð2°€MÜ  Ó-€Hä�‰œœD¤›N×1Ñ1Ð4EÕEÓFØ�$Ø�Ø�}×(Ñ(¨°bÓ9×\Ð\¼SÄÐS[ÕA[Ó=\Ø�m×'Ñ'¨
°BÓ7×ZÐZ¼3¼ÐQYÕ?YÓ;ZØ�=×$Ñ$ WÐ.LÓMØ�M×%Ñ% h°Ó6ð8€Cô ˜˜cÓ"€FØ×Ñ˜AÔØ"(§-¡-×"5Ñ"5Ó"7×"BÑ"BÔ"DÓ`Ñ"D˜QÏLÉLÐY^×L_—q�qÑ"DˆÐ`ÜÐ6´s¸2³w·|±|ÀKÓ7P×7cÐ7cÐTcÐ6dÐeÓfÐfÜ Ó6Ð6ùò as   Ä/FÅFc               ó   € V ^8„  d   QhRR/# )r   r   r   r   )r   s   "r   r   r   P   s   € ÷ ñ ˜tñ r   c                 ó\   € ^ RI Hp  \        V ! RR4      4      pVP                  RRR7       V# )zS``<HERMES_HOME>/cache/piper-voices/`` so voice downloads follow profile boundaries.)Úget_hermes_dirzcache/piper-voicesÚpiper_voices_cacheT©ÚparentsÚexist_ok)Úhermes_constantsr[   r   Úmkdir)r[   Úroots     r   Ú_get_piper_voices_dirrc   P   s-   € å/Ü‘Ð3Ð5IÓJÓK€DØ‡J�J�t d€JÔ+Ø€Kr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úvoicer   Údownload_dirr   r   r   )r   s   "r   r   r   X   s!   € ÷ ñ  Sð ¸ð Àñ r   c           
     óR  € T ;'       g    \         p \        V 4      P                  4       pVP                  P	                  4       R8X  d"   VP                  4       '       d   \        V4      # W R2,          pVP                  4       '       d+   W R2,          P                  4       '       d   \        V4      # \        P                  RW4        \        \        P                  RRV R\        V4      .R4      pTP                  ^ 8w  dG   TP                   ;'       g    RP#                  4       ;'       g    Rp\        RT  RTR,           24      hTP                  4       '       g   \        RT R24      h\        T4      #   \        P                   d   p\        RT  R	24      ThR
p?ii ; i)z¬Resolve *voice* (an .onnx path or a name like ``en_US-lessac-medium``, downloaded into
*download_dir* on first use) to a concrete .onnx file; RuntimeError when it can't be.z.onnxz
.onnx.jsonz0[Piper] Downloading voice '%s' to %s (first use)z-mzpiper.download_voicesz--download-diri,  z/Piper voice download timed out after 300s for 'Ú'Nr@   zno stderr outputz!Piper voice download failed for 'z': :Ni�  Nz#Piper voice download completed but uh    is missing â€” check voice name (see: https://github.com/OHF-Voice/piper1-gpl/blob/main/docs/VOICES.md))ÚDEFAULT_PIPER_VOICEr   Ú
expanduserÚsuffixÚlowerÚexistsr   ÚloggerÚinfor8   rF   rG   r5   ÚTimeoutExpiredrP   rK   rL   rM   )re   rf   Ú	candidateÚcachedrU   ÚexcrL   s   &&     r   Ú_resolve_piper_voice_pathrt   X   s†  € ð ×(Ð(Ô(€EÜ�U“×&Ñ&Ó(€IØ×Ñ×ÑÓ 7Ô*¨y×/?Ñ/?×/AÒ/AÜ�9‹~ÐØ˜g U˜OÕ+€FØ‡}�}‡‚˜L¨W°JÐ+?Õ?×GÑG×IÒIÜ�6‹{ÐÜ
‡K�KÐBÀEÔXð`ÜÜ�^‰^˜TÐ#:¸EÐCSÔUXÐYeÓUfÐgÐiló
ˆð
 ×Ñ˜AÔØ—-‘-×%Ð% 2×,Ñ,Ó.×DÐDÐ2DˆÜÐ>¸u¸gÀSÈÐPTÍÈÐWÓXÐXØ�=‰=�?Š?ÜØ1°&°ð :(ð )ó*ð 	*ô ˆv‹;Ðøô ×$Ñ$ô `ÜÐLÈUÈGÐSTÐUÓVÐ\_Ð_ûð`ús   Ã)E< Å<F&ÆF!Æ!F&c               ó    € V ^8„  d   QhRRRR/# ©r   r<   r   r   ztuple[Any, dict[str, Any]]r   )r   s   "r   r   r   t   s   € ÷ bñ b¨^ð bÐ@Zñ br   c                ó¶  aaa€ \        4       P                  4       o\        V R4      pVP                  R4      ;'       g    \        p\        VP                  R4      ;'       g    \        4       4      P                  4       pVP                  RRR7       \        VP                  RR4      4      o\        W#4      oVVV3R lpS R	S 2p\        \        WT4      V3# )
z½Resolve + load (or fetch from cache) the selected Piper voice -> ``(voice, piper_config)``.
Shared by synthesis and ``warm_tts_provider`` so a warm-up fills exactly the slot synthesis hits.r   re   Ú
voices_dirTr]   Úuse_cudaFc                 ó„   <€ \         P                  R S4       SP                  SSR7      p \         P                  R4       V # )z[Piper] Loading voice: %s)ry   z[Piper] Voice loaded)rn   ro   r   )ÚvÚ
PiperVoiceÚ
model_pathry   s    €€€r   Ú_load_piper_voiceÚ7_load_piper_voice_for_config.<locals>._load_piper_voice   s6   ø€ Ü�‰Ð/°Ô<Ø�O‰O˜J°ˆOÓ:ˆÜ�‰Ð*Ô+Øˆr   z::cuda=)r	   Ú_import_piperr
   rE   ri   r   rc   rj   ra   Úboolrt   r'   r   )	r<   Úpiper_configÚ
voice_namerf   r~   Ú	cache_keyr|   r}   ry   s	   &     @@@r   Ú_load_piper_voice_for_configr…   t   sÃ   ú€ ô “×(Ñ(Ó*€JÜ˜J¨Ó0€LØ×!Ñ! 'Ó*×AÐAÔ.A€JÜ˜×(Ñ(¨Ó6×QÐQÔ:OÓ:QÓR×]Ñ]Ó_€LØ×Ñ˜t¨dÐÔ3Ü�L×$Ñ$ Z°Ó7Ó8€HÜ*¨:ÓD€J÷ð �,˜g h ZÐ0€IÜ!Ô"4°iÓSÐUaÐaÐar   c               ó(   € V ^8„  d   QhRRRRRRRR/# r:   r   )r   s   "r   r   r   �   s)   € ÷ 7ñ 7˜cð 7°ð 7Àð 7ÐTWñ 7r   c                óh  a€ ^ RI p\        V4      w  poSP                  R^ 4      p\        V4      \        J d   TM^ pRp\
        ;QJ d#    V3R l\         4       F  '       g   K   RM	  RM! V3R l\         4       4      '       d“    ^ RIHp V! \        SP                  RR4      4      \        SP                  R	R
4      4      \        SP                  RR4      4      \        SP                  RR4      4      \        SP                  RR4      4      VR7      p\        V4      p	VP                  V	R4      ;_uu_ 4       p
Ve   VP!                  W
VR7       MVP!                  W
4       RRR4       \#        W‘4      #   \         d    \        P                  R4        L„i ; i  + '       g   i     LA; i)é    NÚ
speaker_idc              3  ó,   <"  € T F	  qS9   x € K  	  R # 5i)Nr   )Ú.0Úkr‚   s   & €r   Ú	<genexpr>Ú&_generate_piper_tts.<locals>.<genexpr>–   s   øé € Ð
<Ñ&; �ÖÓ&;ùs   ƒTF)ÚSynthesisConfigÚlength_scaleç      ð?Únoise_scalegòÒMbXå?Únoise_w_scalegš™™™™™é?ÚvolumeÚnormalize_audio©r�   r’   r“   r”   r•   r‰   uZ   [Piper] SynthesisConfig not available in this piper-tts version â€” advanced knobs ignoredÚwb)Ú
syn_config)Úwaver…   rE   Útyper,   ÚanyÚ_PIPER_ADVANCED_KNOBSr   r�   Úfloatr�   ÚImportErrorrn   Úwarningr   ÚopenÚsynthesize_wavr   )r0   r;   r<   r™   re   Ú_raw_speakerr‰   r˜   r�   rT   Úwav_filer‚   s   &&&        @r   Ú_generate_piper_ttsr¤   �   se  ø€ ÛÜ6°zÓBÑ€Eˆ<à×#Ñ# L°!Ó4€LÜ!% lÓ!3´sÓ!:‘À€Jð €Jß
ƒsÔ
<Õ&;Ó
<‡s‡s‚sÔ
<Õ&;Ó
<×<Ò<ð
	yÝ-Ù(Ü" <×#3Ñ#3°NÀCÓ#HÓIÜ! ,×"2Ñ"2°=À%Ó"HÓIÜ# L×$4Ñ$4°_ÀcÓ$JÓKÜ˜\×-Ñ-¨h¸Ó<Ó=Ü $ \×%5Ñ%5Ð6GÈÓ%NÓ OØ%ô'ˆJô ! Ó-€HØ	�‰�8˜T×	"Ô	" hØÒ!Ø× Ñ  ¸JÐ ÕGà× Ñ  Ô0÷	 
#ô
   Ó6Ð6øô ô 	yÜ�N‰NÐwÖxð	yú÷ 
#×	"ús   ÂBE; Ä>*F!Å; FÆFÆ!F1	c               ó    € V ^8„  d   QhRRRR/# rv   r   )r   s   "r   r   r   ¬   s   € ÷ hñ h°ð hÐD^ñ hr   c                ó®   aa€ \        4       P                  4       o\        V R4      pVP                  R\        4      oVV3R lp\        \        SV4      V3# )zVLoad (or fetch from cache) the KittenTTS model; returns ``(model, kittentts_config)``.r   rB   c                 ón   <€ \         P                  R S4       S! S4      p \         P                  R4       V # )z[KittenTTS] Loading model: %sz%[KittenTTS] Model loaded successfully)rn   ro   )ÚmÚ	KittenTTSÚ
model_names    €€r   Ú_load_kittentts_modelÚ?_load_kittentts_model_for_config.<locals>._load_kittentts_model²   s.   ø€ Ü�‰Ð3°ZÔ@Ù�jÓ!ˆÜ�‰Ð;Ô<Øˆr   )r	   Ú_import_kittenttsr
   rE   ÚDEFAULT_KITTENTTS_MODELr'   r   )r<   Ú	kt_configr«   r©   rª   s   &  @@r   Ú _load_kittentts_model_for_configr°   ¬   sN   ù€ ä“	×+Ñ+Ó-€IÜ˜ [Ó1€IØ—‘˜wÔ(?Ó@€Jöô "Ô"8¸*ÐF[Ó\Ð^gÐgÐgr   c               ó(   € V ^8„  d   QhRRRRRRRR/# r:   r   )r   s   "r   r   r   »   s)   € ÷ 7ñ 7˜cð 7°ð 7Àð 7ÐTWñ 7r   c           	     ó  € \        V4      w  r4VP                  WP                  R \        4      VP                  RR4      VP                  RR4      R7      p^ RIp\        V4      pVP                  WuR4       \        Wq4      # )re   Úspeedr‘   Ú
clean_textT)re   r³   r´   NiÀ]  )r°   ÚgeneraterE   ÚDEFAULT_KITTENTTS_VOICEÚ	soundfiler   Úwriter   )r0   r;   r<   rB   r¯   ÚaudioÚsfrT   s   &&&     r   Ú_generate_kittenttsr»   »   sv   € Ü7¸
ÓCÑ€EØ�N‰NØ—M‘M 'Ô+BÓCØ�m‰m˜G SÓ)°i·m±mÀLÐRVÓ6Wð ó Y€Eó Ü  Ó-€HØ‡H�HˆX˜eÔ$Ü Ó6Ð6r   r–   )*Ú__conditional_annotations__Ú__doc__Ú
__future__r   Úloggingr5   rF   Úpathlibr   Útypingr   r   r   r   Útools.tts_tool_deliveryr   r	   r
   r   Ú	getLoggerrn   r®   r¶   ri   rH   rI   rJ   r#   r   Ú__annotations__r   r   r'   r8   rX   rc   rt   r…   rœ   r¤   r°   r»   )r¼   s   @r   Ú<module>rÅ      sÕ   øðôõ #ã Û Û 
Ý ß -Ó -ç ^Ó ^à	×	Ò	Ð+Ó	,€à=Ð Ø"Ð Ø+Ð Ù�x“.×'Ñ'Ð*:Õ:€ð
 Ð ð
 &(Ð �NÓ 'Ø)+Ð ˜Ó +àÐ Ð.Dð6FÐ Ð2ó Fõ
õõ7õ&õõ8bð, tÐ õ7õ>h÷7r   