+
    lHàjß¢  ã                  óŽ  a€ 0 t $ R t^ RIH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Ht ^ RIH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 ]P8                  ! ]4      tR	tR
t Rt!Rt"R
t#R
t$^t%^
t&^
t'RR‡/Rˆ U u/ uF  q R‰bK  	  up CRŠ U u/ uF  q R‹bK  	  up Ct(R])R&   RŒt* ! R R]+4      t,RRRRRRRRRRRRRRR]%RR/	t-R ])R!&   R"t.]/! 0 R�m4      t0R# R$ lt1R% R& lt2R' R( lt3R) R* lt4R+R/R, R- llt5R. R/ lt6R0 R1 lt7R2 R3 lt8RŽR4 R5 llt9RŽR6RR7R/R8 R9 lllt:R: R; lt;R< R= lt<RŽR> R? llt=R@ RA lt>RB RC lt?RD t@RE RF ltARŽRG RH lltBRI RJ ltCRK RL ltDRM RN ltERO RP ltFRQ RR ltGRŽR+R/RS RT llltH] ! RU RV4      4       tI ! RW RX4      tJRsKRY])RZ&   RsLR[])R\&   RsM]
Pœ                  ! 4       tOR] R^ ltPR_ R` ltQRŽRa Rb lltRRc Rd ltSRe Rf ltTRg Rh ltURi Rj ltVRkRRlR/Rm Rn lltWRŽRo Rp lltXRq Rr ltYRs Rt ltZRu Rv lt[Rw Rx lt\Ry Rz lt]R{ R| lt^R} R~ lt_RŽR R€ llt`R� R‚ ltaRƒ R„ ltbR… R† ltcR# u up i u up i )�u%  Wake-word ("Hey Hermes") detection â€” hands-free session trigger.

One always-on hotword listener shared by CLI, TUI and desktop GUI (a single owner,
gated by ``wake_surface_enabled``). Engines live in :mod:`tools.wake_word_engines`;
this module owns config, the capture loop and the process-wide listener singleton.
Capture reuses voice mode's 16 kHz mono int16 ``sounddevice`` path on a daemon
thread; callers ``pause()`` while a voice turn holds the mic and ``resume()`` once
idle (two input streams on one device is unreliable cross-platform).
)Úannotations)Úinstall_hintN)Úsuppress)Ú	dataclass)ÚPath)ÚAnyÚCallableÚDictÚOptional)Ú_EngineÚ_OpenWakeWordEngineÚ_PorcupineEngineÚ_SherpaKwsEnginei€>  ç       @g      @gš™™™™™©?Ú	porcupinezdict[str, tuple[str, str]]Ú
_PROVIDERSc                  ó   € ] tR t^EtRtRtR# )ÚWakeWordInUsezCRaised when another surface or process owns the wake-word listener.© N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__static_attributes__r   ó    Ú4/home/ubuntu/.hermes/hermes-agent/tools/wake_word.pyr   r   E   s   † ÝMr   r   ÚenabledFÚsurfaceÚautoÚinput_deviceÚcaptureÚproviderÚphraseú
hey hermesÚsensitivityg333333ã?Úconfirmation_framesÚstart_new_sessionTúdict[str, Any]Ú	_DEFAULTSÚ
hey_hermesc               ó   € V ^8„  d   QhRR/# ©é   ÚreturnÚstrr   )Úformats   "r   Ú__annotate__r1   Y   s   € ÷ añ a ñ ar   c                 ó”   € \         P                  P                  \         P                  P                  \        4      R\
         R24      # )uK   Path to the shipped hey_hermes.tflite â€” pyopen-wakeword runs TFLite only.Ú	wakewordsz.tflite)ÚosÚpathÚjoinÚdirnameÚ__file__Ú_BUNDLED_MODEL_NAMEr   r   r   Ú_bundled_wakeword_pathr:   Y   s0   € ä�7‰7�<‰<œŸ™Ÿ™¬Ó1°;ÔCVÐBWÐW^Ð@_Ó`Ð`r   c               ó   € V ^8„  d   QhRR/# ©r-   r.   r(   r   )r0   s   "r   r1   r1   ^   s   € ÷ 0ñ 0˜~ñ 0r   c                 óØ   € Rp \        \        4      ;_uu_ 4        ^ RIHp V! 4       P	                  R4      p RRR4       \        V \        4      '       d   V # / #   + '       g   i     L*; i)zAReturn the ``wake_word`` config section, shape-guarded to a dict.N)Úload_configÚ	wake_word)r   Ú	ExceptionÚhermes_cli.configr>   ÚgetÚ
isinstanceÚdict)Úcfgr>   s     r   Úload_wake_word_configrF   ^   sN   € à
€CÜ	”)×	Õ	Ý1Ù‹m×Ñ Ó,ˆ÷ 
ô ˜S¤$×'Ò'ˆ3Ð/¨RÐ/÷ 
×	ús   šAÁA)	c               ó$   € V ^8„  d   QhRRRRRR/# )r-   rE   r(   Úkeyr/   r.   r   r   )r0   s   "r   r1   r1   g   s!   € ÷ 6ñ 6ˆnð 6 3ð 6¨3ñ 6r   c                óZ   € V P                  V4      pVf   \        P                  V4      # T# ©N)rB   r)   )rE   rH   Úvals   && r   Ú_getrL   g   s'   € Ø
�'‰'�#‹,€CØ!$¢Œ9�=‰=˜ÓÐ5°#Ð5r   c               ó    € V ^8„  d   QhRRRR/# )r-   rE   r(   rH   r/   r   )r0   s   "r   r1   r1   l   s   € ÷ ñ �.ð  sñ r   c                ó¤   €  V! \        W4      4      p\	        \        WS4      V4      #   \        \        3 d    T! \        T,          4      p L;i ; i)zINumeric config value via ``cast``, defaulting on junk, clamped to lo..hi.)rL   Ú	TypeErrorÚ
ValueErrorr)   ÚminÚmax)rE   rH   ÚcastÚloÚhiÚns   &&&&& r   Ú_clampedrW   l   sL   € ð!Ù”�c“Ó ˆô Œs�1‹z˜2ÓÐøô ”zÐ"ô !Ù”˜3•Ó Šð!ús   ‚( ¨$AÁAÚ	supportedc               ó$   € V ^8„  d   QhRRRRRR/# )r-   rE   r(   rX   úCallable[[str], bool] | Noner.   r/   r   )r0   s   "r   r1   r1   u   s(   € ÷ hñ h�>ð hÐ1Mð hÐY\ñ hr   c               óØ   a€ \        \        V R 4      4      P                  4       P                  4       ;'       g    RpVR8w  d   V# Sf	   ^ RIHp Vo\        V3R l\         4       R4      # )r"   r   ©Úextra_supportedc              3  ól   <"  € T F)  pS! \         V,          ^,          4      '       g   K%  Vx € K+  	  R# 5i)é   N)r   )Ú.0ÚnamerX   s   & €r   Ú	<genexpr>Ú_provider.<locals>.<genexpr>|   s'   øé € ÐYÑ"6˜$¹)ÄJÈtÕDTÐUVÕDW×:X—’Ó"6ùs   ƒ"4ª
4r   )r/   rL   ÚstripÚlowerÚ	pm.extrasr]   ÚnextÚ_PROVIDER_PREFERENCE)rE   rX   r"   r]   s   &d  r   Ú	_providerri   u   s^   ø€ Ü”4˜˜ZÓ(Ó)×/Ñ/Ó1×7Ñ7Ó9×CÐC¸V€HØ�6ÔØˆØÒÝ-Ø#ˆ	ÜÔYÕ"6ÓYÐ[fÓgÐgr   c               ó    € V ^8„  d   QhRRRR/# )r-   rE   r(   r.   úint | str | Noner   )r0   s   "r   r1   r1      s   € ÷ yñ y�~ð yÐ*:ñ yr   c                óÈ   € \        V R4      p\        V\        4      '       d   R# Ve   \        V\        4      '       d   V# \	        V4      P                  4       ;'       g    R# )zBConfigured PortAudio input selector, preserving indices and names.r    N)rL   rC   ÚboolÚintr/   rd   )rE   Úraws   & r   Ú_input_devicerp      sT   € ä
ˆs�NÓ
#€CÜ˜c¤4×(Ò(ˆ4Ðx°S²[ÄJÈsÔTW×DXÒDX¨cÐxÔ_bÐcfÓ_g×_mÑ_mÓ_o×_wÐ_wÐswÐxr   c               ó    € V ^8„  d   QhRRRR/# )r-   rE   r(   r.   Úfloatr   )r0   s   "r   r1   r1   …   s   € ÷ 9ñ 9�nð 9¨ñ 9r   c                ó(   € \        V R \        RR4      # )r%   ç        ç      ð?)rW   rr   ©rE   s   &r   Ú_sensitivityrw   …   s   € Ü�C˜¬¨s°CÓ8Ð8r   c               ó    € V ^8„  d   QhRRRR/# )r-   rE   r(   r.   rn   r   )r0   s   "r   r1   r1   ‰   s   € ÷ <ñ <˜nð <°ñ <r   c                ó(   € \        V R\        ^^
4      # )zUConsecutive over-threshold frames required to fire, clamped 1..10 (1 = single-frame).r&   )rW   rn   rv   s   &r   Ú_confirmation_framesrz   ‰   s   € ä�CÐ.´°Q¸Ó;Ð;r   c               ó    € V ^8„  d   QhRRRR/# )r-   rE   úOptional[dict[str, Any]]r.   r/   r   )r0   s   "r   r1   r1   Ž   s   € ÷ 4ñ 4Ð-ð 4¸ñ 4r   c                ó`   € V e   T M	\        4       p \        \        V R4      4      ;'       g    R# )zHHuman-facing wake phrase label (purely cosmetic; engine keys detection).r#   r$   )rF   r/   rL   rv   s   &r   Úwake_phraser~   Ž   s+   € à’‰#Ô&;Ó&=€CÜŒt�C˜Ó"Ó#×3Ð3 |Ð3r   Úprefer_clientÚforce_localc               ó(   € V ^8„  d   QhRRRRRRRR/# )r-   rE   r|   r   rm   r€   r.   r/   r   )r0   s   "r   r1   r1   ”   s2   € ÷ iñ iÐ6ð iÐQUð iØ&*ðiØ7:ñir   c               ó  € V e   T M	\        4       p V'       d   R# \        \        V R4      ;'       g    R4      P                  4       P	                  4       pVR9   d   R# VR8w  d   V'       d   \        4       '       g   R# R# )u  Return ``local`` or ``client`` capture mode for this arm. ``prefer_client`` is set by remote
desktop; ``force_local`` keeps CLI/TUI on the process mic. Under ``auto`` a working backend input
always wins; client is the fallback only for a preferring surface with no usable backend mic â€”
CLI/TUI stay local so status reports the real requirement rather than a path nothing will feed.Úlocalr!   r   Úclient)r„   ÚremoteÚexternal)rF   r/   rL   rd   re   Ú_local_input_device_ready)rE   r   r€   ro   s   &$$ r   Úresolve_capture_moderˆ   ”   sm   € ð ’‰#Ô&;Ó&=€CßÙÜ
Œd�3˜	Ó"×,Ð, fÓ
-×
3Ñ
3Ó
5×
;Ñ
;Ó
=€CØ
Ð.Ô.ÙØ˜g”~¯-Ô@Y×@[Ò@[ˆ8ÐhÐahÐhr   c               ó    € V ^8„  d   QhRRRR/# )r-   Úinfor   r.   rn   r   )r0   s   "r   r1   r1   £   s   € ÷ ñ ˜#ð  #ñ r   c                ó”   € \        V \        4      '       d   V P                  R 4      M\        V R ^ 4      p\	        T;'       g    ^ 4      # )Úmax_input_channels)rC   rD   rB   Úgetattrrn   )rŠ   Úchs   & r   Ú_input_channelsr�   £   s:   € Ü+5°d¼D×+AÒ+Aˆ�‰Ð&Ô	'ÄwÈtÐUiÐklÓGm€BÜˆr�wˆw�Q‹<Ðr   c               ó   € V ^8„  d   QhRR/# ©r-   r.   rm   r   )r0   s   "r   r1   r1   ¨   s   € ÷ ñ  4ñ r   c                 ó\  €  \        4       w  rV P                  4       p\        V\        4      '       d   \	        V4      ^ 8„  # \
        ;QJ d    R V 4       F  '       g   K   RM	  RM! R V 4       4      ;'       g    \	        V P                  RR4      4      ^ 8„  #   \         d     R# i ; i)zGTrue when PortAudio is importable and at least one input device exists.c              3  ó>   "  € T F  p\        V4      ^ 8„  x € K  	  R# 5i©é    N)r�   )r`   Úds   & r   rb   Ú,_local_input_device_ready.<locals>.<genexpr>°   s   é € Ð<±G¨q”O AÓ&¨Ö*³Gùs   ‚TFNÚinput)Ú_import_audioÚquery_devicesrC   rD   r�   Úanyr@   )ÚsdÚ_Údevicess      r   r‡   r‡   ¨   s—   € ð	Ü“‰ˆØ×"Ñ"Ó$ˆÜ�gœt×$Ò$Ü" 7Ó+¨aÑ/Ð/ç“Ñ<±GÓ<——’Ñ<±GÓ<Ó<÷ Hð HÜ" 2×#3Ñ#3°D¸'Ó#BÓCÀaÑGð	Iøäô Úðús)   ‚?B Á
B ÁB Á!B Á=B ÂB+Â*B+c               ó$   € V ^8„  d   QhRRRRRR/# )r-   r   r/   rE   r|   r.   rm   r   )r0   s   "r   r1   r1   ¶   s(   € ÷ Rñ R #ð RÐ,Dð RÐPTñ Rr   c                ó"  € Ve   TM	\        4       p\        \        VR4      4      P                  4       P	                  4       ;'       g    Rp\        VP                  R4      4      ;'       d$    VRV P                  4       P	                  4       39   # )u»   Should ``surface`` (cli/tui/gui) host the listener? True when enabled and the configured
surface is ``auto`` or this one; ``auto`` only makes it eligible â€” the lock admits one claimant.r   r   r   )rF   r/   rL   rd   re   rm   rB   )r   rE   Úwants   && r   Úwake_surface_enabledr¢   ¶   ss   € ð ’‰#Ô&;Ó&=€CÜŒt�C˜Ó#Ó$×*Ñ*Ó,×2Ñ2Ó4×>Ð>¸€DÜ�—‘˜	Ó"Ó#×QÐQ¨°¸¿¹»×9NÑ9NÓ9PÐ0QÑ(QÐQr   c               ó   € V ^8„  d   QhRR/# r,   r   )r0   s   "r   r1   r1   À   s   € ÷ ñ ˜cñ r   c                 óœ   € \        \        4      ;_uu_ 4        ^ RIHp  V ! 4       ;'       g    RuuRRR4       #   + '       g   i     R# ; i)r•   ©Úget_active_profile_nameÚdefaultN)r   r@   Úhermes_cli.profilesr¦   r¥   s    r   Ú_active_profile_namer©   À   s2   € Ü	”)×	Õ	Ý?Ù&Ó(×5Ð5¨I÷ 
×	×	Ñ	ñ ús	   ˜:ºA	c               ó   € V ^8„  d   QhRR/# )r-   r.   zdict[str, str]r   )r0   s   "r   r1   r1   Ç   s   € ÷ ñ  .ñ r   c                 óž  € / p \        \        4      ;_uu_ 4        ^ RIHp ^ RIHpHp V! 4        Fè  p\        VRR4      ;'       g    \        V4      p\        \        4      ;_uu_ 4        V! \        V! V4      4      R,          4      P                  R4      ;'       g    / p\        V\        4      '       dY   VP                  R4      '       dB   \        VP                  R4      ;'       g    R	V 24      P                  4       pV'       d   WpV&   RRR4       Kê  	  RRR4       V #   + '       g   i     EK  ; i  + '       g   i     T # ; i)
u"  Map ``profile name -> wake phrase`` for every wake-enabled profile, reading each profile's own
``config.yaml`` raw (``load_config()`` targets only the ACTIVE profile). Phrase defaults to
``"hey <profile>"``; the sherpa engine listens for all and routes to the match. Unreadable â†’ skipped.)Úread_user_config_raw)Úget_profile_dirÚlist_profilesra   Nzconfig.yamlr?   r   r#   zhey )r   r@   rA   r¬   r¨   r­   r®   r�   r/   r   rB   rC   rD   rd   )Úphrasesr¬   r­   r®   rŠ   ra   Úwcr#   s           r   Úenrolled_profile_phrasesr±   Ç   sø   € ð !€GÜ	”)×	Õ	Ý:ßFÙ!–OˆDÜ˜4 ¨Ó.×;Ð;´#°d³)ˆDÜœ)×$Õ$Ù)¬$©¸tÓ/DÓ*EÈÕ*UÓV×ZÑZÐ[fÓg×mÐmÐkm�Ü˜b¤$×'Ò'¨B¯F©F°9×,=Ò,=Ü  §¡¨Ó!1×!BÐ!B°t¸D¸6°]ÓC×IÑIÓK�FßØ(. ™÷ %Ñ$ñ $÷ 
ð €N÷ %×$Ñ$ú÷ 
Ö	ð €Nús<   š,D;Á#D;Á*A$D&ÃD&Ã,D&ÄD&ÄD;Ä&D8Ä1
D;Ä;E	c                 ó   € ^ RI p ^ RIpW3# r”   )ÚnumpyÚsounddevice)Únprœ   s     r   r™   r™   Ü   s   € ÛÛØˆ6€Mr   c               ó   € V ^8„  d   QhRR/# r‘   r   )r0   s   "r   r1   r1   â   s   € ÷ ñ ˜$ñ r   c                 óž   € \        \        \        4      ;_uu_ 4        \        \	        4       4      uuR R R 4       #   + '       g   i     R# ; i©NF)r   ÚImportErrorÚOSErrorrm   r™   r   r   r   Ú_audio_availabler»   â   s+   € Ü	”+œw×	'Õ	'Ü”M“OÓ$÷ 
(×	'×	'Ñ	'áús	   �;»A	c               ó    € V ^8„  d   QhRRRR/# )r-   Úselectorrk   r.   r(   r   )r0   s   "r   r1   r1   è   s   € ÷ ñ Ð%5ð À>ñ r   c                ó2  € RV /p T;'       g    \        4       ^ ,          pVP                  V R4      p\	        T\
        4      '       g   T# TP                  R4      '       d   \        TR,          4      TR&   RR\        3RR\        3RR	\        33 FC  w  rVp\	        TP                  T4      \        \        34      '       g   K3  T! Y5,          4      Y&&   KE  	  R	T9   d}   \        \        4      ;_uu_ 4        TP                  TR	,          4      p\	        T\
        4      '       d-   TP                  R4      '       d   \        TR,          4      TR&   RRR4       T# T#   \         d   p\        T4      TR&   Tu Rp?# Rp?ii ; i  + '       g   i     T# ; i)
z¯Resolve a PortAudio selector into JSON-safe diagnostics (``InputStream`` stays the
authority on whether the device actually opens). Imports sounddevice unless ``sd`` is given.r½   r˜   ÚerrorNra   rŒ   Údefault_samplerateÚhostapiÚhostapi_index)r™   rš   r@   r/   rC   rD   rB   rn   rr   r   Úquery_hostapis)	r½   rœ   ÚdetailsrŠ   ÚerH   Úout_keyrS   rÁ   s	   &&       r   Ú_describe_input_devicerÇ   è   sg  € ð  *¨8Ð4€GðØ×%Ð%”=“? 1Õ%ˆØ×Ñ ¨'Ó2ˆô �dœD×!Ò!ØˆØ‡x�x�×ÒÜ˜d 6�lÓ+ˆ�‰Ø 4Ð6JÌCÐPØ 4Ð6JÌEÐRÐU^Ð`oÔqtÐTuówÑˆ�dä�d—h‘h˜s“m¤c¬5 \×2Ô2Ù# D¥I›ˆGÓñwð ˜'Ô!Ü”i× Õ Ø×'Ñ'¨°Õ(@ÓAˆGÜ˜'¤4×(Ò(¨W¯[©[¸×-@Ò-@Ü%(¨°­Ó%9�˜	Ñ"÷ !ð €Nˆ7€Nøô! ô Ü˜q›6ˆ�ÑØ�ûðú÷ !Ö ð €Nús5   †E �$E Ã6AFÄ<FÅFÅ(E=Å7FÅ=FÆF	c               ó   € V ^8„  d   QhRR/# )r-   Úoutput_lengthrn   r   )r0   s   "r   r1   r1     s   € ÷ @ñ @°Cñ @r   c                ó@  € V P                  WP                  R7      P                  R4      pVP                  V8X  d,   V P                  WP                  R7      P                  R4      # VP                  ^ 8X  d   V P                  W P                  R7      # VP                  V8”  df   V P                  ^ VP                  V^,           V P                  R7      pV P                  P                  W4RR 4      V P                  V4      ,          pM[V P                  VP                  V P                  R7      pV P                  V P                  ^ VP                  ^,
          V4      Wc4      pV P                  V4      P                  RR4      P                  V P                  4      # )z?Convert one native-rate capture block to an exact engine frame.©ÚdtypeNiÿ  éÿÿÿÿi €ÿÿ)ÚasarrayÚfloat64ÚreshapeÚsizeÚint16ÚzerosÚlinspaceÚint64ÚaddÚreduceatÚdiffÚarangeÚinterpÚrintÚclipÚastype)rµ   ÚframerÉ   ÚsourceÚedgesÚvaluesÚsource_positionss   &&&    r   Ú_resample_audio_framerã     s1  € à�Z‰Z˜§Z¡ZˆZÓ0×8Ñ8¸Ó<€FØ‡{�{�mÔ#Ø�z‰z˜%§x¡xˆzÓ0×8Ñ8¸Ó<Ð<Ø‡{�{�aÔØ�x‰x˜¯X©XˆxÓ6Ð6Ø‡{�{�]Ô"ð —‘˜A˜vŸ{™{¨M¸AÕ,=ÀRÇXÁX�ÓNˆØ—‘—‘ ¨s°¨Ó4°r·w±w¸u³~ÕE‰ð Ÿ9™9 V§[¡[¸¿
¹
˜9ÓCÐØ—‘˜2Ÿ;™; q¨&¯+©+¸­/¸=ÓIÐK[ÓdˆØ�7‰7�6‹?×Ñ ¨Ó.×5Ñ5°b·h±hÓ?Ð?r   c               ó    € V ^8„  d   QhRRRR/# )r-   rÄ   r(   r.   r/   r   )r0   s   "r   r1   r1     s   € ÷ _ñ _˜~ð _°#ñ _r   c                ó´  € \         P                  R8X  d   R# \         P                  R8X  d   RMRpV P                  R4      p\        V P                  R4      ;'       g    R4      P	                  4       ;'       g    Vf   R	M
\        V4      p\        V P                  R
4      ;'       g    R4      P	                  4       pV'       d	   V RV R2MTpRV RV R2# )zEPlatform-specific remediation for an armed stream delivering silence.Údarwinz�Microphone delivers only silence. Grant the Hermes backend microphone access in System Settings > Privacy & Security > Microphone, then toggle the wake word.Úwin32z@Set wake_word.input_device to a different PortAudio input devicezCheck the selected input devicer½   ra   Ú úsystem defaultrÁ   z (Ú)z&Microphone delivers only silence from z. z, then toggle the wake word.)ÚsysÚplatformrB   r/   rd   )rÄ   Úfixr½   ÚlabelrÁ   s   &    r   Úsilent_audio_hintrï     sÈ   € ä
‡|�|�xÔñ9ô �l‰l˜gÔ%ñ NØ+Lð à�{‰{˜:Ó&€HÜ�—‘˜FÓ#×)Ð) rÓ*×0Ñ0Ó2×oÐoÈ8ÒK[Ñ7GÔadÐemÓan€EÜ�'—+‘+˜iÓ(×.Ð.¨BÓ/×5Ñ5Ó7€Gß&-ˆuˆg�R˜�y Ñ"°5€EØ3°E°7¸"¸S¸EÐA]Ð^Ð^r   c               ó    € V ^8„  d   QhRRRR/# )r-   rE   r(   r.   r   r   )r0   s   "r   r1   r1   $  s   € ÷ 3ñ 3�~ð 3¨'ñ 3r   c                óž   € \        V 4      pV\        9  d   \        R V: 24      h\        4       \        V,          ^ ,          ,          ! V 4      # )zUnknown wake_word provider: )ri   r   rP   Úglobals)rE   r"   s   & r   Ú_build_engineró   $  sB   € Ü˜‹~€HØ”zÔ!ÜÐ7¸±|ÐDÓEÐEÜ‹9”Z Õ)¨!Õ,Ö-¨cÓ2Ð2r   c               ó   € V ^8„  d   QhRR/# r‘   r   )r0   s   "r   r1   r1   -  s   € ÷ ñ �Dñ r   c                 óÆ   € \        \        4      ;_uu_ 4        ^ RIHp HpHp V! 4       pV! V4      ;'       d    V ! V4      R8g  uuRRR4       #   + '       g   i     R# ; i)u®   Is a speech-to-text provider configured and enabled? (A wake without STT arms the
mic but every utterance dies at transcription â€” same bar as ``check_voice_requirements``.))Ú_get_providerÚ_load_stt_configÚis_stt_enabledÚnoneNF)r   r@   Útools.transcription_toolsrö   r÷   rø   )rö   r÷   rø   Ú
stt_configs       r   Ú
_stt_readyrü   -  sK   € ô 
”)×	Õ	ß]Ñ]Ù%Ó'ˆ
Ù˜jÓ)×QÐQ©m¸JÓ.GÈ6Ñ.Q÷ 
×	×	Ñ	ñ ús   ˜,AÁA 	c               ó   € V ^8„  d   QhRR/# r‘   r   )r0   s   "r   r1   r1   7  s   € ÷ )ñ )�Dñ )r   c                 óZ  €  ^ RI Hp HpHp V ! V! 4       4      pRRRRRR/pTP                  T4      pTe+    ^ RIp^ R	IHp TP                  T4      '       g   T! 4       #   ^ R
I Hp \        T! 4       4      #   \         d     R# i ; i  \         d     R# i ; i  \         d     R# i ; i)u{  Can the configured text-to-speech provider run (or install at first use)?

The wake flow is fully hands-free (wake â†’ speak â†’ hear the reply); without
TTS the reply is silent and the loop is pointless.

PROBE, not an installer: ``check_tts_requirements`` lazily pip-installs the
provider SDK via ``_import_*`` â†’ ``pm.ensure_import`` â€” running that inside
a status poll froze wake.status for the length of a pip install (and a
failed install marked the wake word unavailable, unmounting the desktop
ear). When the provider's deps aren't installed yet, "installable at first
use" counts as ready and we never touch pip from here.
)rö   Ú_load_tts_configÚcheck_tts_requirementsFÚedgezedge-ttsÚ
elevenlabsztts-premiumÚmistralN©Úlazy_installs_allowed)r   )Útools.tts_toolrö   rÿ   r   r@   rB   ÚpmÚ
pm.installr  Ú	availablerm   )rö   rÿ   r   r"   Ú_LAZY_TTS_FEATURESÚfeaturer  r  s           r   Ú
_tts_readyr  7  sÅ   € ðßZÑZÙ Ñ!1Ó!3Ó4ˆð
 	�
Ø�mØ�9ðÐð
 !×$Ñ$ XÓ.€GØÒð	ÛÝ8à—<‘< ×(Ò(á,Ó.Ð.ð )ðÝ9äÑ*Ó,Ó-Ð-øô/ ô Úðûô" ô 	Úð	ûô ô Úðús:   ‚A7 · B	 ÁB	 Á!B Á7BÂBÂ	BÂBÂB*Â)B*c               ó$   € V ^8„  d   QhRRRRRR/# )r-   rE   r|   rX   rZ   r.   r(   r   )r0   s   "r   r1   r1   c  s)   € ÷ Iñ IÐ&>ð IØ,HðIØTbñIr   c               óø  € V e   T M	\        4       p ^ RIp^ RIHp ^ RIHp T;'       g    Tp\        WR7      pVR8X  d   RpMVR(9   d   RpMRpVP                  V4      pT;'       g	    V! V4      pV! 4       p	V'       d   \        4       MR	p
R
p\        4       p\        4       pRpV'       g_   R) Uu. uF'  pV! \        V,          ^,          4      '       g   K%  VNK)  	  ppRV R2pV'       d   VRRP                  V4       R2,          pM³VR8X  d:   \        P                  ! R4      ;'       g    RP                  4       '       g   R	pRpMsV'       g   V	'       g   \!        V4      pMWV'       d   V
'       g   \#        V 4      R8X  d   RpM4V'       d	   V'       g%   RP                  R RV3RV33 4       4      pRV R2p\#        V 4      pVR8X  d   T;'       g    T	pM?T;'       d    T
;'       g    V'       * ;'       d    T	pV'       d   V
'       g   V'       g   RpRT;'       d!    T;'       d    T;'       d    T;'       d    TRTRTR T
R!V'       d   \%        4       MR	R"VR#VR$VR%VR&\'        V 4      R'V/# u upi )*zDReport whether wake-word detection can run, with a remediation hint.Nr  r\   )rX   r   úwake-porcupineúwake-sherpaúwake-openwakewordFTrè   zThe z/ wake engine is not supported on this platform.z Set wake_word.provider to z or Ú.ÚPORCUPINE_ACCESS_KEYzDSet PORCUPINE_ACCESS_KEY (free key at https://console.picovoice.ai).rƒ   zHMicrophone capture needs sounddevice + numpy and a working audio device.z and c              3  ó>   "  € T F  w  rV'       d   K  Vx € K  	  R # 5irJ   r   )r`   ra   Úoks   &  r   rb   Ú/check_wake_word_requirements.<locals>.<genexpr>”  s   é € ð 
Ù!Y‘X�TÔac�DŠDÓ!Yùs   ‚“
zspeech-to-textztext-to-speechzWake word needs uN    configured â€” run `hermes tools` (Voice section) or see the voice-mode docs.r„   u¨   No local microphone on this backend. Remote desktop can stream the client mic â€” set wake_word.capture: client or use a desktop build with client-capture wake support.r	  r"   Údeps_availableÚaudio_availableÚlocal_input_availabler!   Úaccess_key_setÚstt_availableÚtts_availabler#   Úhint©Úsherpazsherpa-onnxÚkwsÚopen)r  r   )rF   r  r  r  rf   r]   ri   r	  r»   rü   r  r   r6   r4   Úgetenvrd   r   rˆ   r‡   r~   )rE   rX   r  r  r]   r"   r  Údeps_okÚplatform_okÚlazy_okÚaudio_okÚkey_okÚstt_okÚtts_okr  ra   ÚalternativesÚmissingÚcapture_modeÚmic_oks   &$                  r   Úcheck_wake_word_requirementsr.  c  sk  € ð ’‰#Ô&;Ó&=€CÛÝ0Ý)à×,Ð,˜_€IÜ˜Ô2€HØ�;ÔØ"‰Ø	Ð=Ô	=Ø‰à%ˆØ�l‰l˜7Ó#€GØ×/Ð/™Y wÓ/€KÙ#Ó%€G÷ &-ÔÔ!°%€HØ€Fô ‹\€FÜ‹\€FØ€DçÙ)@ó ;Ñ)@ Ù$¤Z°Õ%5°aÕ%8×9÷ ˜Ñ)@ˆð ;à�h�ZÐNÐOˆßØÐ1°&·+±+¸lÓ2KÐ1LÈAÐNÕNˆDøØ	�[Ô	 ¬"¯)ª)Ð4JÓ*K×*QÐ*QÈr×)XÑ)X×)ZÒ)ZØˆØU‰ßŸWÜ˜GÓ$‰ß	ŸÔ&:¸3Ó&?À7Ô&JØY‰ßŸ6Ø—,‘,ñ 
Ø#3°VÐ"<Ð?OÐQWÐ>XÑ!Yó
ó 
ˆð # 7 )ð ,>ð ?ˆô (¨Ó,€Lð �xÔØ×#Ð#˜G‰à×&Ð&˜h×DÐD°¬K×,CÐ,C¸GˆßŸ8¯Dð>ˆDð
 	�[×LÐL V×LÐL°×LÐL¸6×LÐLÀfÈjÐZbØ˜'Ð#4°hØÇÔ!:Ô!<ÈUØ�<Ð!1°6¸?ÈFÐTcÐekØ”+˜cÓ" F¨Dðð ùò?;s   Â1"I7ÃI7c                  óŒ   € ] tR tRt$ RtRtR]R&   RtR]R&   RtR]R&   ]	t
R]R	&   R
tR]R&   RtR]R&   RR R lltR R ltRtR# )Ú_Capturei±  zNOne armed audio source: a PortAudio stream (local) or the feed queue (client).Nr   ÚstreamÚqueuerµ   rn   Úrateé   Úframe_lengthFrm   Ú_skip_available_pollc               ó   € V ^8„  d   QhRR/# )r-   ÚstopzOptional[threading.Event]r   )r0   s   "r   r1   Ú_Capture.__annotate__¾  s   € ÷ ñ Ð2ñ r   c                ót  € V P                   eÚ   \        V P                   RR4      pVe“   Ve�   V P                  '       g}   RpV P                   P                  V P                  8  dV   VP                  \        4      '       d   R# V\        ,          pV\        8¼  g   K\  \        P                  RV4       RV n         V P                   P                  V P                  4      ^ ,          # \        \        4      ;_uu_ 4        V P                  P                  RR7      uuRRR4       #   + '       g   i     R# ; i)u   One raw block; None when nothing arrived within ~250 ms (client) or ``stop`` was
set while waiting (local). Stream errors propagate.

A PortAudio ``read(n)`` blocks until ``n`` samples exist and, on a wedged ALSA/
PipeWire device, never returns â€” so the halting thread's ``join`` timed out and
``close()`` raced the still-pending read. Poll ``read_available`` in short slices
against ``stop`` and only call ``read`` once the block is guaranteed to be there.

A device that never advances ``read_available`` (Windows DirectSound) would spin
here forever, so after ``_READ_STALL_FALLBACK_SECONDS`` of starvation the guard is
abandoned (with a warning) and the blocking read takes over; a truly wedged
blocking read is released by ``_halt_thread`` aborting the stream.
NÚread_availablert   u_   wake word: read_available stuck below frame length for %.1fs â€” falling back to blocking readsTg      Ð?©Útimeout)r1  r�   r6  r;  r5  ÚwaitÚ_READ_POLL_SECONDSÚ_READ_STALL_FALLBACK_SECONDSÚloggerÚwarningÚreadr   r@   r2  rB   )Úselfr8  r	  Ústalleds   &&  r   rC  Ú_Capture.read¾  sí   € ð �;‰;Ò"Ü §¡Ð-=¸tÓDˆIØÒ IÒ$9À$×B[×B[ÐB[Ø�Ø—k‘k×0Ñ0°4×3DÑ3DÔDØ—y‘yÔ!3×4Ò4Ù#ØÔ1Õ1�GØÔ">Ö>ÜŸ™ðGØHOôQð 59˜Ô1ØØ—;‘;×#Ñ# D×$5Ñ$5Ó6°qÕ9Ð9Ü”i× Õ Ø—:‘:—>‘>¨$�>Ó/÷ !× × Ñ áús   Ã?D&Ä&D7	c               ó   € V ^8„  d   QhRR/# ©r-   r.   ÚNoner   )r0   s   "r   r1   r9  ß  s   € ÷  ñ  �tñ  r   c                ó¢  € V P                   f   R# \        V P                   RR4      p\        \        4      ;_uu_ 4        Ve	   V! 4        MV P                   P	                  4        RRR4       \        \        4      ;_uu_ 4        V P                   P                  4        RRR4       R#   + '       g   i     LL; i  + '       g   i     R# ; i)zŒ``abort()`` first: it discards pending buffers and unblocks any in-flight read,
which ``stop()`` (drains, waits) cannot do on a dead device.NÚabort)r1  r�   r   r@   r8  Úclose)rD  rK  s   & r   rL  Ú_Capture.closeß  sˆ   € ð �;‰;ÒÙÜ˜Ÿ™ W¨dÓ3ˆÜ”i× Õ ØÒ Ù•à—‘× Ñ Ô"÷	 !ô
 ”i× Õ Ø�K‰K×ÑÔ÷ !Ñ ÷ !× ú÷
 !× Ð ús   ¿'B*ÂB=Â*B:	Â=C	)r6  rJ   )r   r   r   r   r   r1  Ú__annotations__r2  rµ   ÚSAMPLE_RATEr3  r5  r6  rC  rL  r   r   r   r   r0  r0  ±  sS   ‡ áXà€FˆCÓØ€Eˆ3ÓØ€BˆƒNØ€Dˆ#ÓØ€L�#Óð "'Ð˜$Ó&÷÷B ñ  r   r0  c                  óØ   € ] tR tRtRt]RRR3R R llt]R R l4       t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 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# )"ÚWakeWordDetectoriî  uÅ   Background hotword listener; fires ``on_wake()`` when the phrase is heard. The engine is built
once and kept across pause/resume â€” only the stream + reader thread cycle, so mic toggles are cheap.NFc               ó0   € V ^8„  d   QhRRRRRRRRR	R
RR/# )r-   Úenginer   Úon_wakeúCallable[[], None]Úcooldownrr   Ú
on_failureú,Optional[Callable[[WakeWordDetector], None]]r    rk   Úexternal_audiorm   r   )r0   s   "r   r1   ÚWakeWordDetector.__annotate__ò  s:   € ÷ :ñ :˜wð :Ð1Cð :Èuð :ØIð:à/ð:àHLñ:r   c                	óÖ  € WW43w  V n         V n        V n        V n        V\	        V4      uV n        V n        V P                  '       d	   R RRRRR/MR V/V n        RV n        RV n	        \        P                  ! 4       \        P                  ! 4       uV n        V n        \        P                  ! 4       RuV n        V n        \"        P$                  ! ^@R7      V n        R	^ uV n        V n        R# )
r½   r„   ra   zclient capturerÁ   r…   Nrt   )ÚmaxsizeF)rS  rT  rV  rW  rm   r    rY  Úinput_device_detailsÚ_threadÚ_capÚ	threadingÚEventÚ_stopÚ_callback_inflightÚLockÚ_lockÚ
_last_firer2  ÚQueueÚ_audio_qÚaudio_silentÚ_silent_frames)rD  rS  rT  rV  rW  r    rY  s   &&&&&&&r   Ú__init__ÚWakeWordDetector.__init__ò  sÖ   € ð EKÐU]ÐDiÑAˆŒ�T”\ 4¤=°$´/Ø1=¼tÀNÓ?SÐ.ˆÔ˜4Ô.ð ×"×"Ð"ð ˜ 6Ð+;¸YÈÑQØ)3°\Ð(Bð 	Ô!ð 48ˆŒð )-ˆŒ	Ü.7¯oªoÓ.?ÄÇÂÓARÐ+ˆŒ
�DÔ+Ü&/§n¢nÓ&6¸Ð#ˆŒ
�D”Oä*/¯+ª+¸bÔ*AˆŒð 27¸Ð.ˆÔ˜4Ö.r   c               ó   € V ^8„  d   QhRR/# r‘   r   )r0   s   "r   r1   rZ    s   € ÷ .ñ .˜ñ .r   c                	óR   € V P                   pVR J;'       d    VP                  4       # rJ   )r^  Úis_alive)rD  Úts   & r   ÚrunningÚWakeWordDetector.running  s#   € à�L‰LˆØ˜ˆ}×-Ð- §¡£Ð-r   c               ó   € V ^8„  d   QhRR/# rH  r   )r0   s   "r   r1   rZ    s   € ÷ 4ñ 4 ñ 4r   c           	     ó  € V P                   '       g   R#  ^ RIp\        T\        \
        \        34      '       d   TP                  YP                  R7      pM+TP                  YP                  R7      P                  R4      p\        T P                  P                  4      pT^ 8:  d   R# \        ^ \        TP                  ^ ,          4      T4       Fl  pY5YT,            pTP                  ^ ,          T8  d,   TP!                  T^ YFP                  ^ ,          ,
          34      p T P"                  P%                  T4       Kn  	  R#   \         d     R# i ; i  \         d¥    \'        \        4      ;_uu_ 4        T P"                  P)                  4        RRR4       M  + '       g   i     M; i\'        \        4      ;_uu_ 4        T P"                  P%                  T4       RRR4        EK    + '       g   i      EK/  ; ii ; i)z¬Enqueue one int16 mono frame (or raw bytes) for client capture. Short frames are
zero-padded to ``engine.frame_length``, long ones split; on overflow the oldest is dropped.NrË   rÍ   )rY  r³   r@   rC   ÚbytesÚ	bytearrayÚ
memoryviewÚ
frombufferrÒ   rÎ   rÐ   rn   rS  r5  ÚrangeÚshapeÚpadrh  Ú
put_nowaitr   Ú
get_nowait)rD  Ú	pcm_int16rµ   ÚarrÚflÚoffsetÚchunks   &&     r   ÚfeedÚWakeWordDetector.feed  so  € ð ×"×"Ð"Ùð	Ûô �i¤%¬´JÐ!?×@Ò@Ø—-‘- 	·±�-Ó:‰Cà—*‘*˜Y¯h©h�*Ó7×?Ñ?ÀÓCˆCÜ�—‘×)Ñ)Ó*ˆØ�Œ7ÙÜ˜Aœs 3§9¡9¨Q¥<Ó0°"Ö5ˆFØ ¥Ð-ˆEØ�{‰{˜1�~ Ô"ØŸ™˜u q¨"¯{©{¸1­~Õ*=Ð&>Ó?�ð4Ø—‘×(Ñ(¨Ö/ó 6øô ô 	Úð	ûô ô 4äœi×(Õ(Ø—M‘M×,Ñ,Ô.÷ )×(×(Ð(úäœi×(Õ(Ø—M‘M×,Ñ,¨UÔ3÷ )×(×(Ö(úð	4úsS   –E Ä#EÅEÅEÅ"HÅ8F	Æ	HÆF,Æ'HÇG.	Ç"HÇ.HÇ9HÈHc               ó   € V ^8„  d   QhRR/# rH  r   )r0   s   "r   r1   rZ  (  s   € ÷ bñ b�tñ br   c           	     óL  € V P                   ;_uu_ 4        V P                  '       d    RRR4       R# V P                  P                  4        \        P
                  ! 4       p. p\        P                  ! V P                  W3RRR7      V n        V P                  P                  4        RRR4       XP                  \        4      '       g   V P                  4        \        R4      hX'       d$   V P                  4        \        R4      V^ ,          hR#   + '       g   i     Ls; i)z@Open the mic (or client feeder) and begin listening. Idempotent.NTz	wake-word)ÚtargetÚargsÚdaemonra   z1Timed out while opening the wake-word microphone.z(Failed to open the wake-word microphone.)re  rq  rb  Úclearr`  ra  ÚThreadÚ_runr^  Ústartr>  Ú_START_TIMEOUT_SECONDSÚ_halt_threadÚTimeoutErrorÚRuntimeError)rD  ÚreadyÚstartup_errorss   &  r   r�  ÚWakeWordDetector.start(  sÔ   € à�Z�Z‹ZØ�|�|ˆ|Ø÷ ‰Zð �J‰J×ÑÔÜ—O’OÓ%ˆEØ24ˆNÜ$×+Ò+°4·9±9ÀEÐCZØ37¸kôKˆDŒLà�L‰L×ÑÔ ÷ ð �z‰zÔ0×1Ò1Ø×ÑÔÜÐRÓSÐSßØ×ÑÔÜÐIÓJÐP^Ð_`ÕPaÐañ ÷ �Zús   •D³A5DÄD#	c               ó   € V ^8„  d   QhRR/# rH  r   )r0   s   "r   r1   rZ  ;  s   € ÷ ñ �tñ r   c                	ó&   € V P                  4        R # rJ   )r�  ©rD  s   &r   ÚpauseÚWakeWordDetector.pause;  s   € Ø×ÑÖr   c               ó   € V ^8„  d   QhRR/# rH  r   )r0   s   "r   r1   rZ  >  s   € ÷ ñ ˜ñ r   c                	ó&   € V P                  4        R # rJ   )r�  r—  s   &r   ÚresumeÚWakeWordDetector.resume>  s   € Ø�
‰
Žr   c               ó   € V ^8„  d   QhRR/# rH  r   )r0   s   "r   r1   rZ  A  s   € ÷ ñ �dñ r   c                	óZ   € V P                  4        V P                  P                  4        R # rJ   )r�  rS  rL  r—  s   &r   r8  ÚWakeWordDetector.stopA  s   € Ø×ÑÔØ�‰×ÑÖr   c               ó   € V ^8„  d   QhRR/# rH  r   )r0   s   "r   r1   rZ  E  s   € ÷ $ñ $˜dñ $r   c                	óH  € V P                   ;_uu_ 4        V P                  P                  4        V P                  pR R R 4       Xef   V\        P
                  ! 4       JdM   VP                  \        R7       VP                  4       '       d!   V P                  pVe   VP                  4        V P                   ;_uu_ 4        V P                  VJ d"   Ve   VP                  4       '       g   R V n        R R R 4       R #   + '       g   i     LÉ; i  + '       g   i     R # ; i)Nr<  )re  rb  Úsetr^  r`  Úcurrent_threadr6   Ú_HALT_JOIN_SECONDSro  r_  rL  )rD  rp  Úcaps   &  r   r�  ÚWakeWordDetector._halt_threadE  s¶   € Ø�Z�Z‹ZØ�J‰J�N‰NÔØ—‘ˆA÷ ð
 Š=˜Q¤i×&>Ò&>Ó&@Ó@Ø�F‰FÔ-ˆFÔ.Ø�z‰z�|Š|ð
 —i‘i�Ø’?Ø—I‘I”KØ�Z�Z‹Zð �|‰|˜qÓ  a¢i°q·z±z·|²|Ø#�”÷	 ‰Z÷ �Zú÷ �ZˆZús   •'C=Ã*DÃ,DÃ=D	ÄD!	c               ó   € V ^8„  d   QhRR/# rH  r   )r0   s   "r   r1   rZ  [  s   € ÷ ,ñ , ñ ,r   c                	óö   €  V P                  4        V P                  P                  4        R#   \         d!   p\        P                  R T4        Rp?LBRp?ii ; i  T P                  P                  4        i ; i)zwake word callback failed: %sN)rT  r@   rA  rB  rc  rŠ  )rD  rÅ   s   & r   Ú_dispatch_wakeÚWakeWordDetector._dispatch_wake[  s]   € ð	,Ø�L‰LŒNð ×#Ñ#×)Ñ)Ö+øô ô 	?Ü�N‰NÐ:¸A×>Ñ>ûð	?ûð ×#Ñ#×)Ñ)Õ+ús&   ‚. ®A¹AÁA ÁAÁA ÁA8c               ó    € V ^8„  d   QhRRRR/# )r-   r5  rn   r.   r0  r   )r0   s   "r   r1   rZ  c  s   € ÷ "ñ "¨#ð "°(ñ "r   c           	     óŽ  € V P                   '       d6   \        \        4      ;_uu_ 4         V P                  P	                  4        K   \        4       w  r#\        T P                  T4      ;qPn        \        TR7      TP!                  R4      rv\#        T\$        \&        34      '       dS   \#        T\(        4      '       g=   T^ 8”  d6   \        \*        \,        4      ;_uu_ 4        \/        T4      Tn        RRR4       \3        ^\/        YP0                  ,          \        ,          4      4      Tn        \
        P                  RTP!                  R4      ;'       g    R	T P                  TP!                  R
4      ;'       g    RTP!                  R4      ;'       g    RTP0                  \        4        TP7                  T P                  TP0                  ^RTP4                  R7      Tn        TP8                  P;                  4        T#   + '       g   i     M; i\
        P                  RT\        4       \        T P                  TR7      #   \        \        3 d   p\
        P                  RT4       h Rp?ii ; i  + '       g   i     EL�; i  \         d-   pTP=                  4        \
        P                  RT4       h Rp?ii ; i)z7Open the audio source; raises on any local-mic failure.NuL   wake word: client-capture mode (frame=%d, rate=%d) â€” waiting for wake.feed)r2  r5  z*wake word: audio libraries unavailable: %s)rµ   rÀ   zmwake word: opening microphone device=%s selector=%r hostapi=%s default_rate=%s capture_rate=%d engine_rate=%dra   ré   rÁ   ÚunknownrÒ   )ÚdeviceÚ
samplerateÚchannelsrÌ   Ú	blocksizez(wake word: failed to open microphone: %s)rY  r   r@   rh  r}  rA  rŠ   rO  r0  r™   r¹   rº   r¿   rÇ   r    r]  rB   rC   rn   rr   rm   ÚOverflowErrorrP   Úroundr3  rR   r5  ÚInputStreamr1  r�  rL  )rD  r5  rœ   rµ   rÅ   rÄ   r¦  r3  s   &&      r   Ú_open_captureÚWakeWordDetector._open_capturec  s  € à××ÐÜœ)×$Õ$ØØ—M‘M×,Ñ,Ö.ð
	Ü"“_‰FˆBô /EÀT×EVÑEVÐXZÓ.[Ð[ˆÔ+ä ”O W§[¡[Ð1EÓ%FˆTÜ�dœS¤%˜L×)Ò)´*¸TÄ4×2HÒ2HÈTÐTUÌXÜœ-¬×4Õ4Ü  ›;�”÷ 5ä˜q¤%¨·x±xÕ(?Ä+Õ(MÓ"NÓOˆÔÜ�‰ð EØFMÇkÁkÐRXÓFY×FmÐFmÐ]mØ×%Ñ% w§{¡{°9Ó'=×'JÐ'JÀØ—K‘KÐ 4Ó5×BÐB¸ÀCÇHÁHÌkô	[ð	ØŸ™¨t×/@Ñ/@ÈSÏXÉXÐ`aØ.5À×AQÑAQð (ó SˆCŒJà�J‰J×ÑÔð
 ˆ
÷? %×$úô �K‰KÐfØ$¤kô3ä $§-¡-¸lÔKÐKøô œWÐ%ô 	Ü�L‰LÐEÀqÔIØûð	ú÷ 5×4Ð4ûô ô 	Ø�I‰IŒKÜ�L‰LÐCÀQÔGØûð	úsH   ªHÁ	I	 Ã"I9Æ/AJ ÈH	É	I6ÉI1É1I6É9J
	ÊKÊ'J?Ê?Kc               ó    € V ^8„  d   QhRRRR/# )r-   Úsilent_alert_framesrn   r.   rI  r   )r0   s   "r   r1   rZ  ‡  s   € ÷ >ñ >¸ð >Àñ >r   c                ó<  €  Ve   \        V4      '       g   ^ M!\        \        V4      P                  4       4      pV\
        8:  do   V ;P                  ^,          un        V P                  V8X  dC   RV n        Ve6   \        P                  R\
        \        \        V P                  4      4       R# R# R# V P                  '       d9   V P                  '       d   \        P                  R4       ^ RuV n        V n        R# R#   \         d    \
        ^,           p Lßi ; i)z³Track consecutive near-zero frames; flag/unflag ``audio_silent``. ``frame`` is None when
no client frame arrived (counts as silence for status, but is never logged as a dead mic).NTz;wake word: mic delivers only silence (peak<=%d for %ds); %su0   wake word: mic audio detected â€” stream healthyF)Úlenrn   ÚabsrR   r@   Ú_SILENCE_PEAKrj  ri  rA  rB  Ú_SILENCE_ALERT_SECONDSrï   r]  rŠ   )rD  rÞ   r¹  Úpeaks   &&& r   Ú_note_silenceÚWakeWordDetector._note_silence‡  sé   € ð	%Øš¬S°¯ZªZ‘1¼SÄÀUÃÇÁÓAQÓ=RˆDð ”=Ô Ø×Ò 1Õ$ÕØ×"Ñ"Ð&9Ô9Ø$(�Ô!ØÒ$Ü—N‘NÐ#`Ü#0Ô2HÜ#4°T×5NÑ5NÓ#OöQñ %ñ :ð × × Ð Ø× × Ð Ü—‘ÐNÔOØ56¸Ð2ˆDÔ Ö!2ñ !øô ô 	%Ü  1Õ$ŠDð	%ús   ‚9D  Ä DÄDc               ó   € V ^8„  d   QhRR/# rH  r   )r0   s   "r   r1   rZ  ›  s   € ÷ 
iñ 
i�tñ 
ir   c                ó°  € \         P                  ! 4       pWP                  ,
          V P                  8  d   \        P                  R4       R# Wn        \        P                  R4       V P                  P                  4       '       gN   V P                  P                  4        \        P                  ! V P                  RRR7      P                  4        R# R# )zBHonor the cooldown, then run ``on_wake`` on its own thread (once).u0   wake word: detection within cooldown â€” ignoredNu.   wake word: phrase detected â€” firing callbackTzwake-word-callback)r‡  r‰  ra   )ÚtimeÚ	monotonicrf  rV  rA  ÚdebugrŠ   rc  Úis_setr£  r`  r‹  rª  r�  )rD  Únows   & r   Ú_fireÚWakeWordDetector._fire›  s‘   € ä�nŠnÓˆØ—‘Õ  4§=¡=Ô0Ü�L‰LÐKÔLÙØŒÜ�‰ÐDÔEØ×&Ñ&×-Ñ-×/Ò/Ø×#Ñ#×'Ñ'Ô)Ü×Ò D×$7Ñ$7ÀÐK_Ô`×fÑfÖhñ 0r   c               ó    € V ^8„  d   QhRRRR/# )r-   r5  rn   r.   zOptional[_Capture]r   )r0   s   "r   r1   rZ  §  s   € ÷ ñ ¨Sð Ð>Pñ r   c                ó  € V P                   '       d   R# V Fš  p\        P                  RV4       V P                  P	                  V4      '       d    R#  V P                  V4      p\        \        4      ;_uu_ 4        T P                  P                  4        RRR4       R^ uT n
        T n        Tu # 	  \        P                  R4       R#   \         d"   p\        P                  RT4        Rp?KÜ  Rp?ii ; i  + '       g   i     Lk; i)zJRetry only an already-started local capture, keeping its owner and engine.Nz(wake word: reopening microphone in %.1fsz'wake word: microphone reopen failed: %sFzCwake word: microphone recovery exhausted; toggle wake word to retry)rY  rA  rB  rb  r>  r¶  r@   r   rS  Úresetri  rj  )rD  r5  ÚretriesÚdelayr¦  rÅ   s   &&&   r   Ú_recover_captureÚ!WakeWordDetector._recover_capture§  sÍ   € à××ÐÙÛˆEÜ�N‰NÐEÀuÔMØ�z‰z�‰˜u×%Ò%ÚðØ×(Ñ(¨Ó6�ô œ)×$Õ$Ø—‘×!Ñ!Ô#÷ %à5:¸AÐ2ˆDÔ˜tÔ2ØŠJñ ô 	�‰Ð\Ô]Ùøô ô Ü—‘ÐHÈ!ÔLÝûðú÷ %×$ús$   ÁCÁ=C;ÃC8ÃC3Ã3C8Ã;Dc               ó$   € V ^8„  d   QhRRRRRR/# )r-   r’  zthreading.Eventr“  zlist[BaseException]r.   rI  r   )r0   s   "r   r1   rZ  »  s#   € ÷ 7&ñ 7&˜/ð 7&Ð;Nð 7&ÐSWñ 7&r   c           
     	ó&  € V P                   P                  p V P                  V4      pW@n        \        \        4      ;_uu_ 4        T P                   P                  4        R R R 4       \        P                  RT\        T P                  4       TP                  4        Rp\        R4      p\        ^\        \         \        ,          \        ^T4      ,          4      4      p T P"                  P%                  4       '       gÄ    TP'                  T P"                  4      p	T	f   T P/                  R T4       KT  \1        T	R^4      ^8X  d
   T	R,          MT	p
TP2                  \        8w  d   \5        TP6                  Y£4      p
T P/                  Y¨4        T P                   P9                  T
4      '       d   T P;                  4        Ká  Kã  Te   TP+                  4        \        P                  R4       T'       d$   T P>                  e   T P?                  T 4       R # R # R #   \         d-   pTP                  T4       TP                  4         R p?R # R p?ii ; i  + '       g   i     ELý; i  \         d–   p\        P)                  RT4       TP+                  4        R pT P"                  P%                  4       '       g   T P-                  Y74      pTe   Y@n         R p?EKü  T P"                  P%                  4       '       * p R p?EK?  R p?ii ; i  \         d#   p\        P=                  RT4        R p?EKR  R p?ii ; i  Te   TP+                  4        \        P                  R4       T'       d"   T P>                  e   T P?                  T 4       i i i ; i)	Nz5wake word: listening (frame=%d, rate=%d, external=%s)Fz wake word: stream read error: %sÚndimzwake word: engine error: %szwake word: stream closed)g      à?ru   r   ):NNNr•   ) rS  r5  r¶  r_  r@   Úappendr£  r   rÍ  rA  rŠ   rO  rY  ÚiterrR   rn   r¾  rb  rÇ  rC  rB  rL  rÐ  rÀ  r�   r3  rã   rµ   ÚprocessrÉ  rÆ  rW  )rD  r’  r“  r5  r¦  rÅ   ÚfailedrÎ  r¹  ÚdatarÞ   s   &&&        r   rŒ  ÚWakeWordDetector._run»  s²  € Ø—{‘{×/Ñ/ˆð	Ø×$Ñ$ \Ó2ˆCØŒIô ”i× Õ Ø�K‰K×ÑÔ÷ !ä�‰ÐKØ ¤+¨t×/BÑ/Bô	Dà�	‰	ŒØˆô �Ó'ˆÜ! !¤SÔ)?Ä+Õ)MÔPSÐTUÐWcÓPdÕ)dÓ%eÓfÐð"	&Ø—j‘j×'Ñ'×)Ò)ðØŸ8™8 D§J¡JÓ/�Dð ’<Ø×&Ñ& tÐ-@ÔAÙÜ&-¨d°F¸AÓ&>À!Ô&C˜˜Tž
È�Ø—8‘8œ{Ô*Ü1°#·&±&¸%ÓN�EØ×"Ñ" 5Ô>ðCØ—{‘{×*Ñ*¨5×1Ò1ØŸ
™
žñ 2ð
 ŠØ—	‘	”Ü�K‰KÐ2Ô3ß˜$Ÿ/™/Ò5Ø—‘ Ö%ñ 6‰vøôc ô 	Ø×!Ñ! !Ô$Ø�I‰IŒKÝûð	ú÷ !× Ð ûô !ô Ü—N‘NÐ#EÀqÔIØ—I‘I”KØ�CØŸ:™:×,Ñ,×.Ò.Ø"×3Ñ3°LÓJ˜Ø’ð %(œ	Þ Ø!%§¡×!2Ñ!2Ó!4Ô4�FÞûðûô. !ô CÜ—L‘LÐ!>À×BÓBûðCûð ŠØ—	‘	”Ü�K‰KÐ2Ô3ß˜$Ÿ/™/Ò5Ø—‘ Õ%ð 6ˆvús—   ˜H ÁIÃ"L< ÄI) ÄA1L< Æ1L ÇL< ÈIÈ&!IÉIÉI&	É)L	É4A#LËL< ËLË=L< ÌL	Ì	L< ÌL9ÌL4Ì-L< Ì4L9Ì9L< Ì<1NÍ."N)rh  rc  r_  rf  re  rj  rb  r^  ri  rV  rS  rY  r    r]  rW  rT  )r   r   r   r   r   Ú_FIRE_COOLDOWN_SECONDSrk  Úpropertyrq  rƒ  r�  r˜  rœ  r8  r�  rª  r¶  rÀ  rÉ  rÐ  rŒ  r   r   r   r   rQ  rQ  î  st   † ñnð XnØLPØ26Èu÷:ð( ô.ó ð.õ4õ:bõ&õõõ$õ,,õ"õH>õ(
iõ÷(7&ñ 7&r   rQ  úOptional[WakeWordDetector]Ú	_detectorzobject | NoneÚ_detector_ownerc               ó   € V ^8„  d   QhRR/# )r-   r.   r   r   )r0   s   "r   r1   r1   ý  s   € ÷ Dñ D�Dñ Dr   c                 ó8   € ^ RI Hp  V ! 4       R,          R,          # )r•   ©Úget_default_hermes_rootÚruntimezwake-word.lock)Úhermes_constantsrã  râ  s    r   Ú
_lock_pathræ  ý  s   € Ý8Ù"Ó$ yÕ0Ð3CÕCÐCr   c               ó    € V ^8„  d   QhRRRR/# )r-   Úacquirerm   r.   rI  r   )r0   s   "r   r1   r1     s   € ÷ dñ d˜Dð d Tñ dr   c                ó>  € \         P                  R8X  dµ   ^ RIpV'       dW   V P                  ^ \         P                  4       V P                  4       ^ 8X  d"   V P                  R4       V P                  4        V P                  ^ 4       TP                  V P                  4       V'       d   VP                  MVP                  ^4       R# ^ RIpTP                  V P                  4       V'       d   VP                  VP                  ,          MVP                   4       R# )zINon-blocking exclusive lock (or unlock) of one byte / whole file, per OS.ÚntNó    )r4   ra   ÚmsvcrtÚseekÚSEEK_ENDÚtellÚwriteÚflushÚlockingÚfilenoÚLK_NBLCKÚLK_UNLCKÚfcntlÚflockÚLOCK_EXÚLOCK_NBÚLOCK_UN)Úhandlerè  rì  rö  s   &&  r   Ú_flockrü    s¥   € ä	‡w�w�$„ÛßØ�K‰K˜œ2Ÿ;™;Ô'Ø�{‰{‹} Ô!Ø—‘˜UÔ#Ø—‘”Ø�‰�AŒØ�‰�v—}‘}“¿7¨¯ªÈÏÉÐYZÖ[ãØ�‰�F—M‘M“OÏ e§m¡m°e·m±mÖ&CÐUZ×UbÑUbÖcr   c               ó   € V ^8„  d   QhRR/# )r-   r5   zOptional[Path]r   )r0   s   "r   r1   r1     s   € ÷ 
ñ 
 ñ 
r   c                óø   € T ;'       g    \        4       pVP                  P                  RRR7       \        VR4      p \	        VR4       V#   \
         d"   pTP                  4        \        R4      ThRp?ii ; i)zCAcquire the cross-process microphone lease, or raise WakeWordInUse.T)ÚparentsÚexist_okza+bú&Wake-word microphone is already owned.N)ræ  ÚparentÚmkdirr!  rü  rº   rL  r   )r5   Ú	lock_pathrû  rÅ   s   &   r   Ú_acquire_machine_lockr    sx   € à×$Ð$œ
›€IØ×Ñ×Ñ 4°$ÐÔ7Ü�)˜UÓ#€FðMÜˆv�tÔð €Møô ô MØ�‰ŒÜÐDÓEÈ1ÐLûðMús   ¿A ÁA9ÁA4Á4A9c               ó   € V ^8„  d   QhRR/# rH  r   )r0   s   "r   r1   r1     s   € ÷ ñ  Tñ r   c                ó˜   € V f   R #  \        V R4       V P                  4        R #   \         d     Li ; i  T P                  4        i ; ir¸   )rü  rº   rL  )rû  s   &r   Ú_release_machine_lockr    sD   € Ø‚~ÙðÜˆv�uÔð 	�‰Žøô ô Ùðûð 	�‰�ús   ˆ& ¦4±7 ³4´7 ·A	c               ó    € V ^8„  d   QhRRRR/# )r-   rL  rU  r.   rI  r   )r0   s   "r   r1   r1   *  s   € ÷ +ñ +Ð.ð +°4ñ +r   c                ód   € \         pR;s;ss  V ! 4        \        V4       R#   \        T4       i ; i)zcForget the singleton and run ``close``, always releasing the machine lease (caller holds the lock).N)Ú_detector_file_lockrÞ  rß  r  )rL  Úlock_handles   & r   Ú_teardown_lockedr  *  s5   € ô &€KØ8<Ð<€IÐ<�Ð"5ð+ÙŒä˜kÖ*øÔ˜kÕ*ús   Ž" ¢/c               ó    € V ^8„  d   QhRRRR/# )r-   ÚownerÚobjectr.   rÝ  r   )r0   s   "r   r1   r1   5  s   € ÷ Uñ U˜6ð UÐ&@ñ Ur   c                ó6   € \         e   \        V J d   \         # R# )zIThe armed detector iff ``owner`` holds the lease (caller holds the lock).N)rÞ  rß  ©r  s   &r   Ú_owned_detectorr  5  s   € ä!Ò-´/ÀUÓ2JŒ9ÐTÐPTÐTr   c               ó    € V ^8„  d   QhRRRR/# )r-   ÚdetectorrQ  r.   rI  r   )r0   s   "r   r1   r1   :  s   € ÷ 4ñ 4Ð/ð 4°Dñ 4r   c                ó®   € \         ;_uu_ 4        \        V J d    \        V P                  P                  4       RRR4       R#   + '       g   i     R# ; i)zDRelease ownership if the active microphone stream dies unexpectedly.N)Ú_detector_lockrÞ  r  rS  rL  )r  s   &r   Ú_detector_failedr  :  s-   € ç	ŽÜ˜Ó Ü˜XŸ_™_×2Ñ2Ô3÷ 
��Šús   �*AÁA	ÚconfigrY  c          
     ó,   € V ^8„  d   QhRRRRRRRRR	R
/# )r-   rT  rU  r  r  r  r|   rY  rm   r.   rQ  r   )r0   s   "r   r1   r1   A  s3   € ÷ ñ Ð/ð ¸6ð ÐKcð Ø$(ðØ5Eñr   c          
     ó¾  € Vf   \        R4      h\        ;_uu_ 4        \        eE   \        VJd   \	        R4      hV \        n        \        P                  4        \        uuRRR4       # \        4       s Ve   TM	\        4       p/ VCRV'       d   RMR/Cp\        \        V4      V \        \        V4      VR7      sVs\        P                  4        \        uuRRR4       #   \         dZ    \!        \        4      ;_uu_ 4        \#        \        e   \        P$                  MR 4       RRR4       h   + '       g   i     h ; ii ; i  + '       g   i     R# ; i)	u  Claim, build, and start the detector. Idempotent for the same owner; a different owner
(or process) gets :class:`WakeWordInUse`. Raises if engine construction fails (missing deps /
access key / model) â€” callers should probe :func:`check_wake_word_requirements` first.Nz wake-word owner must not be Noner  r!   r„   rƒ   )rW  r    rY  c                 ó   € R # rJ   r   r   r   r   Ú<lambda>Ú!start_listening.<locals>.<lambda>\  s   € ÑVZr   )rP   r  rÞ  rß  r   rT  rœ  r  r  rF   rQ  ró   r  rp   r�  r@   r   r  r8  )rT  r  r  rY  rE   Ú
engine_cfgs   &$$$  r   Ústart_listeningr   A  s  € ð
 ‚}ÜÐ;Ó<Ð<÷ 
ŽÜÒ Ü eÓ+Ü#Ð$LÓMÐMØ 'ŒIÔÜ×ÑÔÜ÷ 
Šô 4Ó5Ðð	Ø"Ò.‘&Ô4IÓ4KˆCØT˜CÐT ¿©HÈGÑTˆJÜ(¬°zÓ)BÀGÔXhÜ6CÀCÓ6HÐYgôiˆIà#ˆOÜ�O‰OÔÜ÷ 
Šøô  ô 	Üœ)×$Õ$Ü ´9Ò3H¤§¢ÉlÔ[÷ %à÷ %Ö$àúð	ú÷! 
�ˆúsC   žAEÁ+
EÁ6C$ÂAC$Ã$"EÄ%D4Ä+	EÄ4EÄ?	EÅEÅE	c               ó$   € V ^8„  d   QhRRRRRR/# )r-   r  r  ÚactionrX  r.   rm   r   )r0   s   "r   r1   r1   `  s#   € ÷ ñ �vð Ð'Sð Ð_cñ r   c                óª   € \         ;_uu_ 4        \        V 4      pVf    RRR4       R# Ve	   V! V4        RRR4       R#   + '       g   i     R# ; i)z^Under the lock, True iff ``owner`` holds the lease; also runs ``action(detector)`` when given.NFT)r  r  )r  r"  Údets   && r   Ú_owned_callr%  `  s>   € ç	ŽÜ˜eÓ$ˆØŠ;Ø÷ 
‰ð ÒÙ�3ŒKØ÷ 
��Šús   �AªAÁA	c               ó    € V ^8„  d   QhRRRR/# ©r-   r  r  r.   rm   r   )r0   s   "r   r1   r1   k  s   € ÷ ñ ˜ð  Dñ r   c                ó   € \        V 4      # rJ   ©r%  r  s   &r   Úowns_listenerr*  k  s   € Ü�uÓÐr   c               ó    € V ^8„  d   QhRRRR/# r'  r   )r0   s   "r   r1   r1   o  s   € ÷ 6ñ 6˜fð 6¨ñ 6r   c                ó6   € \        V \        P                  4      # )z;Release the microphone only when ``owner`` holds the lease.)r%  rQ  r˜  r  s   $r   Úpause_listeningr-  o  s   € ä�uÔ.×4Ñ4Ó5Ð5r   c               ó    € V ^8„  d   QhRRRR/# r'  r   )r0   s   "r   r1   r1   t  s   € ÷ 7ñ 7˜vð 7¨$ñ 7r   c                ó6   € \        V \        P                  4      # )z;Re-open the microphone only when ``owner`` holds the lease.)r%  rQ  rœ  r  s   $r   Úresume_listeningr0  t  s   € ä�uÔ.×5Ñ5Ó6Ð6r   c               ó    € V ^8„  d   QhRRRR/# r'  r   )r0   s   "r   r1   r1   y  s   € ÷ Fñ F˜Vð F¨ñ Fr   c                ó   € \        V R 4      # )z<Fully stop the detector only when ``owner`` holds the lease.c                ó,   € \        V P                  4      # rJ   )r  r8  ©r$  s   &r   r  Ú stop_listening.<locals>.<lambda>{  s   € Ô*:¸3¿8¹8Ô*Dr   r)  r  s   $r   Ústop_listeningr6  y  s   € ä�uÑDÓEÐEr   c               ó   € V ^8„  d   QhRR/# )r-   r.   rÝ  r   )r0   s   "r   r1   r1   ~  s   € ÷ ñ Ð5ñ r   c                 óh   € \         ;_uu_ 4        \        uuR R R 4       #   + '       g   i     R # ; irJ   )r  rÞ  r   r   r   Ú_current_detectorr9  ~  s   € ß	ŽÜ÷ 
��‹ús   �  1	c               ó   € V ^8„  d   QhRR/# r‘   r   )r0   s   "r   r1   r1   ƒ  s   € ÷ Dñ D�dñ Dr   c                 óF   € \        4       ;p R J;'       d    V P                  # rJ   )r9  rq  r4  s    r   Úis_listeningr<  ƒ  s!   € Ü$Ó&Ð&ˆC¨tÐ3×CÐC¸¿¹ÐCr   c               ó   € V ^8„  d   QhRR/# r‘   r   )r0   s   "r   r1   r1   ‡  s   € ÷ Iñ I˜ñ Ir   c                 óF   € \        4       ;p RJ;'       d    V P                  # )z¤True when the armed stream opens fine but delivers only silence (dead mic), so
detection can never fire; status shows "listening but the microphone appears silent".N)r9  ri  r4  s    r   Úaudio_is_silentr?  ‡  s%   € ô %Ó&Ð&ˆC¨tÐ3×HÐH¸×8HÑ8HÐHr   c               ó    € V ^8„  d   QhRRRR/# )r-   rE   r|   r.   r(   r   )r0   s   "r   r1   r1   �  s   € ÷ fñ fÐ!9ð fÀ^ñ fr   c                óœ   € \        4       ;pe   \        VP                  4      # \        \	        V e   V 4      4      # \        4       4      4      # )zDReturn configured/active PortAudio input diagnostics for status UIs.)r9  rD   r]  rÇ   rp   rF   )rE   r$  s   & r   Úget_input_device_statusrB  �  sD   € ä Ó"Ð"ˆÒ/Ü�C×,Ñ,Ó-Ð-Ü!¤-°s²°Ó"dÓeÐeÔLaÓLcÓ"dÓeÐer   c               ó   € V ^8„  d   QhRR/# )r-   r.   zOptional[tuple[str, str]]r   )r0   s   "r   r1   r1   ”  s   € ÷ eñ eÐ1ñ er   c                 óP   € \        4       ;p f   R# \        V P                  RR4      # )z‘(matched phrase, profile) of the most recent wake fire when the engine reports
per-phrase matches (sherpa multi-profile routing); None otherwise.NÚ
last_match)r9  r�   rS  r4  s    r   Úget_last_matchrF  ”  s+   € ô -Ó.Ð.�CÒ7ˆ4Ðd¼WÀSÇZÁZÐQ]Ð_cÓ=dÐdr   c               ó    € V ^8„  d   QhRRRR/# r'  r   )r0   s   "r   r1   r1   š  s   € ÷ ñ ˜ð ¨tñ r   c                óÖ   € \         ;_uu_ 4        \        V 4      pVe   VP                  '       g    RRR4       R#  RRR4       XP                  V4       R#   + '       g   i     L#; i)zMPush client-captured PCM into ``owner``'s armed detector; True when accepted.NFT)r  r  rY  rƒ  )r  r~  r$  s   $$ r   Ú
feed_audiorI  š  sL   € ç	ŽÜ˜eÓ$ˆØŠ;˜c×0×0Ð0Ø÷ 
‰à0÷ 
ð ‡H�HˆYÔÙ÷ 
�ús   �!A±AÁA(	c               ó   € V ^8„  d   QhRR/# r<   r   )r0   s   "r   r1   r1   ¤  s   € ÷ Tñ T˜^ñ Tr   c                 óÀ   € \        4       ;p f   R\        RR/# R\        R\        V P                  4      R\	        \        V P                  RR4      ;'       g    R4      /# )z8Sample rate + frame length for client capture streamers.Úsample_rater5  r4  rY  )r9  rO  rm   rY  rn   r�   rS  r4  s    r   Údetector_frame_inforM  ¤  s_   € ä Ó"Ð"ˆÒ+Øœ{¨N¸DÐAÐAØœ;Ð(8¼$¸s×?QÑ?QÓ:RØœC¤¨¯
©
°NÀDÓ I× QÐ QÈTÓRðTð Tr   )r   r  r  )r   r  )ÚopenwakewordÚowwrƒ   )r   r  )rN  r  r   >   rè   Úhermesr*   r$   rJ   )dÚ__conditional_annotations__r   Ú
__future__r   r  r   Úloggingr4   r2  rë   r`  rÄ  Ú
contextlibr   Údataclassesr   Úpathlibr   Útypingr   r   r	   r
   Útools.wake_word_enginesr   r   r   r   Ú	getLoggerr   rA  rO  rÛ  rŽ  r?  r@  r¥  Ú_DEFAULT_CONFIRMATION_FRAMESr½  r¾  r   rN  rh   r‘  r   r)   r9   Ú	frozensetÚ_BUNDLED_MODEL_ALIASESr:   rF   rL   rW   ri   rp   rw   rz   r~   rˆ   r�   r‡   r¢   r©   r±   r™   r»   rÇ   rã   rï   ró   rü   r  r.  r0  rQ  rÞ  rß  r  rd  r  ræ  rü  r  r  r  r  r  r   r%  r*  r-  r0  r6  r9  r<  r?  rB  rF  rI  rM  )ÚkrQ  s   0@r   Ú<module>r^     sÍ  øðôõ #å Û Û 	Û Û 
Û Û Ý Ý !Ý ß 0Ó 0÷ó ð 
×	Ò	˜8Ó	$€à€ð Ð ØÐ ØÐ ð  #Ð ØÐ ð  !Ð ð
 €ØÐ ð
 Ð7ð*á7_Ó`Ñ7_°!Ð
-Ò-Ñ7_Ñ`ð*ñ AaÓaÑ@`¸1Ð
6Ò6Ñ@`Ñað*€
Ð&ó ð
 ?Ð ôN�Lô Nð ˆu�i ¨¸¸yÈ&Ø�˜ ,°¸sØÐ7Ð9LÈdð€	ˆ>ó ð #Ð Ù"Ò#MÓNÐ õaõ
0õ6õ
ðhÐPT÷ hõyõ9õ<÷
4ñiÐX]ð iØ-2÷ið iõõ
÷Rõõò*õ÷õ4@õ&_õ3õõ)ñXIØKO÷Ið Ið\ ÷9 ð 9 ó ð9 ÷xD&ñ D&ðR )-€	Ð%Ó ,Ø!%€�Ó %ØÐ Ø—’Ó!€õDõ
d÷ 
õõ+õUõ
4ðÐfjð Ø+0÷÷>õõ6õ
7õ
Fõ
õ
DõI÷fõeõ÷TùòK aùÚas   Â H=ÂI