
    ESj                     p   d Z ddlZddlmc mZ ddlmZ ddl	m
Z
 ddlmZ ddl	mZ ddlmZmZmZ d d	Zd
ddededefdZd Zd Zd Zd Zd Zd Zd Zd Zd Zedk(  rddl Z  e! e"       jG                               D  cg c]  \  } }| jI                  d      s| c}} Z%dZ&e%D ]  Z'	  e'         e(de'j>                          !  e(d e+e%      e&z
   d e+e%       d        e,e&rd      d      yc c}} w # e)$ r. e&dz  Z& e(de'j>                           e jT                          Y w xY w)!u  Tone-aware TTS (TONE_TTS): the sensing → delivery bridge, in pure logic.

Two halves of the "voice presence" move, tested without any audio or model:
  1. voice.prosody's rolling ToneState — the EMA smooths Ahmed's recent vocal
     energy so one loud word can't flip the mood, and laughter recency fades.
  2. voice.tts_pocket's clip picker (_biased_stem) — a specific brain tag wins;
     a bouncy tag softens to `warm` when he's plainly down (never urgent/
     annoyed/shocked); an untagged line follows his tone; TONE_TTS=0 replays
     today's tag-only pick byte-for-byte.

Run: `python -m pytest test_tone.py`  (or `python test_tone.py` standalone).
    N)SimpleNamespace)prosody)	ToneState)
tts_pocket)_biased_stem_NEVER_DAMP_TAG_TO_STEMreturnc                  *    t               t        _        y)uH   Neutral tone state — the picker tests that read the global start here.N)r   r   _TONE_STATE     7/Users/ahmed/devFolder/Ultron/claude-voice/test_tone.py_resetr      s    #+Gr   Flaughtagsr   c                     t        j                  t        j                  t        |      d| i             t        j                         S )zDFold one synthetic read (just its tags) into the rolling tone state.r   )r   feats)r   _publish_toneProsodylist
tone_state)r   r   s     r   _pubr      s:    '//tDz18%0@B Cr   c                     t                t        d      D ]  } t        d        t        j                  } |       }|j
                  }|st        j                  d      dz   dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            d x}x}}t        d      }|j                  }| }|st        j                  d      d	z   d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }t        t        j                  |            d x}}y )N   animatedz%sustained energy should read animatedz_
>assert %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.tone_state
}()
}.up
}r   )py0py2py4py6flatz/a single flat turn must not flip a settled moodz.
>assert not %(py2)s
{%(py2)s = %(py0)s.down
}str   r   )r   ranger   r   r   up
@pytest_ar_format_assertmsg@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationdown)_@py_assert1@py_assert3@py_assert5@py_format7r#   @py_format4s          r   )test_ema_settles_and_one_word_cannot_flipr6   &   s    
H1XZ KK""K"KK$KKKKKKK7KKK7KKKKKKKKK"KKKKKK	fBwwIw;I;IIIIIIIIIrIIIrIIIwIIIIIIr   c                  6   t                t        dd      } | j                  }| }|st        j                  d      dz   dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dz  }t        t        j                  |            d x}}t        d      D ]  }t        dd      }  g }| j                  }|}|r| j                  }|}|r| j                  }|}|sddt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      d	z  }|j                  |       |rd
dt        j                         v st        j                  |       rt        j                  |       ndt        j                        dz  }	|j                  |	       |rlddt        j                         v st        j                  |       rt        j                  |       ndt        j                        dz  }
|j                  |
       t        j                  |d      i z  }dd|iz  }t        t        j                  |            d x}x}x}x}}y )Nr"   slowz6one flat turn is 'down' at most, not yet 'really flat'z-
>assert not %(py2)s
{%(py2)s = %(py0)s.low
}r#   r$   r   z!%(py4)s
{%(py4)s = %(py2)s.down
})r   r    z %(py8)s
{%(py8)s = %(py6)s.low
})r!   py8z$%(py12)s
{%(py12)s = %(py10)s.slow
})py10py12r   zassert %(py15)spy15)r   r   lowr'   r(   r)   r*   r+   r,   r-   r.   r%   r/   r8   append_format_boolop)r#   r1   r2   r5   r0   @py_assert0@py_assert7@py_assert11@py_format5@py_format9@py_format13@py_format14@py_format16s                r   test_flat_and_slow_read_downrH   /   sn   
H	ff	BvvOv:O:OOOOOOOOOrOOOrOOOvOOOOOO1X&&! )277)7)7rvv)v)v"'')'))))))2)))2)))7))))7)))))r)))r)))v))))v)))))")))")))')))))))))))))r   c                     t                d} d}t        | |      }|j                  }|sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |       t        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            d x} x}x}}t               } | j                  }|st        j                  d      dz   dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |       t        j                  |      d	z  }t        t        j                  |            d x} }t               } | j                  }| }|st        j                  d
      dz   dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |       t        j                  |      d	z  }t        t        j                  |            d x} x}}y )NlaughingTr   zYassert %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py0)s(%(py2)s, laugh=%(py4)s)
}.laughing
}r   )r   r   r    r!   r9   z-laughter should still register one turn laterzE
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s()
}.laughing
})r   r   r    u   …then fadezI
>assert not %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s()
}.laughing
})r   r   rJ   r)   r*   r'   r+   r,   r-   r.   r(   )r1   r2   r3   rA   rD   rC   @py_format6s          r   test_laughter_recency_decaysrL   8   sW   
H0$04
$'0'00000000040004000
000$000'00000000006K6??K?KKKKKKKKK4KKK4KKK6KKK?KKKKKKv.v..........t...t...v.........r   c                     t        d      } dD ]  \  }}d}t        ||| |      }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      ndd	t	        j
                         v st        j                  |      rt        j                  |      nd	d
t	        j
                         v st        j                  |       rt        j                  |       nd
t        j                  |      t        j                  |      d	t	        j
                         v st        j                  |      rt        j                  |      nd	dz  }dd|iz  }t        t        j                  |            d x}x}} y )Ng?energy))calmrP   )dryrQ   )curiousrR   )sadrS      ==zK%(py7)s
{%(py7)s = %(py0)s(%(py1)s, %(py2)s, %(py3)s, %(py5)s)
} == %(py9)sr   tagstemr&   r   py1r   py3py5py7py9zassert %(py11)spy11
r   r   r'   _call_reprcomparer)   r*   r+   r,   r-   r.   )r&   rX   rY   @py_assert4@py_assert6@py_assert8@py_format10@py_format12s           r    test_specific_tag_wins_over_tonerh   A   s   	#	B>	T+-6|Cr2.6.$6666.$666666|666|666666C666C666666666666666r666r6662666.666666$666$6666666>r   c            
      (   t        d      } t        d      }t               }d}d}d}t        ||| |      }d}||k(  }|s2t        j                  d|fd||f      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      t        j                  |      d
t	        j
                         v st        j                  |       rt        j                  |       nd
t        j                  |      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d x}x}x}x}x}}d}d}d}t        ||| |      }d}||k(  }|s2t        j                  d|fd||f      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      t        j                  |      d
t	        j
                         v st        j                  |       rt        j                  |       nd
t        j                  |      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d x}x}x}x}x}}d}d}d}t        ||||      }d}||k(  }|s2t        j                  d|fd||f      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d x}x}x}x}x}}d}d}d}t        ||||      }d}||k(  }|s2t        j                  d|fd||f      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d x}x}x}x}x}}y )N333333rN   333333?excitedrT   warmrU   zL%(py9)s
{%(py9)s = %(py0)s(%(py2)s, %(py4)s, %(py5)s, %(py7)s)
} == %(py12)sr   r/   r   r   r    r]   r^   r_   r;   assert %(py14)spy14amusedr&   neutralra   )r/   r&   rs   r1   r2   rd   re   rB   @py_assert10rE   @py_format15s              r   "test_bounce_softens_only_when_downrv   J   sA   D!D	#	BkG!A9ABA<	9dB7A6A76AAAA76AAAAAA<AAA<AAA	AAA9AAAAAAdAAAdAAABAAA7AAA6AAAAAAAA ?(?"?<(D"5??5????5??????<???<??????(??????D???D???"???5???????????!B9B"B<	9b"5BB5BBBB5BBBBBB<BBB<BBB	BBB9BBBBBBbBBBbBBB"BBB5BBBBBBBBBBB!G9GrG<	9gr:GiG:iGGGG:iGGGGGG<GGG<GGG	GGG9GGGGGGgGGGgGGGrGGG:GGGiGGGGGGGGr   c                     t        dd      } t        D ]  }t        j                  |      }d }||u}|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }t	        j                  | d      d	z   d
|iz  }t        t	        j                  |            d x}}d}t        ||| |      }||k(  }	|	st	        j
                  d|	fd||f      dt        j                         v st	        j                  t              rt	        j                  t              nddt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      nddz  }
t	        j                  | d      dz   d|
iz  }t        t	        j                  |            d x}x}}	 y )Ng333333g      rO   pace)is not)z%(py0)s is not %(py3)srY   )r   r\   z should map to a clipz
>assert %(py5)sr]   r   rU   rW   r   rX   	deep_downrZ   u0    must never soften — the meter earns its shoutz
>assert %(py11)sr`   )r   r   r	   getr'   rb   r)   r*   r+   r,   r(   r-   r.   r   )r{   rX   rY   @py_assert2r1   r5   rK   rc   rd   re   rf   rg   s               r   2test_never_damp_list_holds_at_deep_down_late_nightr~   T   s|   D1I{$>t4>>>t4>>>>>>t>>>t>>>4>>>C5(=!>>>>>>>23 	E|Cy!4 	E4< 	E 	E3D3D	E4 	E 	E>Df	E 	E,D,D  	E 	E;D9  	E 	E>Df	E 	E,D,D   	E 	E;D9   	E 	E>Df	E 	E,D,D "& 	E 	E;D9 "& 	E 	E>Df	E 	E,D,D (1 	E 	E;D9 (1 	E 	E;D9 34 	E 	E;D9 5 	E 	E>Df	E 	E,D,D 9= 	E 	E;D9 9= 	E 	E3D3DseCD	E 	E 	E1D1D	E 	E 	E r   c                  J   d } d }t               }d}t        | |||      }d }||u }|sNt        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |       t        j                  |      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x} x}x}x}x}x}}d } d }d	}t        |
      }d}t        | |||      }d}	||	k(  }
|
sbt        j                  d|
fd||	f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |       t        j                  |      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |	      d	z  }dd|iz  }t        t        j                  |            d x} x}x}x}x}x}x}
}	d } d }d}t        |
      }d}t        | |||      }d}	||	k(  }
|
sbt        j                  d|
fd||	f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |       t        j                  |      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |	      d	z  }dd|iz  }t        t        j                  |            d x} x}x}x}x}x}x}
}	d } d }d}t        |      }d}t        | |||      }d}	||	k(  }
|
sbt        j                  d|
fd||	f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |       t        j                  |      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |	      d	z  }dd|iz  }t        t        j                  |            d x} x}x}x}x}x}x}
}	d } d }d	}| }t        |
      }d}t        | |||      }d}||k(  }	|	sbt        j                  d|	fd||f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |       t        j                  |      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      d	z  }dd|iz  }t        t        j                  |            d x} x}x}x}x}x}x}x}	}d } d }d}| }t        |
      }d}t        | |||      }d}||k(  }	|	sbt        j                  d|	fd||f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |       t        j                  |      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      d	z  }dd|iz  }t        t        j                  |            d x} x}x}x}x}x}x}x}	}y )NrT   )is)ze%(py11)s
{%(py11)s = %(py0)s(%(py2)s, %(py4)s, %(py7)s
{%(py7)s = %(py5)s()
}, %(py9)s)
} is %(py14)sr   r   )r   r   r    r]   r^   r_   r`   rq   zassert %(py16)spy16rk   rN   rr   rU   )zt%(py13)s
{%(py13)s = %(py0)s(%(py2)s, %(py4)s, %(py9)s
{%(py9)s = %(py5)s(energy=%(py7)s)
}, %(py11)s)
} == %(py16)s)	r   r   r    r]   r^   r_   r`   py13r   zassert %(py18)spy18g      ?rl   r   )zs%(py13)s
{%(py13)s = %(py0)s(%(py2)s, %(py4)s, %(py9)s
{%(py9)s = %(py5)s(laugh=%(py7)s)
}, %(py11)s)
} == %(py16)srm   )zw%(py14)s
{%(py14)s = %(py0)s(%(py2)s, %(py4)s, %(py10)s
{%(py10)s = %(py5)s(energy=-%(py7)s)
}, %(py12)s)
} == %(py17)s)	r   r   r    r]   r^   r:   r;   rq   py17zassert %(py19)spy19tenderra   )r1   r2   rd   re   rt   @py_assert13@py_assert12ru   @py_format17@py_assert15@py_assert14@py_format19@py_assert9rB   @py_assert16@py_format18@py_format20s                    r   test_untagged_follows_toner   _   s   <d<IK<<<dK4<<4<<<<4<<<<<<<<<<<<<<<<<d<<<<<<I<<<I<<<K<<<<<<4<<<<<<<<<<<JdJSJIS$9J2J<d$92>J(J>(JJJJ>(JJJJJJ<JJJ<JJJJJJdJJJJJJIJJJIJJJSJJJ$9JJJ2JJJ>JJJ(JJJJJJJJKdKSKIS$9K2K<d$92>K)K>)KKKK>)KKKKKK<KKK<KKKKKKdKKKKKKIKKKIKKKSKKK$9KKK2KKK>KKK)KKKKKKKKIdICIIC$8I"I<d$8"=II=IIII=IIIIII<III<IIIIIIdIIIIIIIIIIIIIICIII$8III"III=IIIIIIIIIIIIdIcIcTIIT$:IBI<d$:B?I6I?6IIII?6IIIIII<III<IIIIIIdIIIIIIIIIIIIIIcIII$:IIIBIII?III6IIIIIIIIKdKcKcTKIT$:KBK<d$:B?K8K?8KKKK?8KKKKKK<KKK<KKKKKKdKKKKKKIKKKIKKKcKKK$:KKKBKKK?KKK8KKKKKKKKKr   c            
         t        dd      } d }d }d}t        ||| |      }d}||k(  }|s2t        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            d x}x}x}x}x}}d }d }d}t        ||| |      }d}||k(  }|s2t        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            d x}x}x}x}x}}y )Nrj   rx      rP   rU   rn   r   tonero   rp   rq   rT   rm   ra   )	r   r1   r2   rd   re   rB   rt   rE   ru   s	            r   $test_late_night_flat_slow_is_softestr   h   s   Dt,D6d6!6<dD!,66,6666,666666<666<666666d666666D666D666!666,666666666667d7"7<dD"-77-7777-777777<777<777777d777777D777D777"777-77777777777r   c            
      <   t        d      t        _        t        ddddd      } d| _        t
        j                  }|j                  }d	} || |      }d
}||k(  }|s2t        j                  d|fd||f      dt        j                         v st        j                  t
              rt        j                  t
              ndt        j                  |      t        j                  |      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}x}}d| _        t
        j                  }|j                  }d	} || |      }d}||k(  }|s2t        j                  d|fd||f      dt        j                         v st        j                  t
              rt        j                  t
              ndt        j                  |      t        j                  |      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}x}}t!                y )Nrj   rN   FBASEEXCWARM) rl   rm   )_plain_statesz[excited] hi)hir   rU   )zy%(py9)s
{%(py9)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.PocketTTS
}._state_for
}(%(py5)s, %(py7)s)
} == %(py12)sr   fakero   rp   rq   T)r   r   )r   r   r   r   	_tone_ttsr   	PocketTTS
_state_forr'   rb   r)   r*   r+   r,   r-   r.   r   )	r   r1   r2   rd   re   rB   rt   rE   ru   s	            r   test_flag_gates_the_biasr   p   s   #40Gv>@D DNQ**QQ*4@QMQ@MQQQQ@MQQQQQQ:QQQ:QQQQQQ*QQQQQQ4QQQ4QQQQQQ@QQQMQQQQQQQQDNR**RR*4@RNR@NRRRR@NRRRRRR:RRR:RRRRRR*RRRRRR4RRR4RRRRRR@RRRNRRRRRRRR
Hr   __main__test_zPASS     zFAIL  
/z passed)r
   N)-__doc__builtinsr)   _pytest.assertion.rewrite	assertionrewriter'   typesr   voicer   voice.prosodyr   r   voice.tts_pocketr   r   r	   r   strboolr   r6   rH   rL   rh   rv   r~   r   r   r   __name__	tracebacksortedglobalsitems
startswithfnsfailsfnprint	Exception	print_exclen
SystemExit)kvs   00r   <module>r      sc     !  #  D D
&
 $)    D  Y  J*/7HEL8 z	 12
L2Aall76K12
LCE	"DF2;;-()  
Bs3x% #c(7
34
%Q
''Q
'' 
L  	"QJEF2;;-()I!	"s   C<C</D0D54D5