
    Pj&                    :   d Z ddlmZ ddlZddlZddlmZ ddlZdZ	 ee
      j                         j                  j                  Zedz  dz  Zi dd	d
dddddddddddddddddddddd dd!dd"dd#d$d%dd&d'd'd(d)d'd(d*ddd	d+Z ej                   d,d-j#                  e      z   d.z   ej$                        Z ej                   d/ej$                        Z eej,                  j/                  d0d1            Zd8d2Zd9d3Zd:d4Z G d5 d6      Zd7 Zy);u  Expressive TTS — Chatterbox (Resemble AI, MIT) with an emotion dial.

Kokoro is fast but flat: one tone forever. Chatterbox adds what Ahmed asked
for — a voice with moods. Two controls matter:
  exaggeration  0.0 flat … 0.5 natural … 1.0+ dramatic (per-utterance!)
  voice ref     any 10-20s clip at voices/jarvis_ref.wav becomes HIS voice
                (zero-shot cloning, no training)

Per-sentence emotion: the brain prefixes a sentence with a tag —
  [calm] [warm] [excited] [urgent] [sad] [sarcastic]
— which maps to an exaggeration level here (tags are stripped before
synthesis, and Kokoro simply ignores them). No tag = natural.

VRAM-aware: Chatterbox wants ~2.5-3.5GB. loadable() checks free VRAM first,
so while a game owns the card the engine stays on Kokoro and Jarvis never
fights the game for memory. GPU free at next launch → expressive mode.

Env: VOICE_ENGINE=auto|chatterbox|kokoro (default auto),
     VOICE_REF (default voices/jarvis_ref.wav), CB_EXAGGERATION (0.5).
    )annotationsN)Pathi]  voiceszjarvis_ref.wavcalmg333333?flatg?warmg?happyg?excitedg333333?urgentg?alarmedgffffff?sadg?	sarcasticg333333?dryg?seriousgffffff?neutralg      ?shocked	surprisedcurious
interestedg(\?	intriguedgffffff?g
ףp=
?g      ?g(\?gzG?)amusedplayfulcheekyannoyed	irritated	impatienttestytendergentlesofttiredz^\s*\[(|z)\]\s*z^\s*\[[a-z][a-z ,'-]{0,24}\]\s*CB_MIN_VRAMz3.0c                    t         j                  j                  dd      j                         } | dv r| S 	 ddl}|j
                  j                         r-|j
                  j                         \  }}|dz  t        k\  rdS dS t        |j                  dd      rE|j                  j                  j                         r!t         j                  j                  d	d
       yy# t        $ r Y yw xY w)u   cuda (RTX box) → mps (Apple Silicon, e.g. Ahmed's M4) → cpu.

    Returns the device Chatterbox should load on, or None when no acceptable
    device is available (→ Kokoro). CB_DEVICE overrides the auto-pick.
    	CB_DEVICE )cudampscpur   Ng    eAr'   r(   PYTORCH_ENABLE_MPS_FALLBACK1)osenvirongetlowertorchr'   is_availablemem_get_info_MIN_FREE_VRAM_GBgetattrbackendsr(   
setdefault	Exception)overrider0   free_totals       B/Users/ahmed/devFolder/Ultron/claude-voice/voice/tts_chatterbox.py_pick_devicer<   :   s     zz~~k2.446H))::""$ ::224LD&!CZ+<<6F$F
 5>>5$/ENN4F4F4S4S4UJJ!!"?E   s   AC ?C AC 	C*)C*c                   t         j                  | xs d      }|r9| |j                         d t        |j	                  d      j                            fS t        j                  | xs d      }|r}|j	                  d      j                         dd j                         j                         }|r|j                         d   nd}| |j                         d t        j                  |      fS | dfS )u   Strip a leading [emotion] tag; return (clean_text, exaggeration).
    Unknown tone tags are stripped too (a TTS must never read one aloud);
    their last word is tried as an emotion key ("[Mildly excited]" → 0.85).r&   N   r   )
_TAG_REmatchend	_EMOTIONSgroupr/   _ANY_TAG_REstripsplitr.   )textminnerkeys       r;   split_emotionrL   T   s     	djb!AAEEGH~y)9)9);<<<$*"%A
  "1R(..0668#(ekkmBbAEEGH~y}}S111:    c                     t         j                  j                  dd      j                         } | dk(  ry| dk(  ryt	               duS )zOnly claim the accelerator when there's honest headroom (games come first
    on CUDA; on Apple Silicon MPS we load whenever it's available).VOICE_ENGINEauto
chatterboxTkokoroFN)r,   r-   r.   r/   r<   )forceds    r;   loadablerT   c   sD     ZZ^^NF399;F>%%rM   c                  V    e Zd ZdZdddZed        Zej                  d        Zd	dZy)
ChatterboxTTSzDDrop-in for voice.tts.KokoroTTS: synth(text) -> float32 PCM @ 24kHz.Nc                   |xs t               xs d| _        dd lm} dd lm dfd	}||_        dd l}t        |dd        G d d      }||_	        |j                  j                  | j                        | _        t        t        j                  j!                  dd	            | _        d
| _        t        j                  j!                  dt'        t(                    }t        j*                  j-                  |      r|nd | _        | j.                  r,t1        dt        j*                  j3                  |              nt1        dt(         d       | j5                  d       y )Nr)   r   c                    t        | d      5 }j                  |j                               }d d d        |dvr2j                         D ci c]  \  }}||j	                  |       }}}S # 1 sw Y   AxY wc c}}w )Nrb)Nr)   )openloadreaditemsto)filenamedeviceftensorskv_sts         r;   _safe_load_filez/ChatterboxTTS.__init__.<locals>._safe_load_filez   sm    h%((1668, &]*7>}}Gtq!1add6l?GN	 &% Hs    A.A:.A7PerthImplicitWatermarkerc                      e Zd Zd Zy),ChatterboxTTS.__init__.<locals>._NoWatermarkc                    |S N )selfwavakws       r;   apply_watermarkz<ChatterboxTTS.__init__.<locals>._NoWatermark.apply_watermark   s    JrM   N)__name__
__module____qualname__rq   rl   rM   r;   _NoWatermarkri      s    rM   ru   r`   CB_EXAGGERATIONz0.5g      ?	VOICE_REFz  voice: cloned from z3  voice: Chatterbox default (drop a 10-20s clip at z to clone a voice)zWarm up.)r)   )r<   _devicechatterbox.ttsttssafetensors.torchr0   	load_fileperthr4   rg   rV   from_pretrained_modelfloatr,   r-   r.   _exag_speedstr_DEFAULT_REFpathisfile_refprintbasenamesynth)rm   r`   _cbtrf   _perthru   refre   s          @r;   __init__zChatterboxTTS.__init__q   s   885
 	&'	 ) 	65t<D  /;F+((888M2::>>*;UCD
jjnn[#l*;<77>>#.CD	99)"''*:*:3*?)@ABG!N"46 7

:rM   c                "    | j                   xs dS )Nzchatterbox-default)r   )rm   s    r;   _voicezChatterboxTTS._voice   s    yy000rM   c                t    t        |t              r(t        j                  j	                  |      r|| _        y y y rk   )
isinstancer   r,   r   r   r   )rm   rd   s     r;   r   zChatterboxTTS._voice   s*    a"''.."3DI #4rM   c                    t        |      \  }}|j                         s%t        j                  dt        j                        S d||n| j
                  i}| j                  r| j                  |d<    | j                  j                  |fi |}|j                         j                         j                         j                         j                  t        j                        }t        t        | j                  dt                     }|t         k7  rt#        |      rt        t#        |      t         z  |z        }t        j$                  dt#        |      dz
  |      }	t        j&                  |	      j                  t              }
t        j(                  |
dz   t#        |      dz
        }|	|
z
  j                  t        j                        }||
   d|z
  z  ||   |z  z   j                  t        j                        }|S )z>text (optionally '[emotion] ...') -> float32 mono PCM @ 24kHz.r   )dtypeexaggerationaudio_prompt_pathsrr>   )rL   rF   npzerosfloat32r   r   r   generatesqueezedetachr)   numpyastypeintr4   SAMPLE_RATElenlinspacefloorminimum)rm   rH   cleanexagkwargsrn   pcmr   nxsi0i1ra   s                r;   r   zChatterboxTTS.synth   s   #D)t{{}88ARZZ00 $*:$

K99*.))F&'"dkk""53F3kkm""$((*00299"**EdK89SCH{*R/0AQC1a0B"$$S)BBFCHqL1Bb  ,Ar7a!e$s2w{2::2::FC
rM   rk   )r`   
str | NonereturnNone)rH   r   r   z
np.ndarray)	rr   rs   rt   __doc__r   propertyr   setterr   rl   rM   r;   rV   rV   n   s<    N$N 1 1 ]] rM   rV   c                 p   ddl } t        j                  j                  dd      j	                         }|dk(  s|dk(  r*| j
                  dk(  r	 ddlm}  |       }t        d       |S |dk(  xs |dk(  xr | j
                  dk7  }|rCt               r9t               xs d}	 t        |      }t        d|j                                 |S ddlm}  |       S # t        $ r%}t        d	t        |      dd
  d       Y d}~d}~ww xY w# t        $ r%}t        dt        |      dd
  d       Y d}~gd}~ww xY w)uo  Best available voice per platform, falling back so Jarvis is never
    mute. macOS: Pocket TTS (cloned, streaming, ~7x realtime on 2 CPU cores
    of the M4 — Chatterbox-on-MPS is structurally slow and RAM-heavy there)
    → Kokoro. Elsewhere: Chatterbox on the GPU when it has room → Kokoro.
    VOICE_ENGINE=chatterbox|kokoro|pocket forces an engine anywhere.r   NrO   rP   pocketdarwin)	PocketTTSz(  TTS: Pocket (cloned, streaming) on CPUz  TTS: Pocket unavailable (Z   u   ) — falling backrQ   r)   rv   z"  TTS: Chatterbox (expressive) on z  TTS: Chatterbox unavailable (u   ) — Kokoro)	KokoroTTS)sysr,   r-   r.   r/   platformvoice.tts_pocketr   r   r7   r   rT   r<   rV   upper	voice.ttsr   )r   rS   r   r{   ewant_chatterboxdevr   s           r;   load_ttsr      s8    ZZ^^NF399;Ff.3<<83K	Q2+C<=J
 - J!V+H0H 8:n%	Os+C6syy{mDEJ $;  	Q/As}<NOPP	Q  	O3CF3BK=MNN	Os0   C )D 	DC??D	D5D00D5)r   r   )rH   r   r   ztuple[str, float | None])r   bool)r   
__future__r   r,   repathlibr   r   r   r   __file__resolveparent_PROJECTr   rC   compilejoin
IGNORECASEr@   rE   r   r-   r.   r3   r<   rL   rT   rV   r   rl   rM   r;   <module>r      s  * # 	 	  >!!#**11("%55	
D	$	 &	.5t	t	t	%.	6;T	 	 d	 %.t	 6?	
 t	
 !$	
 )24	
 :Ft	 	 "&$$$TDdD4		 "**)$$y0"--A bjj;R]]K
 "**..>? 4&F FRrM   