
    Pj                        d Z ddlZddlZddlZddlZddlZej                  j                  ej                  j                  e	            Z
ej                  j                  e
d      Zej                  j                  e
dd      Zej                  j                  e
dd      ZdZddlmZ dd	lmZ ddlZd
 ZddZd Zedk(  r e        yy)u  Render podcast scripts with VibeVoice-1.5B (GPU). Runs in the vibevoice venv.

Called by daily_podcast.sh AFTER the vLLM models are stopped — VibeVoice needs the
GPU memory they hold. Loads the model once, renders every script given.

Usage: tts_vibevoice.py script1.txt [script2.txt ...]
Each scriptN.txt needs a sibling scriptN.txt.meta.json with {"title", "description",
"mp3"}; output lands in episodes/<mp3> with a matching .json for the RSS builder.
    Nepisodesvoiceszvv_voice_ref.wavzvv_voice_ref2.wavzmicrosoft/VibeVoice-1.5B)*VibeVoiceForConditionalGenerationInference)VibeVoiceProcessorc                 :   t        j                  dd|       } t        j                  dd|       } t        j                  dd|       } t        j                  dd|       } t        j                  dd|       } | j                  dd	      } t        j                  d
d|       S )u   Deterministic backstop for notation the script model was told not to use.
    ASCII-only substitutions — never touches Lakota characters.z\[\d+(,\s*\d+)*\] zhttps?://\S+|arXiv:\S+z[*_#`]+z\$[^$]{1,80}\$z\b([A-Z])(\d)\bz\1 \2%z percentz	[ \t]{2,} )resubreplace)ss    podcast/tts_vibevoice.pyclean_for_speechr      s     	#R+A
("a0A
z2q!A
 "a(A
!8Q/A			#z"A66,Q''    c                 V   t        |      }|xs t        g}t        |      dkD  rt        j                  dt        j
                        }g }|j                  d      D ]  }|j                         s|j                  |      }	|	rI|j                  t        |	j                  d            |	j                  d      j                         g       p|r"|d   dxx   d|j                         z   z  cc<   |j                  d|j                         g        dj                  d |D              }
ne|j                  d      D cg c]3  }|j                         s|j                         j                  dd      5 }}dj                  d	 |D              }
 ||
g|gd
dd
      }|j                         D ci c]%  \  }}|t        |d      r|j!                  d      n|' }}}t#        j$                         5   | j&                  di |d d|j(                  ddidd}d d d        |j                  dd      }|j+                  j,                  d   |       dd l}t1        j2                  |      5 }|j5                         |j7                         }}|j9                  |j;                               |j;                         |j5                         z  }}d d d        |j=                         }|j?                  d       |jA                         |jC                         |jE                  d       t3        |d      jG                  tI        |jK                        |jM                         z                tO        jP                  |       S c c}w c c}}w # 1 sw Y   xxY w# 1 sw Y   xY w)N   z ^\s*speaker\s*([12])\s*:\s*(.*)$
   r
   c              3   2   K   | ]  \  }}d | d|   yw)zSpeaker z: N ).0nts      r   	<genexpr>zrender.<locals>.<genexpr>:   s!     ?A8A3b,?s   z

c              3   &   K   | ]	  }d |z     yw)zSpeaker 1: Nr   )r   ps     r   r   zrender.<locals>.<genexpr>?   s     :q*:s   Tpt)textvoice_samplespaddingreturn_tensorsreturn_attention_masktocudag?	do_sampleF)max_new_tokens	cfg_scale	tokenizergeneration_configverbose.mp3z.wavr   )output_path@      wbr   ))r   	VOICE_REFlenr   compileIsplitstripmatchappendintgroupjoinr   itemshasattrr%   torchno_gradgenerater*   
save_audiospeech_outputslameencwaveopengetframerategetnchannels
readframes
getnframesEncoderset_bit_rateset_in_sample_rateset_channelsset_qualitywritebytesencodeflushosremove)model	processorscriptmp3_path
voice_refsrefstagturnsrawmr    r   parasinputskvoutwav_pathrD   wratenchframesdurencs                            r   renderrl   (   s   f%F$)D
4y1} jj<bddC<<% 		/C99;		#Ac!''!*oqwwqz/?/?/ABCb	!ciik 11a-.		/ yy??? 8>||F7KY!qwwy""4-YYyy:E::TF4&#DPTVFGM||~Vtq!a'!T"2!$$v,9VFV	 Tenn Tv Tdc'0':':0;U/CUTT /H++A.HE	8	 WNN$ann&6cll1<<>2ALLNannFV4VW //
CR#0068H8H8Ms_`Oa4uSZZ%7#))+%EFGIIhJ' Z WT TW Ws+    N"N4*N5'N/A!NNN(c            
      $   t         j                  dd  D  cg c]G  } t        j                  j	                  |       s#t        j                  j	                  | dz         sF| I }} |st        d       y t        dt         dt         j                         t        j                  t              }t        j                  t        t        j                  dd	      }|j                          |D ]  } t        j                  t!        | dz               }t        j                  j#                  t$        |d
         }|j'                  dd      }t(        t*        gd |j-                  dd       }t/        ||t!        |       j1                         ||      }t        j&                  ||       t        j2                  |d   |d   dt!        |j'                  dd      d             d|v r|d   }	t        j                  j	                  |	      r't5        t        j                  t!        |	                  n	t5               }
|
j7                  |d          t        j2                  t9        |
      t!        |	d             t        d|d
    d| d        y c c} w )Nr   z
.meta.jsonz[vv-tts] no scripts to renderz[vv-tts] loading z...)filer&   sdpa)torch_dtype
device_mapattn_implementationmp3r-   z	.part.mp3speakers)rZ   titledescription)ru   rv   z.jsonrf   paper_idfeatured_pathz	[vv-tts] z (zs))sysargvrT   pathexistsprintMODELstderrr   from_pretrainedr   r?   bfloat16evaljsonloadrF   r<   EPISODESr   r2   
VOICE_REF2getrl   readdumpsetaddsorted)r   jobsrW   rV   metars   tmp_mp3r[   rj   fpfeats              r   mainr   T   s   xx|^!rww~~a'8RWW^^AP\L\=]A^D^-.	eWC
(szz:"2259I6FF5>>fRXZE	JJL 2yya,./0ggll8T%[1 ++fk2:&'?Q(?@UItAw||~w4P


7C 		DM$}:MNs{{673S9	;o&B/1ww~~b/A3tyyb*+suDHHT*%&IIfTlDSM2	$u+bR01!2 _s   $J"JJ__main__)N)__doc__rT   ry   r   rE   r?   r{   dirnameabspath__file__HEREr<   r   r2   r   r~   .vibevoice.modular.modeling_vibevoice_inferencer   'vibevoice.processor.vibevoice_processorr   r   r   rl   r   __name__r   r   r   <module>r      s      	wwrwwx0177<<j)GGLLx);<	WW\\$*=>
" G 
	()X2: zF r   