+
    Y*j  c                     R t ^ RIHt ^ RIt^ RIHu Ht ^ RI	t	^ RI
t
^ RIHtHtHtHt R tR tR tR t]
P(                  P*                  R 4       t]
P(                  P*                  R	 4       tR
 tR tR tR tR t]
P(                  P*                  R 4       t]
P(                  P*                  R 4       tR tR t R t!R# )u   Tests for runtime/speech/tts.py.

All offline — uses FakeTTS test double. Live Kokoro/F5 tests require
MENTORCORE_TEST_TTS=1 and installed model weights.
)annotationsN)FakeTTSVoiceConfig_iter_sentences_split_sentencesc                    \        R 4      p R .qV8H  q"'       g   \        P                  ! RV3RW34      RR\        P                  ! 4       9   g   \        P
                  ! V 4      '       d   \        P                  ! V 4      MRR\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;r!R# )	zHello world.py0	sentencespy3assert %(py5)spy5N==z%(py0)s == %(py3)s	r   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation)r   @py_assert2@py_assert1@py_format4@py_format6s        >/Users/jameslopez/projects/MentorCore/tests/speech/test_tts.pytest_split_sentences_singler      so     0I'((((((((9((((((9((((9((((((((((((    c                    \        R 4      p \        V 4      p^q!V8H  q3'       Eg   \        P                  ! RV3RW34      RR\        P
                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRRR\        P
                  ! 4       9   g   \        P                  ! V 4      '       d   \        P                  ! V 4      MRR\        P                  ! V4      R\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR	;p;r2V ^ ,          pR
qvV8H  q'       gy   \        P                  ! RV3RWg34      R\        P                  ! V4      R\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR	;p;rR	# )z&Be virtuous. Avoid excess. Seek truth.r   lenpy1r   r	   py6assert %(py8)spy8NzBe virtuous.py4assert %(py6)sr   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sz%(py1)s == %(py4)s)
r   r    r   r   r   r   r   r   r   r   )	r   r   @py_assert5@py_assert4@py_format7@py_format9@py_assert0@py_assert3@py_format5s	            r   test_split_sentences_multipler0      s     !IJIy>QQ>33yy>QQ<)>)>)))))<)))<)))>))))))))r   c                     \        R 4      p R V  4       p\        V4      q"'       g   RRR\        P                  ! 4       9   g!   \        P
                  ! \        4      '       d   \        P                  ! \        4      MRR\        P                  ! V4      R\        P                  ! V4      /,          p\        \        P                  ! V4      4      hR;r\        V 4      p^qTV8H  qf'       Eg   \        P                  ! RV3RWE34      RR\        P                  ! 4       9   g!   \        P
                  ! \        4      '       d   \        P                  ! \        4      MRR	R
\        P                  ! 4       9   g   \        P
                  ! V 4      '       d   \        P                  ! V 4      MR
R\        P                  ! V4      R\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;p;reR# )z  First.  Second.  c              3  F   "   T F  qVP                  4       8H  x  K  	  R # 5iN)strip.0ss   & r   	<genexpr>9test_split_sentences_strips_whitespace.<locals>.<genexpr>   s     1y!AGGI~ys   !,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}r   allpy2r%   Nr    r!   r   r	   r"   r#   r$   r   r'   )r   r;   r   r   r   r   r   r   r   r    r   )	r   r   r.   r/   r   r)   r*   r+   r,   s	            r   &test_split_sentences_strips_whitespacer=      s	    !67I1y113111111111131111311111111111111y>QQ>33yy>Qr   c                    R p \        V 4      p. q!V8H  q3'       g   \        P                  ! R
V3RW34      RR\        P                  ! 4       9   g!   \        P
                  ! \         4      '       d   \        P                  ! \         4      MRR\        P                  ! V 4      R\        P                  ! V4      R\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;p ;p;r2R	p \        V 4      p. q!V8H  q3'       g   \        P                  ! R
V3RW34      RR\        P                  ! 4       9   g!   \        P
                  ! \         4      '       d   \        P                  ! \         4      MRR\        P                  ! V 4      R\        P                  ! V4      R\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;p ;p;r2R# ) r   r   r<   r%   py7zassert %(py9)spy9Nz   r   )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)sr   )r   r.   @py_assert6r)   @py_format8@py_format10s         r   test_split_sentences_emptyrE   "   s   %B%2%2%%%%%%%%%%%%%%%%%%B%%%%%%2%%%%%%%%!(E"(b(b((((("(((((((((((((E((("(((b((((((((r   c                 4  "   R  p . p\        V ! 4       4        Rj  xL
  pVP                  V4       K   LD\        T4      p^qCT8H  qU'       Eg   \        P                  ! RT3RY434      RR\
        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRRR\
        P                  ! 4       9   g   \        P                  ! T4      '       d   \        P                  ! T4      MRR\        P                  ! T4      R\        P                  ! T4      /,          pRR	T/,          p\        \        P                  ! T4      4      hR;p;rTR
q^ ,          qT	9   q3'       gy   \        P                  ! RT3RY34      R\        P                  ! T4      R\        P                  ! T	4      /,          p
RRT
/,          p\        \        P                  ! T4      4      hR;p;r9Rq^,          qT	9   q3'       gy   \        P                  ! RT3RY34      R\        P                  ! T4      R\        P                  ! T	4      /,          p
RRT
/,          p\        \        P                  ! T4      4      hR;p;r9R# 5i)c                *   "   R F  p V 5x  K
  	  R# 5i)BeN)rH   z virtzuous. Avoidz excess. )tokens    r   tokens=test_iter_sentences_yields_complete_sentences.<locals>.tokens)   s     GEK H   Nr   r    r!   resultsr	   r"   r#   r$   virtuousr%   r&   excessr   r'   )in)z%(py1)s in %(py4)sr   appendr    r   r   r   r   r   r   r   r   rM   rP   sentencer   r)   r*   r+   r,   r-   r.   r/   s              r   -test_iter_sentences_yields_complete_sentencesrX   '   sp     G)&(3 ! !hx !3 w<11<33ww<1#######:###:###########!qz!z!!!!!8!!!8!!!z!!!!!!!!s.   J757J7A.J&AJ8F Jc                   "   R  p . p\        V ! 4       4        Rj  xL
  pVP                  V4       K   LD\        T4      p^qCT8H  qU'       Eg   \        P                  ! RT3RY434      RR\
        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRRR\
        P                  ! 4       9   g   \        P                  ! T4      '       d   \        P                  ! T4      MRR\        P                  ! T4      R\        P                  ! T4      /,          pRR	T/,          p\        \        P                  ! T4      4      hR;p;rTT^ ,          pR
qT	8H  q3'       gy   \        P                  ! RT3RY34      R\        P                  ! T4      R\        P                  ! T	4      /,          p
RRT
/,          p\        \        P                  ! T4      4      hR;p;r9R# 5i)c                   "   R 5x  R# 5i)No final periodNrK   rK   r   r   rM   8test_iter_sentences_yields_trailing_text.<locals>.tokens8   s     s   
Nr   r    r!   rP   r	   r"   r#   r$   r[   r%   r&   r   r'   r(   rT   rV   s              r   (test_iter_sentences_yields_trailing_textr]   6   s'      G)&(3 ! !hx !3 w<11<33ww<11:*********:***:************s.   H757H7A.H&AH8DHc            	     r   \        4       p V P                  pR q!V8H  q3'       g   \        P                  ! R
V3RW34      RR\        P
                  ! 4       9   g   \        P                  ! V 4      '       d   \        P                  ! V 4      MRR\        P                  ! V4      R\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;p;r2V P                  pRq!V8H  q3'       g   \        P                  ! R
V3RW34      RR\        P
                  ! 4       9   g   \        P                  ! V 4      '       d   \        P                  ! V 4      MRR\        P                  ! V4      R\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;p;r2V P                  pR	q!V8H  q3'       g   \        P                  ! R
V3RW34      RR\        P
                  ! 4       9   g   \        P                  ! V 4      '       d   \        P                  ! V 4      MRR\        P                  ! V4      R\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;p;r2R# )kokoror   cfgr<   r   assert %(py7)sr@   Ni]  g      ?r   z.%(py2)s
{%(py2)s = %(py0)s.engine
} == %(py5)s)z3%(py2)s
{%(py2)s = %(py0)s.sample_rate
} == %(py5)s)z-%(py2)s
{%(py2)s = %(py0)s.speed
} == %(py5)s)r   enginer   r   r   r   r   r   r   r   sample_ratespeedr`   r   r*   r.   r   rC   s         r   test_voice_config_defaultsrg   F   s_   
-C::!!!!!!!:!!!!!!3!!!!3!!!:!!!!!!!!!!!??#e#e#####?######3####3###?###e########999339r   c            	        \        R R7      p V P                  pR q!V8H  q3'       g   \        P                  ! R	V3R
W34      RR\        P
                  ! 4       9   g   \        P                  ! V 4      '       d   \        P                  ! V 4      MRR\        P                  ! V4      R\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;p;r2R# )fakerc   r   r`   r<   r   ra   r@   Nr   rb   )
r   rc   r   r   r   r   r   r   r   r   rf   s         r   test_voice_config_fake_enginerk   M   s~    
V
$C:::33:r   c                    \        ^dR7      p V P                  R\        4       4      p\        V4      p^ q2V8  qD'       Eg   \        P
                  ! RV3RW#34      RR\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRRR\        P                  ! 4       9   g   \        P                  ! V4      '       d   \        P                  ! V4      MRR\        P                  ! V4      R\        P                  ! V4      /,          pR	R
V/,          p\        \        P                  ! V4      4      hR;p;rCR# )d   duration_msHello.r   r    r!   pcmr	   r"   r#   r$   N>z/%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} > %(py6)s)r   
synthesizer   r    r   r   r   r   r   r   r   r   )ttsrq   r   r)   r*   r+   r,   s          r   !test_fake_tts_returns_nonzero_pcmrw   U   s    
c
"C
..;=
1Cs8aa<833ss8ar   c                    \        ^2R7      p V P                  R\        4       4      p\        V4      p^q2V,          p^ qTV8H  qf'       Eg3   \        P
                  ! RV3RWE34      RR\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRRR\        P                  ! 4       9   g   \        P                  ! V4      '       d   \        P                  ! V4      MRR\        P                  ! V4      R\        P                  ! V4      R	\        P                  ! V4      /,          pR
RV/,          p\        \        P                  ! V4      4      hR;p;p;p;re\        P                  ! R\        V4      ^,           R2V4      p	R V	 4       p
\        V
4      q'       g   RRR\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRR\        P                  ! V
4      R\        P                  ! V4      /,          p\        \        P                  ! V4      4      hR;rR# )z$PCM is 16-bit aligned and parseable.rn   Test.r   r    r!   rq   r	   r   rA   zassert %(py11)spy11N<hc              3  *   "   T F	  q^ 8H  x  K  	  R# 5i    NrK   r5   s   & r   r8   2test_fake_tts_returns_valid_pcm.<locals>.<genexpr>a   s     'w!AvwrO   r:   r;   r<   r%   r   )z=(%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} %% %(py5)s) == %(py9)s)r   ru   r   r    r   r   r   r   r   r   r   r   structunpackr;   )rv   rq   r   r*   rB   @py_assert8@py_assert7rD   @py_format12samplesr   r.   r/   s                r   test_fake_tts_returns_valid_pcmr   [   sR   
b
!C
..+-
0Cs8aa<11<33ss8a1mmaCAa0#6G'w''3''''''''''3''''3''''''''''''''r   c                 |   \        ^dR7      p V P                  R\        4       4      p\        \         P                  R,          4      ^,          p\        V4      q3V8H  qD'       EgU   \        P                  ! RV3RW234      RR\        P                  ! 4       9   g!   \        P                  ! \
        4      '       d   \        P                  ! \
        4      MRRR\        P                  ! 4       9   g   \        P                  ! V4      '       d   \        P                  ! V4      MRR\        P                  ! V4      R	R
\        P                  ! 4       9   g   \        P                  ! V4      '       d   \        P                  ! V4      MR
/,          pRRV/,          p\        \        P                  ! V4      4      hR;r4R# )z+100ms at 24kHz = 2400 samples = 4800 bytes.rn   ry   g?r   r    r!   rq   r	   r   expected_bytesra   r@   Nr   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py5)s)r   ru   r   intSAMPLE_RATEr    r   r   r   r   r   r   r   r   )rv   rq   r   r   r*   r   rC   s          r   test_fake_tts_durationr   d   s    
c
"C
..+-
0C,,s23a7Ns8%~%%%%%8%%%%%%3%%%%3%%%%%%%s%%%%s%%%8%%%%%%~%%%%~%%%%%%%%r   c                   "   R  p \        ^2R7      p. pVP                  V ! 4       \        RR7      4        Rj  xL
  pVP                  V4       K   LD\	        T4      p^qTT8H  qf'       Eg   \
        P                  ! RT3RYE34      RR\        P                  ! 4       9   g!   \
        P                  ! \        4      '       d   \
        P                  ! \        4      MRRR\        P                  ! 4       9   g   \
        P                  ! T4      '       d   \
        P                  ! T4      MRR	\
        P                  ! T4      R
\
        P                  ! T4      /,          pRRT/,          p\        \
        P                  ! T4      4      hR;p;reR T 4       p	\        T	4      q'       g   RRR\        P                  ! 4       9   g!   \
        P                  ! \        4      '       d   \
        P                  ! \        4      MRR\
        P                  ! T	4      R\
        P                  ! T
4      /,          p\        \
        P                  ! T4      4      hR;rR# 5i)c                *   "   R F  p V 5x  K
  	  R# 5i)First sentence. N)r   zSecond sentence.rK   )ts    r   rM   Btest_fake_tts_stream_yields_one_chunk_per_sentence.<locals>.tokensn   s     9AG :rO   rn   ri   rj   Nr   r    r!   chunksr	   r"   r#   r$   c              3  >   "   T F  p\        V4      ^ 8  x  K  	  R# 5ir~   )r    )r6   cs   & r   r8   Etest_fake_tts_stream_yields_one_chunk_per_sentence.<locals>.<genexpr>x   s     *6as1vz6s   r:   r;   r<   r%   r   r'   )r   synthesize_streamr   rU   r    r   r   r   r   r   r   r   r   r;   )rM   rv   r   chunkr   r)   r*   r+   r,   r   r.   r/   s               r   2test_fake_tts_stream_yields_one_chunk_per_sentencer   l   sP     b
!CF,,VX{&7QR  eeR v;!!;33vv;!*6**3**********3****3**************s;   3IAAAIAA.IAICI&A3Ic                 *  "   R  p \        4       p. pVP                  V ! 4       \        4       4        Rj  xL
  pVP                  V4       K   LD. qBT8H  qU'       g   \        P
                  ! RT3RY$34      RR\        P                  ! 4       9   g   \        P                  ! T4      '       d   \        P                  ! T4      MRR\        P                  ! T4      /,          pRRT/,          p\        \        P                  ! T4      4      hR;rTR# 5i)	c                   "   R # 5ir3   rK   rK   r   r   rM   0test_fake_tts_stream_empty_input.<locals>.tokens}   s     s   Nr   r   r	   r
   r   r   r   )r   r   r   rU   r   r   r   r   r   r   r   r   )rM   rv   r   r   r   r   r   r   s           r    test_fake_tts_stream_empty_inputr   {   s      )CF,,VX{}E  eeE R<666Rs-   /DAAADAAD/A$Dc                    ^ RI Hp  V ! R\        RR7      4      p\        V4      p^ q2V8  qD'       Eg   \        P
                  ! RV3RW#34      RR\        P                  ! 4       9   g!   \        P                  ! \        4      '       d   \        P                  ! \        4      MRRR\        P                  ! 4       9   g   \        P                  ! V4      '       d   \        P                  ! V4      MRR	\        P                  ! V4      R
\        P                  ! V4      /,          pRRV/,          p\        \        P                  ! V4      4      hR;p;rCR# )r   ru   rp   ri   rj   r   r    r!   rq   r	   r"   r#   r$   Nrr   rt   )runtime.speech.ttsru   r   r    r   r   r   r   r   r   r   r   )ru   rq   r   r)   r*   r+   r,   s          r   test_synthesize_fake_enginer      s    -
X{&9
:Cs8aa<833ss8ar   c            	         ^ RI Hp  \        P                  ! \        RR7      ;_uu_ 4        V ! R\        RR7      4       RRR4       R#   + '       g   i     R# ; i)r   r   zUnknown TTS enginematchrp   unknownrj   Nr   ru   pytestraises
ValueErrorr   r   s    r   %test_synthesize_unknown_engine_raisesr      s5    -	z)=	>	>8[	:; 
?	>	>	>   A		A	c            	         ^ RI Hp  \        P                  ! \        RR7      ;_uu_ 4        V ! R\        RR7      4       RRR4       R#   + '       g   i     R# ; i)r   r   reference_audior   rp   f5rj   Nr   r   s    r   1test_synthesize_f5_without_reference_audio_raisesr      s5    -	z):	;	;8[56 
<	;	;	;r   )"__doc__
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r   r   r   r   r   r   r   r   r0   r=   rE   markasynciorX   r]   rg   rk   rw   r   r   r   r   r   r   r   rK   r   r   <module>r      s    #     V V
)
*)
 " " 	+ 	+ (& + + 
 
 <7r   