Ë
    qE«jâ+  ã                   ó.  — 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ddlmZ d\  Z	Z
Zddddd	d
dœZd
Z ee«      j                  «       j                   d   dz  dz  dz  dz  ZdgZdgZddgZd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zedk(  r e«        yy) a  
Arma el video de marketing (voz TTS + Ken Burns sobre capturas + textos en
pantalla + logo + musica opcional) a partir de un guion.json y las capturas
ya tomadas por el agente `video_marketing_capturas`.

No quema subtitulos: ese paso lo hace el agente/script existente
`tools/subtitulos/generar_video_subtitulado.py` sobre el resultado de este
script.

Uso:
  python generar_video_marketing.py <carpeta_tema>
  python generar_video_marketing.py <carpeta_tema> --musica musica.mp3
  python generar_video_marketing.py <carpeta_tema> --voz shimmer

Espera en <carpeta_tema>:
  guion.json                 - ver formato mas abajo (lo escribe video_marketing_guion)
  capturas/escena_NN.png     - una imagen por escena que la tenga (video_marketing_capturas)

Formato de guion.json (escenas, en orden):
  {
    "texto_voz": "...",          # obligatorio, lo que dice la voz en off
    "texto_pantalla": "...",     # opcional, titular que se ve en pantalla
    "captura": "capturas/escena_02.png",  # opcional, imagen de fondo (si no hay, fondo de color)
    "fondo_color": "#0f766e",    # opcional, usado solo si no hay "captura"
    "logo": true                # opcional, agrega el logo grande centrado (para el cierre)
  }

Salida: video_borrador.mp4 (1080x1920, 9:16) en la carpeta del tema.
é    N)ÚPath)i8  i€  é   z#2563ebz#10b981z#f59e0bz#ef4444z#06b6d4z#0f766e)ÚprimaryÚsuccessÚwarningÚdangerÚinfoÚtealé   ÚpublicÚimagesÚimgzlogo.pngz�C:\Users\larza\AppData\Local\Microsoft\WinGet\Packages\Gyan.FFmpeg_Microsoft.Winget.Source_8wekyb3d8bbwe\ffmpeg-8.1.2-full_build\bin\ffmpeg.exez�C:\Users\larza\AppData\Local\Microsoft\WinGet\Packages\Gyan.FFmpeg_Microsoft.Winget.Source_8wekyb3d8bbwe\ffmpeg-8.1.2-full_build\bin\ffprobe.exezC:\Windows\Fonts\arialbd.ttfzC:\Windows\Fonts\arial.ttfc                 óž   — t        j                  | «      }|r|S |D ]  }t        |«      j                  «       sŒ|c S  t	        d| › d|› �«      ‚)NzNo se encontro 'z%' en PATH ni en las rutas conocidas: )ÚshutilÚwhichr   ÚexistsÚFileNotFoundError)ÚnameÚ	fallbacksÚfoundÚ	candidates       ú0tools/video_marketing/generar_video_marketing.pyÚfind_binaryr   B   sV   € Ü�L‰L˜Ó€EÙØˆÛˆ	Ü�	‹?×!Ñ!Õ#ØÒð ô Ð.¨t¨fÐ4YÐZcÐYdÐeÓ
fÐfó    c                  óv   — t         D ]  } t        | «      j                  «       sŒ| c S  t        dt         › �«      ‚)Nz,No se encontro ninguna fuente TTF conocida: )ÚFONT_FALLBACKSr   r   r   )r   s    r   Ú	find_fontr   L   s8   € ß#ˆ	Ü�	‹?×!Ñ!Õ#ØÒð $ô ÐJÌ>ÐJZÐ[Ó
\Ð\r   c                 ó\   — t        | «      j                  dd«      }|j                  dd«      S )zõEscapa una ruta de Windows para usarla DENTRO de un valor de filtro
    ffmpeg (ej. drawtext=fontfile=...): barras invertidas -> '/', y el ':'
    de la unidad ('C:') se escapa como '\:' segun las reglas de escaping
    de filtergraph de ffmpeg.Ú\Ú/Ú:z\:)ÚstrÚreplace)ÚpathÚps     r   Úescape_ffmpeg_pathr&   S   s+   € ô
 	ˆD‹	×Ñ˜$ Ó$€AØ�9‰9�S˜%Ó Ð r   c                  ó  — t         j                  j                  d«      } | r| S t        t        «      j                  «       }|j                  D ]¥  }|dz  }|j                  «       sŒ|j                  dd¬«      j                  «       D ]h  }|j                  «       }|j                  d«      sŒ%|j                  dd«      d   j                  «       j                  d	«      j                  d
«      c c S   n t        j                  d«       y )NÚOPENAI_API_KEYz.envúutf-8Úignore)ÚencodingÚerrorszOPENAI_API_KEY=Ú=é   Ú"Ú'zªNo se encontro OPENAI_API_KEY ni en el entorno ni en el .env del proyecto. Definila en el .env (misma variable que ya usa OpenAIAssistantClient) o exportala en la sesion.)ÚosÚenvironÚgetr   Ú__file__ÚresolveÚparentsr   Ú	read_textÚ
splitlinesÚstripÚ
startswithÚsplitÚsysÚexit)ÚkeyÚhereÚparentÚenv_fileÚlines        r   Úload_openai_keyrC   \   sÚ   € Ü
�*‰*�.‰.Ð)Ó
*€CÙ
Øˆ
Ü”‹>×!Ñ!Ó#€DØ—,”,ˆØ˜F‘?ˆØ�?‰?ÕØ ×*Ñ*°GÀHÐ*ÓM×XÑXÖZ�Ø—z‘z“|�Ø—?‘?Ð#4Õ5ØŸ:™: c¨1Ó-¨aÑ0×6Ñ6Ó8×>Ñ>¸sÓC×IÑIÈ#ÓNÔNð [ñ ð ô ‡H�Hð	jõr   c                 ó²   — dd l }||| ddœ}|r||d<   |j                  ddd|› �i|d¬	«      }|j                  «        |j                  |j                  «       y )
Nr   Úmp3)ÚmodelÚvoiceÚinputÚresponse_formatÚinstructionsz&https://api.openai.com/v1/audio/speechÚAuthorizationzBearer é<   )ÚheadersÚjsonÚtimeout)ÚrequestsÚpostÚraise_for_statusÚwrite_bytesÚcontent)	ÚtextoÚdestino_mp3Úapi_keyrG   ÚmodeloÚinstruccionesrP   ÚpayloadÚrs	            r   Útts_generar_audior\   o   sl   € Ûà¨¸ÐSXÑY€GÙØ"/ˆ�ÑØ�‰Ø0Ø  G¨G¨9Ð"5Ð6ØØð	 	ó 	€Að ×ÑÔØ×Ñ˜AŸI™IÕ&r   c                 ó„   — t        j                  |ddddddt        | «      gd¬«      j                  «       }t	        |«      S )	Nz-vÚerrorz-show_entrieszformat=durationz-ofzcsv=p=0T)Útext)Ú
subprocessÚcheck_outputr"   r9   Úfloat)r$   Úffprobe_binÚouts      r   Úget_audio_durationre      sJ   € Ü
×
!Ñ
!Ø	�d˜G _Ð6GÈÐPYÔ[^Ð_cÓ[dÐeØô÷ �eƒgð ô �‹:Ðr   c	                 óÊ  — |j                   }	| j                  d«      xs dj                  «       }
|	d|d›d�z  }|j                  |
d¬«       | j                  d«      }t	        d	t        |t        z  «      «      }g }|r‹||z  }|j                  «       st        j                  d
|› d|› d�«       |dddt        |j                  «       «      gz  }dt        dz  › dt        dz  › dt        dz  › d|› dt        › dt        › dt        › d�}nO| j                  d«      xs t        j                  d«      }|dddd|› dt        › dt        › d|d›d t        › �
gz  }d!}|dt        |j                  «       «      gz  }|g}d"}|
r6d#t!        |«      › d$|j"                  › d%�}|j%                  d&|› d'|› d(�«       d)}d	}d&|› d'�}|r£|j                  «       r“d}|dt        |j                  «       «      gz  }t'        | j                  d*«      «      }|r+|j%                  d&|› d+�«       |j%                  d&|› d,�«       n*|j%                  d&|› d-�«       |j%                  d&|› d.�«       d/}d0j)                  |«      }|d1g|¢d2‘|‘d3‘|‘d3‘|› d4�‘d5‘|d›‘d6‘t        t        «      ‘d7‘d8‘d9‘d:‘d;‘d<‘t        |j                  «       «      ‘}t+        j,                  |d=d=t        |	«      ¬>«       y )?NÚtexto_pantallaÚ Útexto_Ú02dz.txtr)   ©r+   Úcapturar.   zEscena z: no existe la captura 'u   ' (Â¿corrio el Capturador?)z-loopÚ1ú-iz[0:v]scale=-2:r   z+:force_original_aspect_ratio=increase,crop=r!   z$,zoompan=z='min(zoom+0.0008,1.2)':d=z:s=Úxz:fps=z[bg]Úfondo_colorÚ#ú-fÚlavfiz
color=c=0xz:d=z.3fz:r=z[0:v]copy[bg]Úbgzdrawtext=fontfile=z
:textfile=zd:fontcolor=white:fontsize=64:line_spacing=12:borderw=3:bordercolor=black@0.75:x=(w-text_w)/2:y=h-340Ú[Ú]z[txt]ÚtxtÚlogoz!:v]scale=420:-1,format=rgba[logo]z(][logo]overlay=(W-w)/2:(H-h)/2-120[vout]z;:v]scale=160:-1,format=rgba,colorchannelmixer=aa=0.75[logo]z"][logo]overlay=W-w-30:H-h-30[vout]z[vout]Ú;ú-yú-filter_complexú-mapz:az-tz-rú-c:vÚlibx264z-pix_fmtÚyuv420pú-c:aÚaacT©ÚcheckÚcapture_outputÚcwd)r@   r3   r9   Ú
write_textÚmaxÚroundÚFPSr   r<   r=   r"   r5   ÚHÚWÚDEFAULT_FONDOÚlstripr&   r   ÚappendÚboolÚjoinr`   Úrun)ÚescenaÚidxÚcarpetaÚ	audio_mp3ÚduracionÚ
ffmpeg_binÚ	font_fileÚlogo_pngÚout_mp4Ú	build_dirrg   Útxt_pathÚcaptura_relÚframesÚinputsÚcaptura_pathÚfondo_filtroÚcolorÚfiltrosÚultimo_labelÚdrawtextÚaudio_input_idxÚ	map_videoÚlogo_idxÚlogo_grandeÚfiltro_complexÚcmds                              r   Úbuild_scene_clipr¬   ‡   s¦  € Ø—‘€IØ—j‘jÐ!1Ó2Ò8°b×?Ñ?ÓA€NØ˜V C¨ 9¨DÐ1Ñ1€HØ×Ñ˜°ÐÔ9à—*‘*˜YÓ'€KÜ�”E˜(¤S™.Ó)Ó*€Fà€FÙØ Ñ,ˆØ×"Ñ"Ô$Ü�H‰H�w˜s˜eÐ#;¸L¸>ÐIdÐeÔfØ�7˜C ¤s¨<×+?Ñ+?Ó+AÓ'BÐCÑCˆð
 œQ ™U˜Gð $Ü˜‘E�7˜!œA ™E˜7ð #2Ø28°¸¼Q¸C¸qÄÀÀ5ÌÈÈTðSñ 	ð —‘˜MÓ*Ò;¬m×CÑCÀCÓHˆØ�4˜ $¨*°U°G¸3¼q¸cÀÄ1À#ÀSÈÐRUÈÐVYÔZ]ÐY^Ð(_Ð`Ñ`ˆØ&ˆà
ˆt”S˜×*Ñ*Ó,Ó-Ð.Ñ.€Fàˆn€GØ€Láà Ô!3°IÓ!>Ð ?¸zÈ(Ï-É-Èð Y%ð %ð 	ð
 	�‰˜˜<˜.¨¨(¨°5Ð9Ô:Øˆð
 €OØ�L�> Ð#€IÙ�H—O‘OÔ%ØˆØ�4œ˜X×-Ñ-Ó/Ó0Ð1Ñ1ˆÜ˜6Ÿ:™: fÓ-Ó.ˆÙØ�N‰N˜Q˜x˜jÐ(IÐJÔKØ�N‰N˜Q˜|˜nÐ,TÐUÕVà�N‰N˜Q˜x˜jÐ(cÐdÔeØ�N‰N˜Q˜|˜nÐ,NÐOÔPØˆ	à—X‘X˜gÓ&€Nà�Dð
à	ð
ð 	ð
ð *ð
ð 	ð	
ð ð	
ð "ð	
ð '6Ð%6°bÐ#9ð	
ð
 	ð
ð
 ˜#�ð
ð 	ð
ô ”#‹hð
ð 	ð
ð ð
ð &ð
ð (1ð
ð 	ð
ð ð
ô 	ˆG�O‰OÓÓð
€Cô ‡N�N�3˜d°4¼SÀ»^ÖLr   c                 ó  — |j                   }|dz  }|j                  dj                  d„ | D «       «      d¬«       t        j                  |dddd	d
d|j
                  ddt        |j                  «       «      gddt        |«      ¬«       y )Nzlista_escenas.txtÚ
c              3   ó<   K  — | ]  }d |j                   › d�–— Œ y­w)zfile 'r0   N)r   )Ú.0Úcs     r   Ú	<genexpr>zconcatenar.<locals>.<genexpr>Õ   s   è ø€ Ð4©e¨�F˜1Ÿ6™6˜( !Ô$©eùs   ‚r)   rk   rz   rr   Úconcatz-safeÚ0rn   z-cÚcopyTr‚   )r@   r†   r�   r`   r‘   r   r"   r5   )ÚclipsÚsalidar—   r›   Ú
lista_paths        r   Ú
concatenarr¹   Ñ   s†   € Ø—‘€IØÐ0Ñ0€JØ×ÑØ�	‰	Ñ4©eÓ4Ó4¸wð ô ô ‡N�NØ	�T˜4 ¨7°C¸¸z¿¹ÐPTÐV\Ô^aÐbh×bpÑbpÓbrÓ^sÐtØ 4¬S°«^ör   c                 óè   — t        j                  |ddt        | j                  «       «      dt        |j                  «       «      dd|› d�ddddd	d
ddt        |j                  «       «      gdd¬«       y )Nrz   rn   r{   z[1:a]volume=zC[m];[0:a][m]amix=inputs=2:duration=first:dropout_transition=2[aout]r|   z0:vz[aout]r}   rµ   r€   r�   T)rƒ   r„   )r`   r‘   r"   r5   )Úvideo_sin_musicaÚmusica_pathr·   r—   Úvolumen_musicas        r   Úmezclar_musicar¾   Ý   sx   € Ü‡N�Nà˜Ø”#Ð&×.Ñ.Ó0Ó1Ø”#�k×)Ñ)Ó+Ó,ØØ˜>Ð*Ð*mÐnØ�E˜6 8Ø�F˜F EÜ�—‘Ó Ó!ð		
ð  4ör   c                  ó
  — t        j                  t        t         j                  ¬«      } | j	                  dt
        ¬«       | j	                  dt
        d d¬«       | j	                  dt        dd	¬
«       | j	                  ddd¬«       | j	                  ddd¬«       | j	                  ddd¬«       | j                  «       }|j                  }|dz  }|j                  «       st        j                  d|› d�«       t        j                  |j                  d¬«      «      }|d   }|dz  }|j                  d¬«       t!        d t"        «      }t!        d!t$        «      }t'        «       }	t)        «       }
t*        j                  «       rt*        nd }g }t-        |d"¬#«      D ]·  \  }}t/        d$|› d%t1        |«      › d&�«       |d'|d(›d)�z  }t3        |d*   ||
|j4                  |j6                  |j8                  «       t;        ||«      d+z   }t/        d$|› d%t1        |«      › d,|d-›d.�«       |d/|d(›d0�z  }t=        |||||||	||«	       |j?                  |«       Œ¹ t/        d1«       |d2z  }tA        |||«       |d3z  }|jB                  ra|jB                  j                  «       rGt/        d4|jB                  jD                  › d5�«       tG        ||jB                  |||jH                  «       ntK        jL                  ||«       t/        d6|«       y )7N)ÚdescriptionÚformatter_classÚcarpeta_tema)Útypez--musicaz-Archivo de audio de fondo (mp3/wav), opcional)rÃ   ÚdefaultÚhelpz--volumen-musicag
×£p=
Ç?r½   )rÃ   rÄ   Údestz--vozÚshimmerz#Voz de OpenAI TTS. Default: shimmer)rÄ   rÅ   z--modelo-ttszgpt-4o-mini-ttsÚ
modelo_tts)rÄ   rÆ   z--instrucciones-vozÚinstrucciones_vozuh   Voz calida en espaÃ±ol rioplatense (Argentina), ritmo tranquilo pero seguro, tono profesional y cercano.)rÆ   rÄ   z
guion.jsonz
No existe u    (Â¿corrio el Guionista?)r)   rk   ÚescenasÚbuildT)Úexist_okÚffmpegÚffprober.   )Ústartru   r    z] Generando voz...Úvoz_rj   z.mp3Ú	texto_vozg333333Ó?z] Armando clip (z.1fzs)...Úescena_z.mp4zConcatenando escenas...zvideo_sin_musica.mp4zvideo_borrador.mp4zMezclando musica de fondo (z)...zListo:)'ÚargparseÚArgumentParserÚ__doc__ÚRawDescriptionHelpFormatterÚadd_argumentr   rb   Ú
parse_argsrÂ   r   r<   r=   rN   Úloadsr7   Úmkdirr   ÚFFMPEG_FALLBACKSÚFFPROBE_FALLBACKSr   rC   ÚLOGO_FALLBACKÚ	enumerateÚprintÚlenr\   ÚvozrÈ   rÉ   re   r¬   rŽ   r¹   Úmusicar   r¾   r½   r   Úcopyfile)ÚparserÚargsr”   Ú
guion_pathÚguionrÊ   r›   r—   rc   r˜   rW   r™   r¶   Úir’   r•   r–   Ú	clip_pathÚ
sin_musicar·   s                       r   Úmainrë   í   sÙ  € Ü×$Ñ$´Ì(×JnÑJnÔo€FØ
×Ñ˜¬TÐÔ2Ø
×Ñ˜
¬°tÐBqÐÔrØ
×ÑÐ*´ÀÐK[ÐÔ\Ø
×Ñ˜¨Ð9^ÐÔ_Ø
×Ñ˜Ð0AÈÐÔUØ
×ÑØÐ$7Øzð ô ð ×ÑÓ€Dà×Ñ€GØ˜<Ñ'€JØ×ÑÔÜ�‰�:˜j˜\Ð)BÐCÔDä�J‰J�z×+Ñ+°WÐ+Ó=Ó>€EØ�IÑ€Gà˜'Ñ!€IØ‡O�O˜T€OÔ"ä˜XÔ'7Ó8€JÜ˜iÔ):Ó;€KÜ“€IÜÓ€GÜ -× 4Ñ 4Ô 6�}¸D€Hà€EÜ˜w¨a×0‰	ˆˆ6Ü��!��A”c˜'“l�^Ð#5Ð6Ô7Ø $ q¨ g¨TÐ 2Ñ2ˆ	Ü˜& Ñ-¨y¸'À4Ç8Á8ÈTÏ_É_Ð^b×^tÑ^tÔuÜ% i°Ó=ÀÑCˆä��!��A”c˜'“l�^Ð#3°H¸S°>ÀÐGÔHØ '¨!¨C¨°Ð 5Ñ5ˆ	Ü˜  G¨Y¸À*ÈiÐYaÐclÔmØ�‰�YÕð 1ô 
Ð
#Ô$ØÐ3Ñ3€JÜˆu�j *Ô-àÐ+Ñ+€FØ‡{‚{�t—{‘{×)Ñ)Ô+ÜÐ+¨D¯K©K×,<Ñ,<Ð+=¸TÐBÔCÜ�z 4§;¡;°¸
ÀD×DWÑDWÕXä�‰˜
 FÔ+ä	ˆ(�FÕr   Ú__main__) rÕ   rÓ   rN   r1   r   r`   r<   Úpathlibr   r‹   rŠ   r‰   ÚSYSTEM_COLORSrŒ   r4   r5   r6   rÝ   rÛ   rÜ   r   r   r   r&   rC   r\   re   r¬   r¹   r¾   rë   Ú__name__© r   r   Ú<module>rñ      s÷   ðñó< Û Û 	Û Û Û 
Ý à�	€€1€cð ØØØØØñ€ð €á�X“×&Ñ&Ó(×0Ñ0°Ñ3°hÑ>ÀÑIÈEÑQÐT^Ñ^€ð WðÐ ð XðÐ ð $Ø!ð€ògò]ò!òò&'ò òGMòT	òò 5ðp ˆzÒÙ…Fð r   