
    8jĘ                    *   S r SSKJr  SSKrSSKrSSKrSSKrSSKJr  SSK	J
r
  SSKrSSKrSSKrSSKJrJrJrJr  SSKJr  SS	KJr  SS
KJr  SSKJrJr  SSKJr  SSKJ r J!r!  0 SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_r"/ SQr#Sr$S r%\RL                  " S!5      r'\" \(5      RS                  5       RT                  S"   r+\+S#-  S$-  S%-  r,\+S#-  S&-  r-\+S#-  S'-  r.S(r// S)Qr0\1" \05       V Vs0 s H  u  pX_M	     snn r2 S=     S>S* jjr3S?S+ jr4S@S, jr5SAS- jr6SBSCS. jjr7SDS/ jr8SES0 jr9SFS1 jr:   SG       SHS2 jjr;  SI     SJS3 jjr<   SK       SLS4 jjr=   SK       SMS5 jjr> SN   SOS6 jjr? SP   SQS7 jjr@ SR   SSS8 jjrASTS9 jrB                SU                                           SVS: jjrCS; rD\ES<:X  a  \R                  " \D" 5       5        ggs  snn f )Wu  Training data generation pipeline for V3 lipsync model.

Produces .npz triples per scenario:
    - audio_features: (T, 141) [mel or wav2vec features — TBD, simple mel for now]
    - conditioning: (T, 19) [16 emotion one-hot + 3 VAD]
    - target: (T, 52) [LAM lipsync + compiler expression merged by channel rules]

Usage:
    python -m scripts.compiler.data_pipeline --limit 10   # test run
    python -m scripts.compiler.data_pipeline              # full run
    )annotationsN)Path)List   )LAM_WEIGHTS_SHAREDLIPSYNC_ONLYEXPRESSION_ONLYSHARED_CHANNELS)compile_expressive_batch)apply_eye_motion)
LAMWrapper)apply_tremorsilence_gate_from_wav)	synth_all)build_synthetic_presetsload_presets_from_jsonneutraljoylaughter
excitement	agreement	gratitudesadnesscryingsulkapologystruggleangerrefusalsurpriseflustershy)r   r            皙?皙?data_pipeliner#   dataemotionzseed_train_final.jsonlv3_trainingaudio_preview   )r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   c                  #    UR                  SSS9  U  Vs/ s H  oUS   PM	     nnU  Vs/ s H  oUR                  S5      PM     nnU  Vs/ s H  oUR                  S5      PM     nn[        [        U 5      5       V	s/ s H  oU	S S3-  PM     n
n	[	        Xj4UUUUS.UD6I S	h  vN n[        X5       VVs/ s H  u  pU(       a  UOS	PM     snn$ s  snf s  snf s  snf s  sn	f  NAs  snnf 7f)
zDTTS all turns via selected backend, passing emotion+VAD for prosody.Tparentsexist_oktextr*   vad06d.mp3)backendconcurrencyemotionsvadsN)mkdirgetrangelenr   zip)turnsout_dirr6   r7   
tts_kwargsttextsr8   r9   ipathsok_flagspoks                 b/home/ubuntu/service/kemix-engine/package/face/animasync-face-v3/scripts/compiler/data_pipeline.pysynth_turns_batchrJ   K   s      MM$M. %&1vYE&*/0%Qi %H0"'(%QEE%L%D(/4SZ/@A/@!!C~%/@EA  H ,/u+?@+?%!A+?@@ '0(A AsP   C/CC/CC/C%C/=C"C/%C'&C/8C)C/)C/c           	        U R                  SU S   5      nU R                  S5      n/ n[        U S   5       GH  u  pVUR                  SS5      R                  5       (       d  UR                  S5        M>  Ub  X5   OUnUR                  SS	5      nX S
U SU S3-  n	U	R	                  5       (       a1  U	R                  5       R                  S:  a  UR                  U	5        M  [        UR                  U S
U S35      5      n
U
 Vs/ s H$  oR                  5       R                  S:  d  M"  UPM&     n
nUR                  U
(       a  U
S   OS5        GM     U$ s  snf )u#  Find pre-generated audio files for a scenario's turns.

Matches filename pattern: {scenario_id}_t{turn_idx}_{emotion}.mp3
Returns list aligned to scen['turns']; None if a turn's audio is missing
or the text is empty.

For per-turn dialogue splits, audio is named after the *original* scenario
and turn index, not the new pseudo-scenario id. expand_split_dialogues
sets `_source_scenario_id` and `_source_turn_indices` so we can reroute
lookup to the original (sid, ti) here.

SAFE: never calls TTS, never writes to audio_dir — read-only lookup.
_source_scenario_idscenario_id_source_turn_indicesr?   r2    Nr*   r   _t_r5   i  z_*.mp3r   )	r;   	enumeratestripappendexistsstatst_sizelistglob)scen	audio_dirsidsrc_tisrE   local_titurn	actual_tiemoexpectedmatchesms               rI   lookup_audio_for_scenariore   _   s;    ((($}*=
>Chh-.GE#DM2xx#))++LL)0)<G%(	hhy),b1SE>>??!8!84!?LL"y~~R	{&&ABC%Ag)9)9D)@1gA7WQZ5 3 L Bs   !E,Ec                    SSK nSSKnUR                  R                  SS5        SSKJn  SSKJnJnJ	nJ
n  [        R                  SU 35        UR                  US/S9nU" 5       n	U UU	UUUS	.$ )
uT  Lazy-load V2 ONNX session + feature extractor and pull the V2-dynamics
helpers out of abc_experiment.py. Lazy import because abc_experiment.py
imports `merge_lam_compiler` / `speech_gate` from THIS module — a
module-level import would cycle.

Returns a dict with keys: variant, sess, feat, run_v2, apply_v2_dynamics,
get_preset_envelope.
r   Nz-/dataset/text-to-face-se/LAM_Audio2Expression)AudioFeatureExtractor)ONNX_V2run_v2apply_v2_dynamicsget_preset_envelopezLoading V2 ONNX: CPUExecutionProvider)	providers)variantsessfeatri   rj   rk   )sysonnxruntimepathinsertdistillation.student_modelrg   scripts.compiler.abc_experimentrh   ri   rj   rk   LOGinfoInferenceSession)
rn   _sysortrg   rh   ri   rj   rk   ro   rp   s
             rI   _load_v2_helpersr|      s     IIQGH@  HH 	*+4J3KLD "D.2     c           	     H   / nU  H  nUR                  SS5      nUR                  S5      (       d  UR                  U5        M>  [        US   5       HI  u  pEUR                  SS5      R	                  5       (       d  M,  UR                  U SU 3UU/U/S.5        MK     M     U$ )ur  Expand each daily_* dialogue scenario into one pseudo-scenario per
non-empty turn (short monologue per turn).

Pseudo-scenario shape:
    scenario_id:          "{original_sid}_t{turn_idx}"  (drives .npz name
                                                         + tremor/eye seed)
    turns:                [original turn]                (single-turn —
                                                          no transitions)
    _source_scenario_id:  original sid                   (audio lookup)
    _source_turn_indices: [original turn_idx]            (audio lookup,
                                                          filenames carry
                                                          the original ti)

Rationale: the blendshape model only consumes (audio, VAD) → face at the
rendering stage, and contextual emotion learning already lives in
MicroAlbert (text + previous-turn context). So we drop the dialogue
structure for this dataset and emit each turn as a self-contained short
monologue. Long_/solo_ scenarios pass through unchanged — their multi-
turn structure is what teaches inter-emotion transitions.
rM   rO   daily_r?   r2   rP   )rM   rL   rN   r?   )r;   
startswithrT   rR   rS   )	scenariosoutsr\   tir_   s         rI   expand_split_dialoguesr      s    * CeeM2&~~h''JJqM!!G*-HB88FB'--//JJ"%b~'*)+	  .  Jr}   c                    [        X-  5      n[        R                  R                  XX4SS9n[        R                  " U5      R
                  nUR                  [        R                  5      $ )zCExtract mel features aligned to fps.

Returns (T, n_mels) float32.
i   )ysrn_mels
hop_lengthn_fft)	intlibrosafeaturemelspectrogrampower_to_dbTastypenpfloat32)wavr   fpsr   r   mellog_mels          rI   mel_featuresr      sZ    
 RXJ
//
(
(
V$ ) C !!#&((G>>"**%%r}   c                    [         R                  " US4[         R                  S9n[        R	                  U S5      nSUSS2U4'   [         R
                  " U[         R                  S9USS2SS24'   U$ )zD(T, 19) conditioning: 16-dim one-hot + 3 VAD, broadcast over frames.   dtyper         ?N   )r   zerosr   EMOTION_TO_IDXr;   asarray)r*   r3   r   condidxs        rI   build_conditioningr      s\    88QG2::.D


Wa
(CDCL::c4DBCLKr}   c                    SU SS2S4   -  SU SS2S4   -  -   SU SS2S4   -  -   SU SS2S4   -  -   n[         R                  " US-  S	S5      R                  [         R                  5      $ )
u   Compute per-frame speech activity [0, 1] from LAM mouth activity.

Per V3_IMPLEMENTATION_PLAN_v2 §3.4:
    activity = 1.2*jawOpen + 1.5*mouthClose + 1.0*mouthFunnel + 1.0*mouthPucker
Normalized via sigmoid-ish.
g333333?N         ?   r      %           )r   clipr   r   )lam_bsactivitys     rI   speech_gater      s     	fQUm
q"u
	
q"u
	 q"u
	  778c>3,33BJJ??r}   c                \   [         S-  nUSU-
  :  aH  SU-
  S:  a  USU-
  -  OSnSS[        R                  " U[        R                  -  5      -
  -  nSU-
  U -  $ USU-   :  a  gSU-
  nUS:  a  USU-   -
  U-  OSnSS[        R                  " U[        R                  -  5      -
  -  nXQ-  $ )um  Brow channel value over a crossfade routed through the neutral (0)
pose. Used when |delta| > BROW_SWING_DELTA so a sad↔anger inversion
doesn't slide linearly between extremes.

Same profile as abc_experiment.py:
    [0, 0.5−PAUSE/2]:  prev → 0 (cosine ramp-down)
    [0.5−PAUSE/2, 0.5+PAUSE/2]:  hold at 0
    [0.5+PAUSE/2, 1]:  0 → next (cosine ramp-up)
r#         ?r   r   r   )NEUTRAL_PAUSE_FRACTIONr   cospi)prev_vnext_vrB   
half_pauselocal_teaseddenoms          rI   _brow_pass_through_zeror      s     (!+J3-0:-=,B!sZ'(sRVVGbeeO445ev%%	
S:	z!6;ai1j()U2SsRVVGbeeO445~r}   c                V   S n[        U 5      n[        R                  " U[        R                  S9nU S   US'   SnSU-  n	[	        SU5       HX  n
U" X5      nX
   XzS-
     -
  U	-  nX-  SU-
  U-  -   nUnX#[        U5      -  -   nU" X5      nXU
   -  SU-
  XzS-
     -  -   Xz'   MZ     U$ )zOne-Euro adaptive low-pass. Peak-preserving smoother for expression
channels (not lipsync-critical). Same impl as abc_experiment.py.c                B    S[         R                  -  U-  U -  nX"S-   -  $ )N       @r   )r   r   )tecutoffrs      rI   sf_one_euro_filter.<locals>.sf
  s%    "%%K& 2%G}r}   r   r   r   r   r   )r=   r   r   r   r<   abs)signalr   
min_cutoffbetad_cutoffr   r   r   dx_prevr   rD   a_ddxdx_hatr   as                   rI   _one_euro_filterr     s    
 	FA
((1BJJ
'CAYCFG	sB1a[i#!e*$*S3Y'11S[00rNAY#'SQZ!77  Jr}   c                &   U R                  5       n[        [        [        5      [        [        5      S1-
  -  5      nU H  n[        USS2U4   XS9USS2U4'   M     [        R                  " USS5      R                  [        R                  5      $ )zDApply One-Euro filter to expression channels (not lipsync-critical).r   Nr   r   r   r   )
copysortedsetr	   r
   r   r   r   r   r   )targetr   r   result	smooth_chchs         rI   smooth_expression_channelsr     s}     [[]Fs?+s?/Crd/JKLI(24>Kq"u  7763$++BJJ77r}   c           	     n   [        U 5      nUS::  a  U R                  [        R                  SS9$ [        R                  " U[        R                  S9nU S   US'   [        SU5       HJ  n[        [        X   5      [        XS-
     5      -
  5      nXs:  a  UOUnXU   -  SU-
  XVS-
     -  -   XV'   ML     U$ )aJ  V2-style jitter-gate EMA. Small per-frame deltas get heavy smoothing
(alpha=jitter_alpha); deltas above `jitter_threshold` pass through with
light smoothing (alpha=base_alpha). Removes sub-threshold mouth jitter
without flattening real phoneme transitions.

Mirrors animasync-face-v2/pipeline_v2/smooth_v2.py::jitter_gate_smooth.
r   T)r   r   r   r   )r=   r   r   r   r   r<   r   float)	r   
base_alphajitter_alphajitter_thresholdr   r   rB   deltaalphas	            rI   _jitter_gate_smoothr   )  s     	FAAv}}RZZd}33
((1BJJ
'CAYCF1a[E&)$uVE]';;<#6
L"cEkSQZ%??  Jr}   c                   U R                  5       n[        [        [        5      S1-  5      nU H  n[	        USS2U4   UX#S9USS2U4'   M     [
        R                  " USS5      R                  [
        R                  5      $ )aO  Apply V2 jitter-gate smoothing to LIPSYNC_ONLY + jawOpen (ch 24).

The compiler+LAM teacher target carries sub-threshold high-frequency
noise in the mouth/jaw channels that V3 then learns and amplifies.
Smoothing the GT before training removes that noise floor while
preserving real phoneme onsets (which exceed the jitter threshold).
r   Nr   r   r   r   r   )	r   r   r   r   r   r   r   r   r   )r   r   r   r   r   lip_chr   s          rI   smooth_lipsync_channelsr   @  su     [[]FC%,-F+1b5Mj%
q"u 
 7763$++BJJ77r}   c                   [         R                  " U SS9R                  [         R                  5      nUS-  nSn[	        USS 5       GH  u  pgXW-  nX   S   nXS-      S   n	[        SXT-
  5      n
[        UR                  S   XT-   5      nX-
  nUS::  a  MP  [         Vs/ s H3  n[        [        X   5      [        X   5      -
  5      [        :  d  M1  UPM5     nn[        X5       Hh  nX-
  US-
  -  nSS[         R                  " U[         R                  -  5      -
  -  nSU-
  U-  UU	-  -   X?'   U H  n[        X   X   U5      X?U4'   M     Mj     GM     U$ s  snf )	zCosine-eased blend across turn boundaries, with brow pass-through-zero
on inverting (large-delta) brow channels. Mirrors abc_experiment.py.r   axisr#   Nr   r   r   )r   concatenater   r   rR   maxminshapeBROW_CHANNELSr   r   BROW_SWING_DELTAr<   r   r   r   )
comp_stackturn_lengthsfade_framesconcathalfcursorrD   Ti	prev_pose	next_pose
fade_startfade_endLr   brow_pass_channelsfrB   r   s                     rI   crossfade_turn_boundariesr   U  so    ^^JQ/66rzzBF!DF<,-M"%	sOA&	FM*
v||A6!6&
&25'%	*>>?BRR  	 
 z,AAE*A3BEE	!223Eu	1EI4EEFI( 7M9=!!"u )	 - .* M
s    0EEc                   [         R                  " UR                  5        Vs/ s H  o3S   PM	     sn[         R                  S9n[         R                  " UR                  5        Vs/ s H  o3S   PM	     sn[         R                  S9nU R                  S   n[         R
                  " US4[         R                  S9nSSUS-  -  -  n[        U5       HZ  n	[         R                  " X@U	   -
  S-  S	S
9n
[         R                  " U
* U-  5      nUR                  5       nUS:  a  X-  nX-  Xy'   M\     [         R                  " USS5      R                  [         R                  5      $ s  snf s  snf )u{   RBF over ALL preset anchors based on VAD distance — cross-emotion blend.
Matches abc_experiment.py.cross_emotion_compile.r3   r   bsr   4   r   r   r#   r   r   g&.>r   )r   r   valuesr   r   r   r<   sumexpr   r   )r9   presetssigmarG   anchor_vads	anchor_bsr   r   	inv_2sig2rB   d2wr   s                rI   cross_emotion_compiler  t  s+    **0@A0@1h0@A#%::/K

W^^-=>-=dG-=>!#-I

1A
((Ar7"**
-CsUaZ'(I1XVV[7*q0q9FFB3?#EEGt8FA  773S!((44 B>s   E&'E+c                   [        U 5      nUS::  d  US:  a  S/U-  $ U  Vs/ s H  n[        R                  US5      PM     nn[        [        U5      5      S:X  a  S/U-  $ SUS-   -  nS/U-  nSnXr:  aH  UnX:  a   XH   XG   :X  a  US-  nX:  a  XH   XG   :X  a  M  [	        Xx5       H	  n	X-
  Xi'   M     UnXr:  a  MH  U V
s/ s H  n
U
S:X  a  UO	U
S:X  a  UOSPM     sn
$ s  snf s  sn
f )u  For each turn, compute the magnitude scale based on emotion-family
persistence across adjacent turns. Single-turn scenarios bypass entirely
(returned scales are all 1.0). Same rule as abc_experiment.py:
   persistence == 1 → fleeting_scale
   persistence == 2 → midpoint(fleeting_scale, 1.0)
   persistence >= 3 → 1.0
All-same-base monologues also bypass (sustained = full strength).
r   r   r   r   r   r#   )r=   SUB_TO_BASEr;   r   r<   )turn_emotionsfleeting_scalenebasespairedrun_lenrD   jkrG   s              rI   compute_persistence_scalesr    s    	MAAv3&uqy4ABMq[__Q	*MEB
3u:!uqyNS()FcAgG	A
%eEH,FA eEH,qAGJ  % A q&avSA  Cs    C"C'c                   U R                   S   n[        R                  " U 5      n[         H  nU SS2U4   USS2U4'   M     [         H  nUSS2U4   USS2U4'   M     [
         H  n[        U   nUS:X  a=  SUSS2U4   S-  SU-
  -  -   nU SS2U4   U-  USS2U4   SU-
  -  S-  -   USS2U4'   MO  X`SS2U4   -  SU-
  USS2U4   -  -   nX(-  SU-
  USS2U4   -  -   USS2U4'   M     USS2S4   USS2S	4   -   S-  n	USS2S
4==   SU	S-  -
  -  ss'   USS2S4==   SU	S-  -
  -  ss'   USS2S4==   SU	S-  -
  -  ss'   [        R                  " USS5      R                  [        R                  5      $ )z=Merge LAM lipsync + compiler expression per V3 channel rules.r   Nr   r   r   r   333333?+   ,   r   皙?   g?r-   r   )
r   r   
zeros_liker   r	   r
   r   r   r   r   )
lamcompgater   r   r   r  emotion_gainblended_activesmiles
             rI   merge_lam_compilerr&    s   		!A
--
C BZArE
  !R%[ArE
  r"8aes!2cDj!AALQUl2T!R%[AH5MPS5SSC2JQU^q1uQU.CCN.!d(d1b5k1IIC2J  BZ#ae*$+E2J1us{?#J2J1us{?#J2J1us{?#J773S!((44r}   c                   / n[        U S   5       GH  u  nnUS   R                  5       (       d  M!  UU   nUb  UR                  5       (       d  M@  [        R                  " [        U5      SSS9u  nn[        U5      S:  a  Ms  UR                  U5      nUR                  S   n[        UU[        S	9nUR                  S   U:  a  USU nOVUR                  S   U:  aC  UUR                  S   -
  n[        R                  " U[        R                  " US
S US45      /SS9n[        U5      n[        UUU[        S9n Sn!Ub  US   " US   US   UUS   5      n!U!R                  S   U:  a  U!SU n!OVU!R                  S   U:  aC  UU!R                  S   -
  n[        R                  " U![        R                  " U!S
S US45      /SS9n!UR!                  UUS   [#        US   5      UUUUU U!S.	5        GM     U(       d  g[%        U V"s/ s H  n"U"S   PM
     sn"US9n#US:  a  [        U5      S:  a  ['        U5      n$['        U	5      n%[        R(                  " US   S   [        R*                  S9n&USS  HX  n"[        R(                  " U"S   [        R*                  S9n'U$U'-  SU$-
  U&-  -   n(U%U&-  SU%-
  U'-  -   n&U(R-                  5       U"S'   MZ     [        R                  " U V"s/ s HC  n"[        R                  " [        R.                  " U"S   [        R*                  S9U"S   S45      PME     sn"SS9n)[1        S U 5       5      n*[        R2                  " U*[        [4        5      4[        R*                  S9n+Sn,U H3  n"[6        R9                  U"S   S5      n-SU+U,U,U"S   -   2U-4'   U,U"S   -  n,M5     U
S:  aa  [        U5      S:  aR  SSKJn.  U." U)U
SSS9R?                  [        R*                  5      n)U." U+U
SSS9R?                  [        R*                  5      n+/ n// / n1n0Sn2/ n3[A        UU#5       GHt  u  n"n4U"S   nU"S   n5U)U2U2U-    n6U+U2U2U-    n7U2U-  n2[C        U5/U-  U6UUS9n8US:  aA  [E        U6UUS9n9['        U5      n:SU:-
  U8-  U:U9-  -   R?                  [        R*                  5      n8U4S:  a"  U8U4-  R?                  [        R*                  5      n8Ub4  U"R9                  S 5      b"  US!   " U5U5      u  n;n<US"   " U8U"S    US#   U;U<S$9n8U/R!                  U85        U3R!                  U5        U0R!                  U"S%   5        [        R                  " U7U6R?                  [        R*                  5      /S
S9R?                  [        R*                  5      n=U1R!                  U=5        GMw     [        U35      S&:  n>U>(       a  UO[G        US'5      n?[        U/5      S:  a  [I        U/U3U?S(9n@OU/S   n@[        R                  " U V"s/ s H  n"U"S)   PM
     sn"SS9nA[        R                  " U V"s/ s H  n"U"S*   PM
     sn"SS9nB[K        WAW@UB5      nCU>(       a  S+OS,nD[M        WCUDS-S.9nCU(       a  [O        WCUUUS/9nC[Q        WCU S0   [        US19nCUS:  a\  US:  aV  [        R                  " U V"s/ s H  n"U"S2   PM
     sn"SS9R?                  [        R*                  5      nE[S        WCUEU S0   UUS39nC[        RT                  " U[        R                  " U0SS9[        R                  " U1SS9WCS49  gs  sn"f s  sn"f s  sn"f s  sn"f s  sn"f )5u  Two-pass scenario → .npz, mirroring abc_experiment.py's variant-C
pipeline (compiler + LAM, no V2 ONNX). Defaults match the canonical
lock-in (damp 0.65, xemo 0.2, blink 3.5, fade 96, σ=30, γ=0.3) — running
with no flag overrides produces training targets that match what the
viewer shows for _d65x20 scenarios.

Pass 1: collect per-turn audio + LAM + speech gate + raw VAD.
Persistence rule: pose-level scale per turn (multi-turn only).
Causal VAD damping: pull each turn's VAD toward running mean of past.
Cross-turn VAD smoothing: σ-frame Gaussian over per-frame VAD trajectory.
Pass 2: per-turn compile (within-emotion + cross-emotion blend, then
persistence damp).
Crossfade between turn boundaries.
Merge LAM, smooth expression channels, apply eye_motion.
r?   r2   N>  T)r   monog      @r   )r   r   r   r   r   )r   ri   ro   rp   r*   r3   )	turn_idxr*   r3   r   r   r   r"  silence_gatev2_bsF)r  r   r   r   c              3  *   #    U  H	  oS    v   M     g7f)r   N ).0cs     rI   	<genexpr>#process_scenario.<locals>.<genexpr>=  s     ,)QC&)s   )gaussian_filter1dnearest)r  r   mode)r8   r9   r  parametric_overlay_intensityr   )r  r,  rk   rj   rn   )envelope_loenvelope_hir   r$      )r   r   r"  r  r   r   r   r   rM   )seed_strr   blink_interval_sr+  )r+  rM   ampr  )audior   r   )+rR   rS   rU   r   loadstrr=   infer_audior   r   FPSr   r   tiler   r   rT   rX   r  r   arrayr   tolistr   r  r   EMOTION_LABELSr   r;   scipy.ndimager3  r   r>   r   r  r   r   r&  r   r   r   r   savez_compressed)Fscenarioaudio_pathsr   r  out_pathpersistence_dampingcross_emotion_weightcross_emotion_sigmavad_damp_gammavad_damp_betavad_smooth_sigmar   r;  option_e_intensity
tremor_amptremor_sigma
v2_helperslipsync_smoothlipsync_smooth_alphalipsync_smooth_jitter_alphalipsync_smooth_threshold	collectedr*  r_   
audio_pathr   r   r   r   r   padr"  sgater,  r0  persist_scales   γ   βrunning_meanrawdampedall_vadsn_totalall_emos_c_emor   r3  r   audio_featscondsr   r   psra   	vad_slice	emo_slicecomp_bsxemor  env_loenv_hicond_per_frameis_monologuefade_for_thiscomp_catlam_catgate_catr   r   	sgate_catsF                                                                         rI   process_scenariorw    s   N I#HW$56$F|!!## *
Z%6%6%8%8,,s:5tDRs8k!,LLO323/99Q<!bq'CYYq\Aciil"C..#rwws23x#q'B!C!LC6" &c2qc: !x(6"Jv$6T)_E {{1~!bq	Q!#%++a.(BGGE"#Ja9: 	 IU$!

 
	I 7^  0()y!9y)*N c)nq0>"=!xx	!U 32::F12A((1U82::6C#Xr\ 99F,bC/??L}}AeH	  ~~A 	

1U82::63D H ,),,Gxx#n"56bjjIHF  9q1033',-!C&  !I 23$,19

&
 	 %,19

&
 	
 JRKFLY/2cF	lVFQJ/	VFQJ/	!*UQY);	
  #%(G0CED*+Aa7*QX5==bjjIG8|++BJJ7G !aeeGn&@'(=>sGLNFF !457Z	%:"G
 	'"A1U8$
 	((45B

&
 	 	^$U 0Z |$)L#/KSa5HM
:,Z:GI a= nn9=9aak9=AFG~~)<)Qqy)<1EH8<F %#J':CPF
 (+45	
 -()	F CL3.NN(12	1Q~	2

&
 	 " /
 nn[q1^^E*	 e 	* f ><< 3s   \)&A
\.\3+\8)\=c            
       ^#    [         R                  " 5       n U R                  S[        [        S9  U R                  S[        [
        S9  U R                  S[        [        SS9  U R                  S[        SS	S9  U R                  S
[        [        S-  SS9  U R                  SS S9  U R                  SSSS9  U R                  SSSS9  U R                  S[        SSS9  U R                  S[        SSS9  U R                  S[        SSS9  U R                  S [        S!S"S9  U R                  S#[        S$S%S9  U R                  S&[        S'S(S9  U R                  S)[        S*S+S9  U R                  S,[        S-S.S9  U R                  S/[        S0S1S9  U R                  S2[        S3S4S9  U R                  S5[        S6S7S9  U R                  S8SS9S9  U R                  S:SS;S9  U R                  S<[        S=S>S9  U R                  S?[        S@SAS9  U R                  SB[        SCSDS9  U R                  SE/ SFQSGSHSI9  U R                  5       nUR                  (       a  SJUl        [        R                  " [        R                  SKSL9  UR                   R#                  SMSMSN9  UR$                  R'                  5       (       d  [)        SOUR$                   35      e[*        R-                  SPUR$                   35        UR.                  (       aW  UR.                  R'                  5       (       a8  [*        R-                  SQUR.                   35        [1        UR.                  5      nO[*        R-                  SR5        [3        5       n[*        R-                  SS[5        U5       ST35        / nUR6                  R9                  5        nU H(  nUR;                  [<        R>                  " U5      5        M*     S S S 5        [*        R-                  SU[5        U5       SV35        UR@                  RC                  5       RE                  5       nU(       a  USW;  a  [G        SX URI                  SY5       5       5      nURJ                  (       a1  [M        SZ U 5       5      (       d  US[-   n[*        R-                  S\5        [5        U5      nU V	s/ s H-  n	U	RO                  S]S^5      RQ                  U5      (       d  M+  U	PM/     nn	[*        R-                  S_U S`U Sa[5        U5       Sb35        URJ                  (       aP  [5        U5      n[S        U5      n[U        Sc U 5       5      n
[*        R-                  SdU Sa[5        U5       SeU
 Sf35        URV                  (       a1  US URV                   n[*        R-                  Sg[5        U5       Sb35        / nSnU HK  m[Y        TUR$                  5      nUR;                  U5        U[U        U4Sh j[[        U5       5       5      -  nMM     [U        Si U 5       5      nX-
  n[*        R-                  SjU SkU SlU Sm35        US:X  a  [)        Sn5      e[*        R-                  So5        []        UR^                  Sp9nS nUR`                  Sq:w  a8  [c        UR`                  5      n[*        R-                  SrUR`                   35        O[*        R-                  Ss5        SStK2J2n  Sn[[        U" USuSv95       GH  u  nmUR                   TS]    Sw3-  nUR'                  5       (       a  USx-  nM8  [g        TUU   UUU40 SyURh                  _SzURj                  _S{URl                  _S|URn                  _S}URp                  _S~URr                  _SURt                  _SURv                  _SURx                  _SUR                  _SURz                  _SU_SUR|                  _SUR~                  _SUR                  _SUR                  _6nU(       d  GM  USx-  nGM!     [*        R-                  SU Sk[5        U5       S35        [*        R-                  SUR                    35        g ! , (       d  f       GN~= fs  sn	f 7f)Nz--scenarios)typedefaultz--outputz--audio_dirz5Directory with pre-generated audio (read-only lookup))ry  rz  helpz--limitr   z0 = allz--presets_jsonzexpression_presets.jsonzUser-authored preset JSON. Defaults to <project_root>/expression_presets.json (the same file abc_experiment.py uses). Falls back to synthetic bootstrap if the file doesn't exist.z--device)rz  z--filter-prefixzlong_,solo_zComma-separated scenario_id prefixes to keep. Default 'long_,solo_' (monologues + single-turn). Use 'all' or '' to disable filtering and process every scenario. When --split-dialogues is set, 'daily_' is auto-added if missing.)rz  r{  z--split-dialogues
store_trueu  Expand each daily_* dialogue into one .npz per turn (short monologue per turn). Audio lookup is rerouted to the original (sid, turn_idx). Dialogue context learning is left to MicroAlbert; this pipeline only consumes (audio, VAD) → face at the render stage.)actionr{  z--persistence-damping?ziPose-level scale for fleeting (multi-turn isolated) emotions. Single-turn scenarios bypass. Default 0.65.z--cross-emotion-weightr'   z_Weight for cross-emotion VAD-distance blend (0=pure within-emotion, 1=pure cross). Default 0.2.z--cross-emotion-sigmar&   u?   Gaussian σ for cross-emotion VAD-distance kernel. Default 0.4.z--vad-damp-gammar  u#   Causal VAD damping γ. Default 0.3.z--vad-damp-betaffffff?u#   Causal VAD damping β. Default 0.7.z--vad-smooth-sigma      >@u<   Cross-turn VAD trajectory Gaussian σ in frames. Default 30.z--fade-frames`   z>Crossfade duration at turn boundaries (monologue). Default 96.z--blink-interval      @z3Mean seconds between blinks (Poisson). Default 3.5.z--option-e-intensityr   uC   α scalar for Option E parametric mouth/cheek overlay. Default 1.0.z--tremor-ampy&1?zcBrow + eyeSquint tremor amplitude. Default 0.014 (matches viewer runtime tremor). Set 0 to disable.z--tremor-sigmar   uR   Gaussian σ for tremor noise smoothing (frames). Default 1.5 → ~2.2 Hz dominant.z--no-tremorz/Disable tremor baking entirely (clean targets).z--lipsync-smoothzApply V2-style jitter-gate EMA to LIPSYNC_ONLY + jawOpen channels of the teacher target before saving. Removes sub-threshold mouth noise V3 would otherwise learn. Mirrors animasync-face-v2/pipeline_v2/smooth_v2.py.z--lipsync-smooth-alpha333333?z8EMA alpha for above-threshold frame deltas. Default 0.6.z--lipsync-smooth-jitter-alpha皙?zWEMA alpha for sub-threshold (jitter) frame deltas. Lower = more smoothing. Default 0.1.z--lipsync-smooth-thresholdQ?u]   Frame-delta cutoff: |Δ|>threshold → real motion, |Δ|<=threshold → jitter. Default 0.03.z	--variant)ABCr  uy  V2-dynamics teacher variant. C = compiler only (no V2). A = strict V2 mask (brows + cheek/nose squint + eyeSquint). B = tiered V2 mask: A's channels PLUS mouth smile/frown, eye wide, mouth dimple at α=0.25. Default B — V3 learns to reproduce V2's prosody-driven motion from (audio, VAD) alone. V2 ONNX is loaded only for A/B (data generation only; not used at V3 inference).)choicesrz  r{  r   z&%(asctime)s %(levelname)s: %(message)s)levelformatTr/   zAudio dir not found: zAudio source (read-only): zLoading user presets from z>Using synthetic preset bootstrap (parametric layer on anchors)u     → z presetszLoaded z scenarios (pre-filter))all*c              3  n   #    U  H+  oR                  5       (       d  M  UR                  5       v   M-     g 7f)N)rS   r/  rG   s     rI   r1  main.<locals>.<genexpr>%  s"     O,AqWWY,As   55,c              3  B   #    U  H  oR                  S 5      v   M     g7f)dailyN)r   r  s     rI   r1  r  &  s     +T8aLL,A,A8s   )r   z;--split-dialogues set: auto-added 'daily_' to filter prefixrM   rO   zFilter prefixes=z: u    → z
 scenariosc              3  T   #    U  H  oR                  S 5      (       d  M  Sv   M      g7f)rL   r   N)r;   r/  r   s     rI   r1  r  6  s     KAee4I.Jaas   (	(z--split-dialogues: z scenarios (z  per-turn splits from dialogues)z--limit applied: c              3     >#    U  H;  u  pUb  M
  TS   U   R                  SS5      R                  5       (       d  M7  Sv   M=     g 7f)Nr?   r2   rO   r   r;   rS   )r/  r   rG   rZ   s      rI   r1  r  D  sF      
+%" !']2.2262>DDF A+s   	A)A	Ac              3  L   #    U  H  n[        S  US    5       5      v   M     g7f)c              3  r   #    U  H-  oR                  S S5      R                  5       (       d  M)  Sv   M/     g7f)r2   rO   r   Nr  )r/  rB   s     rI   r1  !main.<locals>.<genexpr>.<genexpr>I  s&     ?z!UU62%6%<%<%>AAzs   (7	7r?   N)r  r  s     rI   r1  r  H  s)      A 	?qz???s   "$zAudio lookup: /z turns have audio (u)    missing — those turns will be skipped)z3No audio found for any scenario. Check --audio_dir.zLoading LAM model...)devicer  u   V2 teacher ENABLED — variant=z6V2 teacher DISABLED (variant=C, compiler-only targets))tqdmzProcess scenarios)descz.npzr   rK  rL  rM  rN  rO  rP  r   r;  rQ  rR  rS  rT  rU  rV  rW  rX  zDone. z" scenarios successfully processed.zOutput: )BargparseArgumentParseradd_argumentr   	SCENARIOS
OUTPUT_DIR	AUDIO_DIRr   PROJECT_ROOTr   
parse_args	no_tremorrR  loggingbasicConfigINFOoutputr:   r[   rU   
SystemExitrw   rx   presets_jsonr   r   r=   r   openrT   jsonloadsfilter_prefixrS   lowertuplesplitsplit_dialoguesanyr;   r   r   r  limitre   rR   r   r  rn   r|   r  rw  rK  rL  rM  rN  rO  rP  r   blink_intervalrQ  rS  rU  rV  rW  rX  )apargsr  r   r   line
prefix_strprefixesbeforer   n_splitscenario_audio_pathsmissing_totalrE   total_turnsfound_turnsr   rT  r  successsirJ  rH   rZ   s                          @rI   mainr    s    		 	 	"BOOMiO@OOJT:O>OOMiP  ROOICOCOO$4(+DDJ  K OOJO-OO%}]  ^
 OO'O  P OO+%Q  R OO,5#O  P OO+%Z  \OO&UC>  @OO%E3>  @OO(udW  YOOO#rY  [OO&UCN  POO*^  `OONN  O OO$5#=  > OOM,J  LOO&|V  W
 OO,5#S  UOO3%@  A OO0udE  F OOK#U  V ==?D~~gll3[\KKdT2 >>  ""00@ABBHH)$..)9:; T..5577-d.?.?-@AB():):;QR)+HHvc'l^8,- I				!DTZZ-.  
 HHws9~&&=>? ##))+113Jj4OJ,<,<S,AOO+T8+T(T(T+-HHHRSY ) G	1mR0;;HE 		 G#H:RxuS^<LJWX Y*95	KKK&vheC	N3C DI=? 	@ zzl

+	$S^$4J?@ M)$?##E* 
$U+
 
 	
    K -KHH~k]!K= 9HJ KaNOO HH#$
DKK
(C J||s%dll3
24<<.ABIJ Gd93FGHD;;D$7#8!==??qLG&r*C(
 $ 8 8
 "&!:!:
 !% 8 8	

  ..
 ,,
 "22
 ((
 "00
  $66
 
 **
 "
  ..
 "&!:!:
  )-(H(H!
" &*%B%B#
& 2qLG3 I6 HHvgYaI//QRSHHx}%&C 
	Gs9   N4a47/a&Ca47*a/%a/+La4Aa4
a,'a4__main__)
elevenlabsr%   )
r?   
List[dict]r@   r   r6   r?  r7   r   return
List[Path])rZ   dictr[   r   r  r  )rn   r?  )r   r  r  r  )r(  r-   P   )
r   
np.ndarrayr   r   r   r   r   r   r  r  )r*   r?  r3   List[float]r   r   r  r  )r   r  r  r  )r   r   r   r   rB   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  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  r  )r&   )r9   r  r  r  r  r   r  r  )r~  )r  z	List[str]r  r   r  r  )r   r  r!  r  r"  r  r  r  )r~  r'   r&   r  r  r  r  r  r   r  r   NFr  r  r  ),rH  r  rI  r  r   r   r  r  rJ  r   rK  r   rL  r   rM  r   rN  r   rO  r   rP  r   r   r   r;  r   rQ  r   rR  r   rS  r   rT  r  rU  boolrV  r   rW  r   rX  r   r  r  )G__doc__
__future__r   r  asyncior  r  pathlibr   typingr   r   numpyr   torch	constantsr   r   r	   r
   
expressiver   
eye_motionr   lam_wrapperr   tremorr   r   ttsr   utilsr   r   r  r   r   r   	getLoggerrw   __file__resolver0   r  r  r  r  rA  rE  rR   r   rJ   re   r|   r   r   r   r   r   r   r   r   r   r   r  r  r&  rw  r  __name__run)rD   r  s   00rI   <module>r     s^  
 #           1 ( # 7  By	5e%15  $U y	 #I	 06y	
 y
 %i W   
 &z 49*    (H~%%'//26!I-0HH	F"]2
 6!O3	
 $-^#<=#<41!$#<= NOA&)AGJA.8A( F:$N
&@"0 7;<?'*!&49$/92 47-0	8+0	8%*	85?	8 -0.126$)&+ +0 <F0 14256:8(-8*/8 /48 @J8, 24+.8B@ *-5!&51;5, 8</4@K@5L "&"%!$"! # "%),&*+nnn 
n 	n
 n n  n n n n n n n n n  !n" #n$ %n&  'n( "')n* $+n, 
-nbD'N zKK s >s    H