o
    Gaj(                     @   s   d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	Z	ej
ej
eZdd Zdd ZG dd dZG dd	 d	ZG d
d dejZG dd dejZG dd dejZG dd dejZedkrre  dS dS )    Nc                 C   s   t t| d  S )N   )base64	b64encodebytesdecode)	n_samples r   test_backend_stream.py
_pcm16_b64   s   r
   c                 C   sP   t jtjd|gtdt jt jd}|jr&| d|j d|j d|j	  dS dS )zNFace and body own conflicting top-level `models` packages; isolate face tests.z-cT)cwdtextstdoutstderrzisolated test failed (z
)
stdout:
z	
stderr:
N)

subprocessrunsys
executableHEREPIPE
returncodefailr   r   )testcasecoderesultr   r   r	   _run_isolated   s   
r   c                   @   s   e Zd Zdd ZdddZdS )	_FakeFacec                 C   s
   || _ d S N)owner)selfr   r   r   r	   __init__!      
z_FakeFace.__init__Nc                 C   s>   | j jt||||f | j jrtdtj|dftjdS )Nface failedr   )dtype)	r   
face_callsappendlen	fail_faceRuntimeErrornpzerosfloat32)r   pcmemotionn_framesframe_startr   r   r	   push_pcm$   s   z_FakeFace.push_pcmr   )__name__
__module____qualname__r   r/   r   r   r   r	   r       s    r   c                   @   sP   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd ZdS )_FakeInference)jawOpenmouthSmileLeftc                 C   s.   d| _ g | _g | _g | _d| _d| _d| _d S )Nr   F)frame_cursorr#   
body_callscancel_callsr&   fail_face_startfail_cancelr   r   r   r	   r   /   s   
z_FakeInference.__init__c                 C   s   t  S r   )objectr;   r   r   r	   get_face_model8   s   z_FakeInference.get_face_modelc                 C   s   | j rtdt| S )Nface start failed)r9   r'   r   )r   _modelscenario_idr   r   r	   
FaceStream;   s   z_FakeInference.FaceStreamc                 C   s    ||||f| _ dd|dgddS )N   i>  hipsvrm_normalized_humanoid)fpssample_rateemit_framesbonesrotation_space)started)r   	stream_idr,   guidancerG   r   r   r	   body_stream_start@   s   z _FakeInference.body_stream_startc                 C   s2   | j }d}|  j |7  _ |||g dgggddS )N   )        rO   rO   g      ?rD   )opr.   framesbodyrI   )r6   )r   rP   startrQ   r   r   r	   _packetJ   s   z_FakeInference._packetc                 C      | j d||f | dS )Nchunkr7   r$   rT   r   rK   pcm_b64r,   r   r   r	   body_stream_chunkV      
z _FakeInference.body_stream_chunkc                 C   rU   )NendrW   rX   r   r   r	   body_stream_endZ   r[   z_FakeInference.body_stream_endc                 C   s"   | j | | jrtdddiS )Ncancel failedokT)r8   r$   r:   r'   )r   rK   r   r   r	   body_stream_cancel^   s   z!_FakeInference.body_stream_cancelN)r0   r1   r2   ARKIT_52_NAMESr   r=   rA   rM   rT   rZ   r]   r`   r   r   r   r	   r3   ,   s    	
r3   c                   @   sD   e Zd Zdd Zdd Zdd Zdd Zd	d
 Zdd Zdd Z	dS )ServerStreamLifecycleTestsc                 C   sN   t j| _t | _| jt _t j t j  W d    d S 1 s w   Y  d S r   )server_infer	old_inferr3   fake_streams_lock_streamsclearr;   r   r   r	   setUpf   s   "z ServerStreamLifecycleTests.setUpc                 C   s<   t j t j  W d    n1 sw   Y  | jt _d S r   )rc   rg   rh   ri   re   rd   r;   r   r   r	   tearDownm   s   z#ServerStreamLifecycleTests.tearDownc                 C   s   t dd}| |d d | |d d t jdtddd	}| |d
 d | |d d | |d d dD ]}| || | || d q:| | jjd d | | jj	d d d S )NsneutralrG      rI   rD   rN   joy)r,   r.   r   r,   )queue_msbody_msface_msinference_ms)rV   rl   ro   )rN   ro   rN   r   )
rc   start_streamassertEqualstream_framesr
   assertInassertGreaterEqualrf   r7   r#   )r   metapackettiming_namer   r   r	   >test_rotation_contract_and_absolute_face_cursor_are_propagatedr   s   zYServerStreamLifecycleTests.test_rotation_contract_and_absolute_face_cursor_are_propagatedc                 C   s   t dd d| j_| td t jdddd W d    n1 s#w   Y  t j | dt j	 W d    n1 s=w   Y  | 
| jjdg d S )Nrl   rm   Tr!    )r\   )rc   ru   rf   r&   assertRaisesRegexr'   rw   rg   assertNotInrh   rv   r8   r;   r   r   r	   .test_face_failure_removes_both_sides_of_stream   s   zIServerStreamLifecycleTests.test_face_failure_removes_both_sides_of_streamc                 C   s   d| j _| td tdd W d    n1 sw   Y  tj | dtj W d    n1 s5w   Y  | 	| j j
dg d S )NTr>   rl   rm   )rf   r9   r   r'   rc   ru   rg   r   rh   rv   r8   r;   r   r   r	   8test_start_failure_cancels_body_and_releases_reserved_id   s   zSServerStreamLifecycleTests.test_start_failure_cancels_body_and_releases_reserved_idc                 C   s   t dd d| j_| td t d W d    n1 s w   Y  t j | dt j	 W d    d S 1 s;w   Y  d S )Nrl   rm   Tr^   )
rc   ru   rf   r:   r   r'   cancel_streamrg   r   rh   r;   r   r   r	   .test_cancel_failure_still_removes_server_state   s   "zIServerStreamLifecycleTests.test_cancel_failure_still_removes_server_statec                    s`  t   t  jj fdd}|j_tdd i t jfddd}|   j	dd	 t jfd
dd}|  t
d tj dtj W d    n1 s`w   Y  |    |jdd	 |jdd	 |  |  d d  tj dtj W d    d S 1 sw   Y  d S )Nc                     s(       jdd | i |S )Nr   timeout)set
assertTruewait)argskwargs)enteredoriginalreleaser   r   r	   blocking_chunk   s   zmServerStreamLifecycleTests.test_cancel_waits_for_inflight_chunk_before_removing_state.<locals>.blocking_chunkrl   rm   c                      s     dtdtdS )NrV   rl   rN   )
setdefaultrc   rw   r
   r   resultsr   r	   <lambda>   s    zgServerStreamLifecycleTests.test_cancel_waits_for_inflight_chunk_before_removing_state.<locals>.<lambda>)targetr   r   c                      s     dtdS )Ncancelrl   )r   rc   r   r   r   r   r	   r      s    g?r   	cancelled)	threadingEventrf   rZ   rc   ru   ThreadrS   r   r   timesleeprg   rx   rh   is_aliver   joinassertFalser   )r   r   chunk_threadcancel_threadr   )r   r   r   r   r   r	   :test_cancel_waits_for_inflight_chunk_before_removing_state   s<   


"zUServerStreamLifecycleTests.test_cancel_waits_for_inflight_chunk_before_removing_stateN)
r0   r1   r2   rj   rk   r}   r   r   r   r   r   r   r   r	   rb   e   s    	rb   c                   @      e Zd Zdd ZdS )FaceStreamAlignmentTestsc                 C      t | d d S )Na  
import numpy as np
import face_v3_infer as face

inferred_sample_counts = []
old_render = face.render_face_samples

def fake_render(wav, emotion, **kwargs):
    inferred_sample_counts.append(len(wav))
    n = 1 + len(wav) // 533
    values = np.arange(n, dtype=np.float32)[:, None] / 1000.0
    return np.repeat(values, 52, axis=1), n

face.render_face_samples = fake_render
try:
    stream = face.FaceStream(model_dev=None, scenario_id="s", blend=0)
    first = stream.push_pcm(
        np.zeros(13000, np.float32), "neutral", 24, frame_start=0)
    second = stream.push_pcm(
        np.zeros(12600, np.float32), "neutral", 24, frame_start=24)
finally:
    face.render_face_samples = old_render

# First request contains 200 future/pending samples, but body represented
# frames 0..23: exactly 12,800 samples.
assert inferred_sample_counts == [12800, 25600], inferred_sample_counts
np.testing.assert_allclose(first[:, 0], np.arange(24) / 1000.0)
np.testing.assert_allclose(second[:, 0], np.arange(24, 48) / 1000.0)
assert stream.frames_emitted == 48
r   r;   r   r   r	   @test_absolute_body_frame_slice_excludes_centered_extra_mel_frame      zYFaceStreamAlignmentTests.test_absolute_body_frame_slice_excludes_centered_extra_mel_frameN)r0   r1   r2   r   r   r   r   r	   r          r   c                   @   r   )ProductionWarmupTestsc                 C   r   )Na  
import base64
import numpy as np
import infer_turn as infer

old_request = infer._body_request
old_get_face = infer.get_face_model
old_face_stream = infer.FaceStream
old_warm = infer._STREAMING_WARM
jobs = []
face_calls = []

def fake_request(job):
    jobs.append(job)
    return {"ok": True}

class WarmFace:
    def __init__(self, model, scenario_id):
        pass

    def push_pcm(self, pcm, emotion, n_frames, frame_start=None):
        face_calls.append((len(pcm), n_frames, frame_start))
        return np.zeros((n_frames, 52), dtype=np.float32)

infer._body_request = fake_request
infer.get_face_model = lambda: object()
infer.FaceStream = WarmFace
infer._STREAMING_WARM = False
try:
    infer.warm_models()
finally:
    infer._body_request = old_request
    infer.get_face_model = old_get_face
    infer.FaceStream = old_face_stream
    infer._STREAMING_WARM = old_warm

start = next(job for job in jobs if job["op"] == "stream_start")
chunk = next(job for job in jobs if job["op"] == "stream_chunk")
assert start["emit_frames"] == 24, start
assert len(base64.b64decode(chunk["pcm_b64"])) // 2 == 12800
assert face_calls == [(12800, 24, 0)], face_calls
r   r;   r   r   r	   ,test_warmup_uses_24_frames_and_12800_samples   r   zBProductionWarmupTests.test_warmup_uses_24_frames_and_12800_samplesN)r0   r1   r2   r   r   r   r   r	   r      r   r   c                   @   r   )RealtimeSessionContractTestsc              
      s  i t jj}tjd}G dd d  fdd}|t j_dtjd< zt  }W |t j_|d u r9tjdd  n|tjd< n|t j_|d u rOtjdd  w |tjd< w d d }| |d	 d
 | dd |d D dg | 	d|d  | |d d d S )NOPENAI_API_KEYc                   @   s   e Zd Zdd Zdd ZdS )zlRealtimeSessionContractTests.test_emotion_tool_is_required_before_the_spoken_continuation.<locals>._Responsec                 S   s   d S r   r   r;   r   r   r	   raise_for_status  s   z}RealtimeSessionContractTests.test_emotion_tool_is_required_before_the_spoken_continuation.<locals>._Response.raise_for_statusc                 S   s
   dddS )Nephemeral-test-token{   )value
expires_atr   r;   r   r   r	   json  r    zqRealtimeSessionContractTests.test_emotion_tool_is_required_before_the_spoken_continuation.<locals>._Response.jsonN)r0   r1   r2   r   r   r   r   r   r	   	_Response  s    r   c                    s   | d< |d<   S )NurlrR   r   )r   headersr   r   r   capturedr   r	   	fake_post  s   zlRealtimeSessionContractTests.test_emotion_tool_is_required_before_the_spoken_continuation.<locals>.fake_postz	test-onlyrR   sessiontool_choicerequiredc                 S   s   g | ]}|d  qS )namer   ).0toolr   r   r	   
<listcomp>/  s    zmRealtimeSessionContractTests.test_emotion_tool_is_required_before_the_spoken_continuation.<locals>.<listcomp>toolsset_emotionu   음성을 생성하지 말고instructionsr   r   )
rc   requestspostosenvirongetmint_ephemeral_tokenpoprv   rx   )r   old_postold_keyr   r   r   r   r   r	   <test_emotion_tool_is_required_before_the_spoken_continuation  s,   

zYRealtimeSessionContractTests.test_emotion_tool_is_required_before_the_spoken_continuationN)r0   r1   r2   r   r   r   r   r	   r     r   r   __main__)r   r   r   r   r   r   unittestnumpyr(   rc   pathdirnameabspath__file__r   r
   r   r   r3   TestCaserb   r   r   r   r0   mainr   r   r   r	   <module>   s*    9[".$