
    DSj!                       d Z ddlmZ ddlZddlZddlZddlmZ ddlZ	dej                  d<   ddlmZ ddlmZmZ ddlZddlmZ d	 Zd
 Zd Zd Zd Zd Z G d d      Z G d d      Z G d d      Zd Zd Zd Zd Zd Z d Z!d Z"y)u  Meeting-mode tests — WAV recorder, multilingual STT selection/fallback,
transcript ordering, and the background transcription worker + backlog/finalize
logic. No real models, no audio devices, no Claude session (fakes throughout).

Run:  .venv/bin/python -m pytest test_meeting.py -q
    )annotationsN)Path0RESUME)MeetingSessionWavRecorder)VoiceAppc                   | dz  }t        |      }t        j                  t        j                  dddt        j                              dz  }t        j
                  ddt        j                        }|j                  |       |j                  |       |j                  d	k(  sJ t        |j                  d
z
        dk  sJ |j                          t        j                  t        |      d      5 }|j                         dk(  sJ |j                         dk(  sJ |j!                         dk(  sJ |j#                         d	k(  sJ t        j$                  |j'                  d	      d      j)                  t        j                        dz  }d d d        t        j*                  d d |d      sJ t        j*                  |dd  |d      sJ y # 1 sw Y   DxY w)Nzclip.wavr      i@  dtypeg      ?i  g      ?i  g      ?gư>rb      i>  <i2g    @gMbP?)atol)r   npsinlinspacefloat32fullwritesamplesabssecondsclosewaveopenstrgetnchannelsgetsampwidthgetframerate
getnframes
frombuffer
readframesastypeallclose)tmp_pathprecabwpcms          test_meeting.pytest_wav_recorder_roundtripr0      s{   :A
a.C
r{{1b$bjj9:S@A
T,AIIaLIIaL;;$s{{\)*T111IIK	3q64	 A~~1$$$~~1$$$~~5(((||~%%%mmALL.e<CCBJJORYY 
! ;;s5Dz14000;;s45z14000 
!	 s   3BGGc                   | dz  }t        |      }|j                  t        j                  g dt        j                               |j                          t        j                  t        |      d      5 }t        j                  |j                  d      d      }d d d        d   dk(  r|d	   d
k(  sJ |d   dk(  sJ y # 1 sw Y   &xY w)Nzhot.wav)g       @g       g        g      ?r   r      r   r   i  r   ir   )r   r   r   arrayr   r   r   r   r   r$   r%   )r(   r)   r*   r-   r.   s        r/   test_wav_recorder_clipsr4   0   s    9A
a.CIIbhh,BJJ?@IIK	3q64	 AmmALLO59 
!q6U?s1v///q6Q;; 
!	 s   6'CCc                 &   t         j                  dk(  sJ t         j                  J t         j                  d   t         j                  k(  sJ t	        d t         j                  D              sJ t	        d t         j                  D              sJ y )N"mlx-community/whisper-large-v3-mlxr   c              3  $   K   | ]  }d |v  
 yw)turboN .0rs     r/   	<genexpr>z,test_meeting_stt_defaults.<locals>.<genexpr>B        7%6w!|%6   c              3  $   K   | ]  }d |v  
 yw)smallNr9   r:   s     r/   r=   z,test_meeting_stt_defaults.<locals>.<genexpr>C   r>   r?   )vmMEETING_STT_MODELMEETING_STT_LANG_STT_FALLBACKSanyr9       r/   test_meeting_stt_defaultsrH   =   s|    #GGGG&&&Q2#7#77777R%6%677777R%6%67777rG   c                    g  G fdd      }| j                  t        d|       t        j                         \  }}d|v sJ g dk(  sJ y)zDlarge-v3 + turbo fail to load -> loader degrades to the small model.c                      e Zd Z fdZy)6test_load_meeting_stt_fallback.<locals>.FakeMeetingSTTc                Z    j                  |       d|vrt        | d      || _        y )NrA   z not in cache)appendRuntimeErrorrepo)selfrO   attemptss     r/   __init__z?test_load_meeting_stt_fallback.<locals>.FakeMeetingSTT.__init__K   s0    OOD!d""dV=#9::DIrG   N__name__
__module____qualname__rR   )rQ   s   r/   FakeMeetingSTTrK   J   s    	rG   rW   
MeetingSTTrA   )r6   z$mlx-community/whisper-large-v3-turbozmlx-community/whisper-small-mlxN)setattrrB   load_meeting_stt)monkeypatchrW   sttnamerQ   s       @r/   test_load_meeting_stt_fallbackr^   F   s[    H  L.9##%ICd??    rG   c                     G d d      }| j                  t        d|       	 t        j                          J d       # t        $ r Y y w xY w)Nc                      e Zd Zd Zy),test_load_meeting_stt_all_fail.<locals>.Boomc                    t        d      )Nzno model)rN   )rP   rO   s     r/   rR   z5test_load_meeting_stt_all_fail.<locals>.Boom.__init__]   s    z**rG   NrS   r9   rG   r/   Boomra   \   s    	+rG   rc   rX   z#should raise when every model fails)rY   rB   rZ   rN   )r[   rc   s     r/   test_load_meeting_stt_all_failrd   [   sN    + + L$/
;;;u s   > 	A
	A
c                    t        dd      } | j                  ddd       | j                  dd	d
       | j                         j                         dd  }|d   j	                  d      sJ |d   j	                  d      sJ | j                         j                  | j                   dk(  sJ | j                         j                  | j                   dk(  sJ | j                  j	                  d      sJ y )NonlinezQ3 syncmodetitlethemsecond      Y@tsAhmedfirstg      I@r   r   zAhmed: firstr   zthem: secondz	_room.wavz	_them.wavmeeting_)	r   add	full_text
splitlines
startswithroom_wav_pathr]   stemthem_wav_path)mliness     r/   'test_meeting_session_ordering_and_pathsr{   i   s    HI6AEE&(uE%EE'7tE$KKM$$&qr*E8~...8~...??!!xy%9999??!!xy%999966Z(((rG   c                      e Zd ZdZd Zy)rW   z~Transcribe returns a label derived from the audio's constant fill so a
    test can prove WHICH utterance produced WHICH line.c           	     N    dt        t        t        |d         dz               S )Nzsaid r   d   )introundfloat)rP   audios     r/   
transcribezFakeMeetingSTT.transcribe{   s'    s5uQx3!6789::rG   N)rT   rU   rV   __doc__r   r9   rG   r/   rW   rW   x   s    ;;rG   rW   c                      e Zd Zd Zd Zy)FakeTTSc                    g | _         y N)saidrP   s    r/   rR   zFakeTTS.__init__   s	    	rG   c                    | j                   j                  |       t        j                  dt        j                        S )N   r   )r   rM   r   zerosint16)rP   texts     r/   synthzFakeTTS.synth   s)    		xx**rG   N)rT   rU   rV   rR   r   r9   rG   r/   r   r      s    +rG   r   c                      e Zd Zd Zd Zy)FakeSpeakerc                     d| _         d| _        y )Nr   F)playedspeakingr   s    r/   rR   zFakeSpeaker.__init__   s    rG   c                .    | xj                   dz  c_         y )Nr   )r   )rP   r.   s     r/   playzFakeSpeaker.play   s    qrG   N)rT   rU   rV   rR   r   r9   rG   r/   r   r      s    rG   r   c                 V    t               } t               | _        t               | _        | S r   )r	   r   ttsr   speaker)apps    r/   _appr      s     
*CiCG-CKJrG   c                n    | j                  t        dd        d }t        j                   |              y )NrZ   c                     t               dfS )Nfake)rW   r9   rG   r/   <lambda>z;test_worker_transcribes_labels_and_orders.<locals>.<lambda>   s    9I68RrG   c                   K   t               } t        d      }t        j                  d      }|| _        t        j
                  | j                  ||            }| j                  dt        j                  ddt        j                        d	       | j                  d
t        j                  ddt        j                        d	       |j                  d        t        j                  |d       d {    |j                         sJ |j                         j                         dd  }|d   dk(  sJ |d   dk(  sJ y 7 Lw)Nrf   rh   
   maxsizerj      g?g      i@rm   ro   g?rl      )timeoutr   r   zAhmed: said 10r   zthem: said 90)r   r   asyncioQueue_meeting_stt_queuecreate_task_meeting_transcribe_worker_enqueue_meeting_audior   r   r   
put_nowaitwait_fordoners   rt   )r   sessionqworkerbodys        r/   goz5test_worker_transcribes_labels_and_orders.<locals>.go   s    f h/MM"%!"$$S%C%CGQ%OP""62773bjj+Ie"T""7BGGCrzz,Ju"U	Tvq111{{}}  "--/3Aw****Aw/))) 	2s   C2E4E5AE)rY   rB   r   runr[   r   s     r/   )test_worker_transcribes_labels_and_ordersr      s+    .0RS*  KKrG   c                 >    d } t        j                   |               y )Nc            	     "  K   t               } t        j                  d      | _        t	        d      D ]9  }| j                  dt        j                  ddt        j                        d       ; | j                  j                         dk(  sJ y w)	N   r   r   rj   r   g?      ?rm   )
r   r   r   r   ranger   r   r   r   qsize)r   _s     r/   r   z=test_enqueue_backlog_never_raises_and_is_wav_safe.<locals>.go   sp     f!(q!9rA&&vrwwsC/LQT&U %%++-222s   BBr   r   r   s    r/   1test_enqueue_backlog_never_raises_and_is_wav_safer      s    3 KKrG   c                     t               } t        d      | _        d | _        d | _        d | _        d | _        d | _        i fd}|| _        | fS )N	in_personr   c                   K   |d<   y w)Nwas_backlogr9   )ry   r   r   captureds      r/   fake_finalizez)_prep_stopping_app.<locals>.fake_finalize   s     "-   
)	r   r   meeting	_room_wav	_them_wav_remote_capture_task	_sysaudio_meeting_worker_task_finalize_meeting)r   r   r   s     @r/   _prep_stopping_appr      sW    
&C k2CKCMCM#CCM#CH.)C=rG   c                 >    d } t        j                   |               y )Nc                   K   t               \  } }t        j                  d      | _        | j	                          d {    t        j
                  d       d {    |d   du sJ t        d | j                  j                  D              sJ t        d | j                  j                  D              rJ y 7 {7 `w)Nx   r   {Gz?r   Fc              3  $   K   | ]  }d |v  
 yw)StoppedNr9   r;   ss     r/   r=   z@test_stop_no_backlog_says_stopped.<locals>.go.<locals>.<genexpr>   s     8<a9><r?   c              3  @   K   | ]  }d |j                         v   yw
processingNlowerr   s     r/   r=   z@test_stop_no_backlog_says_stopped.<locals>.go.<locals>.<genexpr>   s     G,Q|qwwy0,   )	r   r   r   r   _stop_meetingsleeprF   r   r   )r   r   s     r/   r   z-test_stop_no_backlog_says_stopped.<locals>.go   s     *,X!(s!;!!!mmD!!!&%///8377<<8888G#'',,GGGGG	 	"!s"   <B>B:B>B<AB><B>r   r   s    r/   !test_stop_no_backlog_says_stoppedr      s    H KKrG   c                 >    d } t        j                   |               y )Nc                 >  K   t               \  } }t        j                  d      }t        d      D ]8  }|j	                  dt        j                  dt
        j                        df       : || _        | j                          d {    t        j                  d       d {    |d   d	u sJ t        d
 | j                  j                  D              sJ t        |j                               D cg c]  }|j                          }}d |v sJ y 7 7 rc c}w w)Nr   r   r2   rj   r   r   r   r   Tc              3  @   K   | ]  }d |j                         v   ywr   r   r   s     r/   r=   zKtest_stop_with_backlog_says_still_processing.<locals>.go.<locals>.<genexpr>   s     Cl<1779,lr   )r   r   r   r   r   r   r   r   r   r   r   rF   r   r   r   
get_nowait)r   r   r   r   draineds        r/   r   z8test_stop_with_backlog_says_still_processing.<locals>.go   s     *,XMM#&qALL&"((3

";SAB !"!!!mmD!!!&$...CcggllCCCC+0+;<+;a1<<>+;<w 	"! =s7   BDDD#D$AD4D
DDDr   r   s    r/   ,test_stop_with_backlog_says_still_processingr      s     KKrG   c                D      fd}t        j                   |              y )Nc                   K   t               } t        dd      }|j                  ddd       i j                  |dfd	       fd
}|| _        | j                  |d d       d {    j                  d      du sJ | j                  j                         rJ | j                  j                         }d|j                         v sJ y 7 dw)Nr   zfinalize testrg   rj   hellor   rm   savec                 0     j                  dd      xs dS )Nr)   zx.md)
setdefault)saveds   r/   r   zDtest_finalize_saves_and_notifies_inbox.<locals>.go.<locals>.<lambda>   s    u/?/?V/L/VPV/VrG   c                   K   dd<   y w)NT
summarizedr9   )mmr   s    r/   
no_summaryzFtest_finalize_saves_and_notifies_inbox.<locals>.go.<locals>.no_summary   s     "&E,r   T)r   r   ready)r   r   rr   rY   _summarize_meetingr   getinboxemptyr   r   )r   ry   r   msgr   r[   s       @r/   r   z2test_finalize_saves_and_notifies_inbox.<locals>.go   s     f?C	fg#&Av'VW	'!+##At#>>>yy&$...99??$$$ii""$#))+%%% 	?s   A'C+C,A%Cr   r   s   ` r/   &test_finalize_saves_and_notifies_inboxr      s    & KKrG   )#r   
__future__r   r   osr   pathlibr   numpyr   environvoice.meetingr   rB   r   r   mainappmodr	   r0   r4   rH   r^   rd   r{   rW   r   r   r   r   r   r   r   r   r   r9   rG   r/   <module>r     s    #  	   

8   5  
1*8*	
); ;+ + ,	"rG   