o
    ij?                     @   s   d 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	dej
eje ddlmZ dd Zdd Zedkr@e  dS dS )	u  Persistent warm body worker — one process, model loaded ONCE, jobs over stdin.

Why a separate process (not just an in-process BodyEngine): the V3 face code and the
GVRM body code both use top-level package names `models` / `scripts` / `dataloaders`,
which collide in a single interpreter (whichever imports first wins → the other breaks
with e.g. `No module named 'models.vrm_lsm'`). Isolating the body engine in its own
process gives it its own module namespace (GVRM's), while the server keeps the V3 face
model warm in-process. Both stay warm.

Protocol (line-based JSON jobs, stdout sentinels):
  emits `@@READY@@` once the model is loaded,
  then for each stdin job emits
  `@@RESULT@@ {"ok":true,"frames":N,"vrma":...}` (or ok:false,error). Non-sentinel
  stdout/stderr lines are logs and are ignored by the parent.

Supported operations:
  generate      batch wav -> vrma (the original warm turn path)
  stream_start  allocate a stateful BodyStream
  stream_chunk  feed raw little-endian PCM16 and return new quaternion frames
  stream_end    flush the last short PCM remainder and release the stream

    python body_worker.py --ckpt ... --vqvae_dir ... --meanstd_dir ... --npz ... --proto_seed ...
    N)
BodyEnginec                  C   sZ  t  } | jddd | jddd | jddd | jddd | jdd d | jd	td
d | jdddd | jdd d | jddd |  }t|j|j|j|j	|j
d|j|j|j|jd
}i }tddd tjD ]>}| }|suqkzt|}|dd}|dkrd|d}n|dkr|j|d |d t|ddd\}}	|||d   d|t|	|d  d!}n|d"kr|d# }
|j|dd$|d%d&t|ddt|d'|jd( d)||
< d||
d*d+||
 jt|jd,d-}n|d.v r\|d# }
|
|vr	td/|
||
 }|dr||d  t |d0d1}|j!}|j"||d2kp3t#|d3d}|j$|dd4}d||
t|tt%|t&'|d5( d,d6}|d2kr[||
= n|d7krr|)|d# d  d||d# d8}nt*d9|td:tj+|d;d< dd W qk t,y } ztd:t+d=t-|d> dd W Y d }~qkd }~ww d S )?Nz--ckptT)requiredz--vqvae_dirz--meanstd_dirz--npzz--proto_seed)defaultz--steps   )typer   z--model_kind)tag3baser   )choicesr   z--codec_selectionz--continuous_decode
store_true)action)
ckpt	vqvae_dirmeanstd_dirnpz
proto_seedfingerssteps
model_kindcodec_selectioncontinuous_decodez	@@READY@@)flushopgenerateping)okr   wavemotionguidanceg      @)r   out_vrma)r   r   framesvrmastream_start	stream_idneutralstylegeneralemit_frames   )r$   r   r&      i>  vrm_normalized_humanoid)r   r   r"   fpssample_rater&   bonesrotation_space)stream_chunk
stream_endzunknown body stream pcm_b64 r/   r   )mapped_only   )r   r   r"   frame_startr   bodyr-   stream_cancel)r   r   r"   zunknown body worker op z@@RESULT@@ ),:)
separatorsF)r   error).argparseArgumentParseradd_argumentint
parse_argsr   r   r   r   r   r   r   r   r   r   printsysstdinstripjsonloadsgetgenerate_takefloat
write_vrma
new_streamPREemitliststream_bone_namesKeyErrorset_emotion_decode_pcm16frames_emittedpush_pcmboolbasis_to_humanoidlennproundtolistpop
ValueErrordumps	Exceptionstr)apaengstreamslinejobr   resultqTr"   streampcmr4   q_basise rl   body_worker.pymain$   s   






	


,rn   c                 C   sP   | s
t jdt jdS tj| dd}t|d rtdt j|ddt jd S )	Nr   )dtypeT)validate   z$PCM16 payload has an odd byte lengthz<i2g      @)	rW   zerosfloat32base64	b64decoderV   r[   
frombufferastype)valuerawrl   rl   rm   rQ   x   s   rQ   __main__)__doc__r;   rt   rD   osrA   numpyrW   pathinsertdirnameabspath__file__body_enginer   rn   rQ   __name__rl   rl   rl   rm   <module>   s    T	
