From 9f2807826ead5e9e5d18ceba2232feaa785ffbf6 Mon Sep 17 00:00:00 2001 From: CGlide Date: Fri, 22 May 2026 16:29:52 +0200 Subject: [PATCH] Add files via upload --- README.md | 6 +- __pycache__/__init__.cpython-312.pyc | Bin 0 -> 1813 bytes __pycache__/load_audio_ui.cpython-312.pyc | Bin 0 -> 6254 bytes __pycache__/load_video_ui.cpython-312.pyc | Bin 0 -> 17175 bytes __pycache__/ltx_director.cpython-312.pyc | Bin 0 -> 45146 bytes .../ltx_director_guide.cpython-312.pyc | Bin 0 -> 5903 bytes __pycache__/ltx_keyframer.cpython-312.pyc | Bin 0 -> 5039 bytes __pycache__/ltx_sequencer.cpython-312.pyc | Bin 0 -> 8348 bytes .../multi_image_loader.cpython-312.pyc | Bin 0 -> 8446 bytes __pycache__/patches.cpython-312.pyc | Bin 0 -> 8657 bytes __pycache__/prompt_relay.cpython-312.pyc | Bin 0 -> 9764 bytes .../speech_length_calculator.cpython-312.pyc | Bin 0 -> 2748 bytes ltx_director.py | 346 +++++++++++++----- ltx_sequencer.py | 63 +++- 14 files changed, 310 insertions(+), 105 deletions(-) create mode 100644 __pycache__/__init__.cpython-312.pyc create mode 100644 __pycache__/load_audio_ui.cpython-312.pyc create mode 100644 __pycache__/load_video_ui.cpython-312.pyc create mode 100644 __pycache__/ltx_director.cpython-312.pyc create mode 100644 __pycache__/ltx_director_guide.cpython-312.pyc create mode 100644 __pycache__/ltx_keyframer.cpython-312.pyc create mode 100644 __pycache__/ltx_sequencer.cpython-312.pyc create mode 100644 __pycache__/multi_image_loader.cpython-312.pyc create mode 100644 __pycache__/patches.cpython-312.pyc create mode 100644 __pycache__/prompt_relay.cpython-312.pyc create mode 100644 __pycache__/speech_length_calculator.cpython-312.pyc diff --git a/README.md b/README.md index 243bd03..e75f10c 100644 --- a/README.md +++ b/README.md @@ -33,14 +33,10 @@ All of my nodes are created with the help of AI, so there may or may not be redu **❗❗IMPORTANT❗❗** -If you don't see the latest version (v1.3.9) yet in the manager then just downloaded the nightly version (or fetch the updates to update the list to see the latest version). +If you don't see the latest version (v1.3.5) yet in the manager then just downloaded the nightly version (or fetch the updates to update the list to see the latest version). Also you will need to update ComfyUI-LTXVideo and ComfyUI-KJNodes to the latest version as well. You cannot use this node without updating ComfyUI-LTXVideo! # 🔄 Recent Updates -**v1.3.9** - * **Fixed recent updates not showing in the manager** - -It took like 5 tries but I finally got it working 🤦‍♂️ **v1.3.3** * **LTX Director Hotfix 2** diff --git a/__pycache__/__init__.cpython-312.pyc b/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e93ac256b7db423a7aa1c81b0fb28a6d6043e546 GIT binary patch literal 1813 zcmZ8h%WoS+7@vLk?M?iSla^@vf*O^C0|$gsq`VYaP2DI?XuFCuvOE)K!>-qzU6z+_(Qm~H*3`hsYr<4T$}@N;+t8on=;z{=6lWS`@Y}ztEMFpjP73M z@Q(;WzjGlRi7_+sfq8-mB9et{$&e(@%a&{_h9Y>yQtgNl5xi zBxA03u5$j31UptFKfSqg=LYTVvxZF>$eEj6%QLHXqeVBJ1`#^$Q>XX3wA~bPsotTq zd9X>_E$?8pVKuu}!*lrR6koI4C8o1m4aKiaLPK%q&YH<+GjPtpwxPJu1+O>!krmmW zT6OIG-ueTNwq4U{`?Bf4W^v~}WenV!K`a6a2^3?r0@D*jks%Re$W$Q`RUtUh!>O^y znQ0by{zD+;BlY>%V#Iq&MfFo#%&|M(Hnkc(Kgy`rW$h-9Rybr}zK4Hw5y%ZB!LeRw zLmsz^(UR-vXXP8|SgKWI#tVz_x`UUfF17YuzNP-}O8tvH@!Z|&WNvm{&#`gaA=KTw zebDgM7;V_@s^fZ}guWP?ZPUYeq0{rV7WITTwoKRS&z^a}!h0qSj&#dF{zQL2LZ?xr zm0zXL4GAa!YIz*3lqOZ;j02SM=rLZAEXqlYlQ<`n?DsV& zdVK=8eonwm7kJYHzy&T7y!Fcg+VlW!`a8UVBcM$eaMO3IV^P43iyXCjh_8O`tfULL z_0@&NL${*%`P!|ub-cQ{T(9Gs%UfI3+D6@<6Uwz}eQR_1F0L)#Tz_ZNZm+N4wd(fz z>dvk0yS2(WU$eXi`0KEbh-mmZo3|2d@?L^1(M&{y0%tdDC?a5f*%dtnTcWAp=A^5L zP{I;ej~l$R;I1hmJJ#Lj?S<=jp#3zz2O0Mm5q3X!R)t%<(Fh=hxo&jK1?XSY^%yV7 zpn|hd%x1fVY1o8ZQR+d>=-llBC%gl&OF;Y>#tqBDnEkJy;!6Q?zGREw#w*f&3}mQC zl5~PTIzgWbx^#j*6yFul{Du~RKUJer@`r^}1k*4hNwZH=BLvehj*1rs<*S2&KA8V( zke?ra<*RSAi5d9?$`8w^czIC1HYi*g%zr+}Ulbp#xdtBd;4wEWq3p~f?R9eN+nA{S F{{U~!-5vk{ literal 0 HcmV?d00001 diff --git a/__pycache__/load_audio_ui.cpython-312.pyc b/__pycache__/load_audio_ui.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..456d7417b3b1fa62dada141be1de0957d59915c1 GIT binary patch literal 6254 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 d_Xn1nqG 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 ICM>u9FX}_&_W%F@ literal 0 HcmV?d00001 diff --git a/__pycache__/ltx_director.cpython-312.pyc b/__pycache__/ltx_director.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fff80cfb2277fa9ce7af11b006b041a521099e8c GIT binary patch literal 45146 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 Bn~VSe literal 0 HcmV?d00001 diff --git a/__pycache__/ltx_director_guide.cpython-312.pyc b/__pycache__/ltx_director_guide.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a569e75df5a5293cb738bfea23bbc67dbf57190 GIT binary patch literal 5903 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 literal 0 HcmV?d00001 diff --git a/__pycache__/ltx_keyframer.cpython-312.pyc b/__pycache__/ltx_keyframer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f1d489600bb52197cd2dca338423a6efdbce5fcf GIT binary patch literal 5039 zcmbVPTW}NC8QxvpWy!kwB3riCCLt(*9Bd#HL!dUq7ceG{NdlCNvgoYsHM)6s1-7zc z(it)%w@htkIOh^S3(*o;<4?UzXsIJ>MBR6KD!VvC-r04#EICDl zo|{k&R~a_5>n#qkN&2n9*XXpsB3ew+Y$BROEG^EmG#6)PSOKn;MNB4RB9~IlF-Bw) zVx~uz(li2NN^p_Pu$=mUb7dC&jbk-uhc9MAZsDxp3# zs*+(IzbP3fJWzD?g;E>eo@K<7Jj=v|6G=hL%)Y@ws8Lp+uWH9%K1MA>0k#hI4lF+2{c-SZR4U$EVlS`zfm|ddJgpLFjCcCP6R!1ATgK( zqRWmXlAOT8u?kn{bP7Snp>T-eeGr+pSNIqckfRX}X_Klo3OqAOeo<{etPtfnZ7Wr? z=D46*l4%hl5JCl|+Jgy})kT?xhGm}cO38Wgv5~6D2nFO9=7a-@6 zY8r;z1Boff<2a+5&uUsj2GtOa34ABkOmYIYK-2U;N2UfYok+%~7vCJKexqqYOvWSF zcj3~`GudC^jfo49E0x+3PA#fV$XG7HMg+}lrmeR2gmn*$s_vU?K+e|oJ%fm~< z%i~Mq>rL{WGr94iW8$Hsad~WMZ29cc+4WI5{6_9<(J_T5N0&yICzdAGUzPjL=O&7d z3nh!uYtNZW4#MVIb}l)8c6n`jb$Ttf8rwK}*K?1&$IGuz%I_vikZoj&T8TX&h?aS3 zn;>jF^|hyYWq!Tq=fT{d;_xn?SvvF3?Oijkn%5kw4yAe5#^6T3?0-QCb||gz3o3y& zrSr($!MpwPvDf9`q|(t{auJ@6Cxq4G-S!e5-@`G~la9OlV6D>9Q+8e(md`?%%KzKX1_YrRI^5W8>;_p!cdz7ZatX32Yt7oScF8;k8lP>K zz;?C)I2>7Lwoz)7>=``clAMxF8@UlBQCA7x51vr})e}$RkXWwD;By_sAT=O^i*TJa#;Ecxq3V89Vb?kg|Djr4vGk4@uoVIKaZSVbB2aKK!h`VLyLf@d0_nkssf zT#_5`mg9CgL+kPzki8mBOM;U8*%qkCTHVKh zWYJGC+lKQ+JB>D+k@^W{+odLCx&m3xnSRxdL_1MB8s{Npe)>I;6nPD5VZ5h`oha^)ocru7d|1c;zT)K~||*i_7zU94q9_ zNkDkr760dYDx;@g$t-zLw6jUX| zUge^!hLHFsSmJSx@U752#;?ia@1UvH%UleK2g9r8DBw1he~jxB6jO|;_koLoznEGmU!|ii?}${R1Ib7AV`BlT4lCRKxr)3)lPmdR*l~y z9zUx*{ujvO$5l07xyJA_f)<48)LoutqTrvPk`dK6%W^ZbB2-Kqi@u!P+{bMdKb^*9V90qP&VkWXfk9KIPT{968xD3nh!@ip| z+@m^l+@sr6trf_pnl;1-PUssHDU+nAdPFXcQ9w;h9&NP@O{2*)U>1AX2M#T$Hb5=< zQ3@EH04n(pjo**Gv#<+nG%d0j{|=Z@o;?68!cQQ(-X}_C!WUQ%6ui5(yrF_ORP^r6 zS)d$mwe}ZU`*Tj^&``nJmm}qdPMPj|bbR=a**|0p)}uL7ZhmF|Mn~SExPx-nfr9%$ z&ZKxcOXu44)$7|9V{fDE*bB%d{EEE)+o^S8| zWZ~*i!CqbMjyHS%kM3{ zw|-#h`bP5u*9)76K0k8nNPhm-vAb_R*gNzv(D_OGN9|jI{z9NX|Jv`*{O-)Xo_kF3 z;OPD5<;l0@3sISk7Xyi{z|}(Fs(fuh&Pc^TcGdhS(79q(f<2!e_>}p~vpKXmxjD3P zq!8@Qol)GrHT$Z4{nery!h)^r4sS9A`X$-X0Yp!4-c#uAlMjy+=#l%~1^P71LlEoC z16P;Q^-}(5q3igH1324u%b|fnU?6u2Hmj{;eeySkjZ=B&J+ko9V38gw22N-zf#CY7 zP0!~ow_5U^TWy74fBv0f>xtYLXy`xq#o!n7^1$TXSMFsBMP9KFDPnw%iz*Ux_$hJ*WT@U!{+i+3-`eZ%s;;i6-t^d?DoU)(-VV)T|> z%5JvEKZq1M-YvQq*~;*}kdzZ4t7?sCf88Px)gFn&lPC>$KcYG!k@++e!++|4YKX=d zL5Q>BY!dNd5Y+w<@FRE>f$kQesnhO)_D@RdaQPGlpu0gRCigeg9+UlvfiQbYcvLz^ zYQqzx=`wkr`m^&(=RXLI(0IO~w6U%hD+*coWAFi2@Ix8a-bsE4&$zXj2$SN%_!7gD zpuLH<6POV{jJih%c%OQyT94|n9^+?W0pm;omzk1*B+0J`$5({+FGSb2F-4M>$(6pf NqpL^1B{V|Q@h`9v^X&it literal 0 HcmV?d00001 diff --git a/__pycache__/ltx_sequencer.cpython-312.pyc b/__pycache__/ltx_sequencer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e255d36c019430bcb6b3e8c4a357f2702cb765ec GIT binary patch literal 8348 zcmbtZYfKy2exDgXFvbRB9=5^2kPw1NAWPWnX7kz*0tpCAvQDxamaH@J8H^o2U}i|b zJKo3Dsx?Si^mT#&5iQp7fcY;fCKw zDV1SX2quydo(;ws{-$CZx%AGJK7`KAMiA>G6)KVpX@uIlz=e1|2<>HpCB{iaj8m)u zk)IIv3p2-!(56^Z)K*NY)h8)r_{6w9vuxhzGpSMo?942i2(esCHt#3e}SG&8Vy-z2yheTTppPdNp!( z^C&6biYj*K!=^MTl2Q9^I@~JqOyze+OLDd$JE}xg@OGf;2hRIt8r}WE`jN!Yn{0V+-7O7tl_bBjf3!*_%D{iAb_Y7$7gErmEMSSabr0KPi>$R`Iw;i>k z{ip-^RKA`6Z@vc#d=CQOgQyF2m*N{X?D+B1yGBCT-sMrZuJuld4xv|24>~N8MRu0j z@r^q)dJT~edUaVpf!bJ-y3}qhCEJ2teQ-pNj3Vh?UAvt!T8jQP^!g5c*!bY69)$tI z_l94wOegt>5V^&sPG2b0=uk3&pf8z-B*L_iq;F3}LQ`}YAK>&&c7Bp$;w&9WOu|Sc z7Nc*lG=mU};BYS!lF675nN}K0r1*9kGD}4j>EYBjW7M$%# z&`6kK3%W((Oqk^rbBqz#gpfL_k!Y=h+8mx{xPrQv1*T;ah)zyIHNw-{T%{sD3swXp ziRoD()pmvvLQ^18V^2?V$v8cVCk$bEBS{9aoMKJP#)I07XE+c!99z#0!%MMi-N6{1 ziBhiy*cclU=&9swI?g2K!IOxcJH!hdn+OY2;8O&jP#&uX3o#i9&vIAqvjJ&{3D>fA2r(?`~Fahhr;Zt0xh$MKH6M}JYkYZLBj91Ed7OyOy>Mdx1 zt&g+9R1(pXNsdOWz;eJFuewGLAwW+jBME`;_8FA24szh|XL!>+ zn}b)XS9AQ}g#g{5E*9n>$&w8N-Uerv| zBu2iL|MaIw)qarHG+2m7Y_X=UYL4o4I_0E0B49;ij*Zd$G!tTd-IsjkmkLuXnw3mU zsVqp;v<-$q3-wVeAN~1nPKW>ME`GjzGu0eWU0bl|J4z^Iw^FVzaPYr0Hd}9o->?1k zx&KIg@@A?gpszl5m8LmY2J=#OxIWR_HyNe!?I}h$%dt$H?@#hVN`#vgtw!r~Z1*;x z83F8NLy^e{#IEW!9BGjd%hMpE5DVRO->i`A;^z|~HR3Kna8C>LTP(yAOurT3BR696 z^sNY^?iKy8fFQ*|Npdc%V{`FFgCPiF^*|_WIUl7?(;~)#MZs1Gr-sL71=wG(BWbV) zF*m>fft?fR8?j{QCe6eCP|qI-QYIwKGBH|+#6kJ(h+-Kyl~iBh-I0J$4@QtGO0k3> zBEv~;Ua3GVAL1fvy=+4}t1<$TSH1Tu{sbI5XmmV%DsLw!ncou#F6%7|$KR zV#x@PZ=y6!|M6Vl*aWbfoWDG@U4~|PAsL6eG?*~4d)>SAxiMib$m{pq?&*2O4yQyU z!3KF%e5wJ$XFGbjca7l>5YNLg^%3#HOxUaLj4h09+FEnA)@-Nr+MHx-&D-Xm*eYMz zKe#Y>XJlbyrB3PyWJdC~OL+3o!Vo4{IWKijWybQh2<|+;aQ=>e!M}1+I{Z$?pSNAz zsxUjP8S|EdD6hI>U$FnhjpfOu$>rEmEPG&Y#ME^?Y$j6Ej^*9`T7 zAj&yv%e+H1wKTPySW0BCt-rG|FP*q3y&D3W1R0_h6PO06G%O`sD!(Jgxl#SlAiWg; zg7?TkLC7VQ;4=05>iWf*l|6sy&GgAO=bh1o(I*b)vU$n8Y+JI)^?S2@*|2wQf}r)lJU{OSSWblc=s)wk%neE0-$e`nK%FY`;|7 zA$wb7ccbiXmOWm%`NaCg_5Sr4$=g?;Z7D_Dk|kI8#W9_6r$esWw?z@2w<)>C^LwzZYN=||(Vla( zuMJC%_PpawY;eiW@}=@k2c2`!t5eeH>ym@cI~dGir#}il?I*`57=u-)zCgi(*Hyl- z+a1;|!d`BLPKbXq#|pDtB7_e*{lORO3ix~Ogx+OBG(`20qB3m}jfnI>PgIAGMWZ?t zOqU}{G~Ob(T9{3J?`&)0oLC+$K!GB5!~~oX>58;1ZBJLGtAuTBqb06zVg)jYc4R^1AKKVJ8wb`#G<^(zrL;ySY;l4_rgXJf7R9jlTMq&t zsb4J9&X>#qu(&;^1`+96k^J~|p;~7plKRCMnQoqi54I0kMUaVQBLjYe|69t59iS7% zU-)l5yD5+r)9HNEwP7M%C)RRD#JVUR_|}6e^qBw;OV6;0&Qe!nJx%}$+3yvBiA4KL z_*8zcq$<$~+#JQ+geF~Khzv6_q@byL^enMRUi$}#u6nUvtXBP3{}S2NVm)wn7IXfz zMKp=^z!9QLtZyLFF46T7`DrJtlKUmAS%bL%5UkZTNPEDuKS$tSSf@YJxfQK1z~ti9 zxC!42juQ*L`g}Yi-2lDyxVEdeQFNlRn;k&aDmH*#rB}$MTIUu$V53K^H;4^TZ@gE& z(>G#x3ouW6l+qjL-lz-N=74U`h^iSi*AtBa<3?o66tNdUwMfyY0Z~E zN^YwvsqtQ!PDK)l^V?SSzeLiWZ%Ois-jBPAJmCEa9%vQ4yKFD=v*`YaS|mU9i$t_l z_wr6D8pJBGQgn%y`-SA#1jIzTDcub7_wLNoYa%H+isGqBw_J38i$hDA7HP4$pat6h*Ob_Lzwm_# z5PJ#1sn3d*NV&8ToRK815{uNQKf6uL8LkqyNneK_a2ykd+ddDNb34t-Ie-&nUrk7u zpN7jQVsF7sUj?BY24);~Acu1X96pbfx@q;IALQ^wKZq~ZF}O9RnogcPNnaWo9T*w% z572?D{(gGE-*;wY;4BRzsm`HoL=b>$Jm3lp47T$IZv!Z3r7!dN+OCktQZ<;{XrKRb z-v~WAc6LDJamEj@yC6@6oFRcl2QehUENOfp0KQ{`gWUyAfRXX#|MC#v5fv|Vq$uC9 zRGE4sr}w7Xj?sae5xAElx&wG?;7P;UKtbQY=-tP)VbgJtD0W_8IDrqUkcd|*3(W!` zN?E&3(K>4z-Jt`sV|1$C2a+_i0hpg=jTvY=1XsWJ^{@f-vxkur22o=iD( zs6}^ZKvf}q9F2#az;9GDPPGgeaC>0j8SEz_b+QsG**#b3l0WB4# zfG92H-K~(;RJHZpUEuMW6_D5&;LY{J%jZ&DD0w@<126~RgmVx<0H1&*8O0QeB@?V- z;-?r0CXU2diUBeeiUCwnj8Q(BP)ykGyizqB81tV6NQ~G4 zj!SZ!ng=n>!Xk0p5tR^<3ILhZ436T!|1!`l&=gUsG@KRGvrWJr(h!Pi8ZeZgVK%ED zxNG3bw}(59%__&Q3jD%1D-P$RIeeew@a0D_-@MImVIJ0BwRjRhWs>6+n=TjwJk>Lb zNsSqW3@Y}*U?EoY<`f$VPYK(kkg*Y_w&!XKqgYiYK|YdVwH=5zpJLZTKZqECf#55k z;UM0AJa+=mF+}2F#WV?Ec22SASpxueg)EP%3*g#96XI4e;8&R%`N1BA6qIsxlFGrV z+Xvii+v0#Nk7Et6=l49^Nvu;DJI97*1vXW?3s4q%@xN~PU%|ol5%JXBxascAxqCBq zz-jL0l}OIjvFYm0xw`YNS28x}w7FMa%T=_>o|ddF=jqz?^yWOhdC!rB;ivs$oBfw_ z@UxxH3@r96#AxmClg<}wmKqr9hJJyF21{2*Pg3u&(1um^F3_MSV0|E z({gkvnr&LMc%&pAWCjt&?B8zuxo32hyp_xkFd-ZEr7*Zdr*2 zZ>I8h6>izqpaE@ZPv2wPnVn{v|KaA!!f$TifK*9g5c<+m04d zOiE!+n&c&ZR@!sxvF$cMd8Z4IYiD-mZue%jFVpw5%CUIt=O4(9=1s@GoMYc=*&4aZ zONXyW?QcJJydyi@Pn}IGOqRSG%C<_*woJcV<;=W~`)l2q0U7+0T1sVyR+-g6_Rv~y z-t~Is{MTl}(Ufgj8_l)$ZOlCE`N!GE7Xs2HM!GSRyTs)$@Q((0neJLm=IB%FGaEf$ z&gSTWMZ4U5KstCL*L-rF*=YTe%{8B0taw_}ob7m2(ivs{nH*0;lTHosM+RR#L z-McZhF)od<(qvd-r=+PFiTe<+B}evAQ1nsfadBXX`i3CthAFv@&JI1Q>w4mC$yTgJ zbM(=?_l+OKG!1M%B+p=O9NCYHeky>AOVm|d1mNGJP>fUW;^M%BD)1V$Wg%)?3fk}a zZ20c*Y7Ys^|e+V@7j;n-ro z>}pv2@Cm&)+rQeGYkM_MA6YTU?)FW0SI*tFW?k=D-@88Xu;XEa6aX(pq-b1X6H?*> zQ1di3fVKUQ9K^*Sbq*JY&f^S+XNY=QRhvow&f$hF(9nc87)bE0r8hzkPv$*W7lt$E z7B4<++rQa%G}m@?-Mw-0@mrUrE7$UGy(e8~rLd51n}u9aW@s@b*ED6xUzUAdwn~0( z&DC_S#vj!jmu#YRQq04<=J?a&r#6rKbI1JuLRvE>MaJLELd3+a`2 zvUBSb($!F|2T7A$zKWMD{C~d)P{3i+bs*0ILVNP%2D@eQF?R4)Gus8>DZ literal 0 HcmV?d00001 diff --git a/__pycache__/multi_image_loader.cpython-312.pyc b/__pycache__/multi_image_loader.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9ba2190da6fd51d2b05d447be741687020e6db9d GIT binary patch literal 8446 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 VS6nk~`>M}IyS7?7=mTVd{{x6Fd{F=Z literal 0 HcmV?d00001 diff --git a/__pycache__/prompt_relay.cpython-312.pyc b/__pycache__/prompt_relay.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58e6490b1785632ac1be7ccc659ba35b9b128464 GIT binary patch literal 9764 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 literal 0 HcmV?d00001 diff --git a/__pycache__/speech_length_calculator.cpython-312.pyc b/__pycache__/speech_length_calculator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87b81722fc0a39f5ad9328815a2a64facd53e7c2 GIT binary patch literal 2748 zcmb6bOKcm*b!K<@*N2iU$x`BYMMqI+J4zZCN$e{ANwOkDrWA>a8%8d*+aA9ddAC6mWWSZ#K{Z0eYdr6k#Sg1nHsGjf#S{$*FIaq$C?H z&^}_{&YSnynfK+N8ynpSAUoqtq@4);l@oQ4YKz_HVX=k?A~=ac)i(}d0gWIcEF&V` z6RMISVG;YKZB7It)vYS7@zL&&fnGx@3Sojmf+`ZcjPBJWLlO}}HX?@XL<%{GE#xFl z;#kHZ*P`9;VjWW%RgJ{P)byMY8&r~!Y*H~aJ%SH>$N_5+p4}lpaAHgZA`)pshzi6; z?8Lz>64!Jv$;k2RZ z@}id2Wg5}r8AFb#y4o-ME-TkmnPzoWHZ(btHDsF6uBmBxUegJc<7pZvs(d}G87l4Z z`32@mWs^oc8BeRsLDZ-M6ca}S!R^Cv?rnaf?FB%7Nr#vqCZ^(PK*|D>sG(+7i7>{NsYgPz}8*weIB*R8Lr7}0?h2v>B zF>^=3m+B~A!vUSTdOaK0Rl=NFrmFH=8B-7pF(}-jOUdv{X2) z5tYtdi7CdAt|}=ys8QpEx-7MV7*1MI3`h3D*q>Qsp3%U>bTAxzXJUA2$@ibb-G4yF z1}C9E2b4z@C+hayKU6_z5WgwxAoT2*07Tbip?vtr-Iwnx55-U3+B!O3?3^e+d*VUc z!>Qur^wtY+7mr=paY$WFl?K#uWPRc8$p=!=|9bJ6vlUV3YT9XZdEFJ{a=CZmD?A)7 zcpX4?YnORxQkxG)btR>SBU(0Xur}p}sw;EqW1HTnLXCqvdMoHNZ`})Oxau9&^tkf^ z5q{G;@FQ3`o`Fc*6mE()o7Rvi{i4^{s{~Ur>J^9TwW+t8QsSVUn!S4U5q#}cxSL=~ zX>8)0&EU0UL4xPt6F>yhR=1q96EWd=LI6n9K7@YhhzN5iB3x}pDCaPEVp>3?Wn?;r z_G+Kty0ul|cBcdyImf-)eR59Inc&&{1k_KSa~Umlmg%Z%-D)a`1)oAX%o{x=#d+PTMXG(Bd6*=X9L(iEHqTPK=Fepi5@>?`m&-}CSO%y;#;-)GMB z!E&Y#)-!$PH~9^qzR7FwcL5Q z+#zqC+Uj_&FjDS(X0vtG+*{bfsIzYS96R&LDI z{Kq`|jgRU-0#VA#S(ayK!R0kLZ~0y4nYYyUKl+=O0sRx8AM)ty-WQ9#Kl!8klQW-P z34M0{-QsNG^V!VSY^F4;7jG53jfXDpYX)L$bL}?lhrJ-{!FrMAh>}yS&*}YVR$$zv$?x?OEFEp}SArzgBF% zSae?e{@Y$8PhcwtAGLO0JmvHYI&WzKzneM3;WVEsVdf5pQyR%8`MMz-zMfT*HI65e zR47fUMoc66)1b&2CWnL5lY#0i-J=2*E)P#J=cVbuU~qIiz?_2@g2N-@lkZq=x4Mdz zWz|sda@ING4}A&HGAi4=JA&Kh-W8F(rNUR0Zgl8We(dYEP=2i3+>?K!+r3SMr}QEo#NQ&0 HEyaHW0m9!D literal 0 HcmV?d00001 diff --git a/ltx_director.py b/ltx_director.py index 92d3b9a..c2f47be 100644 --- a/ltx_director.py +++ b/ltx_director.py @@ -1,8 +1,11 @@ +# --- START OF FILE ltx_director.py --- + import logging import json import base64 import io as _io import math +import time import numpy as np import torch @@ -31,6 +34,145 @@ log = logging.getLogger(__name__) GuideData = io.Custom("GUIDE_DATA") +def _format_timeline_to_text(global_prompt, duration_frames, frame_rate, epsilon, + custom_width, custom_height, resize_method, + timeline_data, local_prompts, segment_lengths, guide_strength): + lines = [] + lines.append("LTX Director Timeline Export") + lines.append("============================") + lines.append("") + lines.append("=== Global Parameters ===") + lines.append(f"Global Prompt:\n{global_prompt}\n") + + fr = float(frame_rate) if frame_rate else 24.0 + if fr <= 0: fr = 24.0 + + lines.append(f"Duration: {duration_frames} frames ({(duration_frames / fr):.2f}s @ {fr} FPS)") + lines.append(f"Epsilon (Penalty Decay): {epsilon}") + + if custom_width > 0 or custom_height > 0: + lines.append(f"Target Dimensions: {custom_width}x{custom_height} (Resize Method: {resize_method})") + else: + lines.append("Target Dimensions: Auto (Based on first image)") + + lines.append("") + lines.append("=== Timeline Segments ===") + + # --- 1. Text Prompts (Extracted from direct inputs) --- + locals_list = [p.strip() for p in local_prompts.split("|")] if local_prompts else [] + lengths_list = [l.strip() for l in segment_lengths.split(",")] if segment_lengths else [] + + if locals_list and any(locals_list): + lines.append("\n--- Text Prompts ---") + current_frame = 0.0 + for i, prompt in enumerate(locals_list): + try: + len_f = float(lengths_list[i]) if i < len(lengths_list) and lengths_list[i] else 0.0 + except ValueError: + len_f = 0.0 + + start_f = current_frame + end_f = start_f + len_f + + start_s = start_f / fr + end_s = end_f / fr + len_s = len_f / fr + + lines.append(f"\n[Prompt {i+1}]") + lines.append(f"Time: {start_s:.2f}s - {end_s:.2f}s (Duration: {len_s:.2f}s)") + lines.append(f"Frames: {start_f:.1f} - {end_f:.1f} (Length: {len_f:.1f})") + lines.append(f"Prompt:\n{prompt}") + lines.append("-" * 40) + + current_frame += len_f + + # --- 2. Images & Audio (Extracted from JSON) --- + try: + tdata = json.loads(timeline_data) if timeline_data else {} + segs = tdata.get("segments", []) + + img_segs = [s for s in segs if s.get("type", "image") == "image"] + img_segs.sort(key=lambda s: float(s.get("start", 0))) + if img_segs: + lines.append("\n--- Image Guides ---") + strengths = [float(x.strip()) for x in guide_strength.split(",")] if guide_strength and guide_strength.strip() else [] + for i, seg in enumerate(img_segs): + start_f = float(seg.get("start", 0)) + start_s = start_f / fr + strength = strengths[i] if i < len(strengths) else 1.0 + + lines.append(f"\n[Image {i+1}]") + lines.append(f"Time Inserted: {start_s:.2f}s (Frame {start_f:.1f})") + lines.append(f"Guide Strength: {strength}") + lines.append("-" * 40) + + audio_segs = [s for s in segs if s.get("type") == "audio"] + audio_segs.sort(key=lambda s: float(s.get("start", 0))) + if audio_segs: + lines.append("\n--- Audio Segments ---") + for i, seg in enumerate(audio_segs): + start_f = float(seg.get("start", 0)) + len_f = float(seg.get("length", 0)) + start_s = start_f / fr + len_s = len_f / fr + file_name = seg.get("fileName", "Unknown") + lines.append(f"\n[Audio {i+1}] {file_name}") + lines.append(f"Time: {start_s:.2f}s (Frame {start_f:.1f}) | Duration: {len_s:.2f}s") + lines.append("-" * 40) + + except Exception as e: + lines.append(f"\n[Note: Could not parse detailed timeline JSON for images/audio. Error: {e}]") + + return "\n".join(lines) + + +# Register API endpoint for instant export from the JS UI if needed +try: + import server + from aiohttp import web + + @server.PromptServer.instance.routes.post("/ltx_director/export_timeline") + async def export_timeline_endpoint(request): + try: + data = await request.json() + global_prompt = data.get("global_prompt", "") + timeline_data = data.get("timeline_data", "{}") + duration_frames = int(data.get("duration_frames", 0)) + frame_rate = float(data.get("frame_rate", 24)) + epsilon = float(data.get("epsilon", 0.001)) + custom_width = int(data.get("custom_width", 0)) + custom_height = int(data.get("custom_height", 0)) + resize_method = data.get("resize_method", "maintain aspect ratio") + local_prompts = data.get("local_prompts", "") + segment_lengths = data.get("segment_lengths", "") + guide_strength = data.get("guide_strength", "") + + formatted_text = _format_timeline_to_text( + global_prompt, duration_frames, frame_rate, epsilon, + custom_width, custom_height, resize_method, + timeline_data, local_prompts, segment_lengths, guide_strength + ) + + out_dir = folder_paths.get_output_directory() + filename = f"ltx_director_prompts_{int(time.time())}.txt" + filepath = os.path.join(out_dir, filename) + + with open(filepath, "w", encoding="utf-8") as f: + f.write(formatted_text) + + return web.json_response({ + "status": "success", + "filepath": filepath, + "filename": filename, + "content": formatted_text + }) + except Exception as e: + log.error(f"[PromptRelay] Export timeline endpoint error: {e}") + return web.json_response({"status": "error", "message": str(e)}, status=500) +except Exception as e: + log.warning(f"[PromptRelay] Could not register /ltx_director/export_timeline endpoint: {e}") + + def _load_image_tensor(seg: dict) -> torch.Tensor: """Decode an image from the ComfyUI input folder (if imageFile provided) or fallback to base64 to a ComfyUI-style image tensor of shape [1, H, W, 3], float32 in [0, 1].""" @@ -389,73 +531,27 @@ class LTXDirector(io.ComfyNode): io.Clip.Input("clip"), io.Vae.Input("audio_vae", optional=True, tooltip="Optional. Connect an Audio VAE to generate audio latents."), io.Latent.Input("optional_latent", optional=True, tooltip="Optional. Connect a latent to override the auto-generated one."), - io.String.Input( - "global_prompt", multiline=True, default="", - tooltip="Conditions the entire video. Anchors persistent characters, objects, and scene context.", - ), - io.Int.Input( - "duration_frames", default=120, min=1, max=10000, step=1, - tooltip="Total timeline length in pixel-space frames. Used by the editor for visual scale only.", - ), - io.Float.Input( - "duration_seconds", default=5, min=0.1, max=1000.0, step=0.01, - tooltip="Total timeline duration in seconds (computed/synced from frames).", - ), - io.String.Input( - "timeline_data", default="", - tooltip="JSON state of the timeline editor (auto-managed; do not edit by hand).", - ), - io.Boolean.Input( - "use_custom_audio", default=False, optional=True, - tooltip="Toggle between using timeline audio (ON) and generating audio from scratch (OFF).", - ), - io.String.Input( - "local_prompts", multiline=True, default="", - tooltip="Auto-populated from the timeline editor.", - ), - io.String.Input( - "segment_lengths", default="", - tooltip="Auto-populated from the timeline editor (pixel-space frame counts).", - ), - io.Float.Input( - "epsilon", default=0.001, min=0.0001, max=0.99, step=0.0001, - tooltip="Penalty decay parameter. Values below ~0.1 all produce sharp boundaries (paper default 0.001). For softer transitions, try 0.5 or higher.", - ), - io.Float.Input( - "frame_rate", default=24, min=1, max=240, step=1, optional=True, - tooltip="Frames per second — only affects how time is displayed in the timeline editor when time_units is set to 'seconds'.", - ), - io.Combo.Input( - "display_mode", options=["frames", "seconds"], default="seconds", optional=True, - tooltip="Display the ruler, segment ranges, length input, and total in frames or seconds. Internal storage is always pixel-space frames.", - ), - io.String.Input( - "guide_strength", default="", - tooltip="Auto-populated from the timeline editor (comma-separated guide strengths for image segments).", - ), - io.Int.Input( - "custom_width", default=0, min=0, max=8192, step=1, optional=True, - tooltip="Target output width for all image segments. Set to 0 to use the original image width.", - ), - io.Int.Input( - "custom_height", default=0, min=0, max=8192, step=1, optional=True, - tooltip="Target output height for all image segments. Set to 0 to use the original image height.", - ), - io.Combo.Input( - "resize_method", - options=["maintain aspect ratio", "stretch to fit", "pad", "crop"], - default="maintain aspect ratio", - optional=True, - tooltip="How to resize image segments to fit the target dimensions.", - ), - io.Int.Input( - "divisible_by", default=32, min=1, max=256, step=1, optional=True, - tooltip="Snap the final output image dimensions to be divisible by this number (e.g. 32 for LTX).", - ), - io.Int.Input( - "img_compression", default=18, min=0, max=100, step=1, optional=True, - tooltip="H.264 CRF compression to apply to each guide image. 0 = no compression, higher = more artefacts.", - ), + io.String.Input("global_prompt", multiline=True, default="", tooltip="Conditions the entire video. Anchors persistent characters, objects, and scene context."), + io.Int.Input("duration_frames", default=120, min=1, max=10000, step=1, tooltip="Total timeline length in pixel-space frames. Used by the editor for visual scale only."), + io.Float.Input("duration_seconds", default=5.0, min=0.1, max=1000.0, step=0.01, tooltip="Total timeline duration in seconds (computed/synced from frames)."), + io.String.Input("timeline_data", default="", tooltip="JSON state of the timeline editor (auto-managed; do not edit by hand)."), + io.Boolean.Input("use_custom_audio", default=False, tooltip="Toggle between using timeline audio (ON) and generating audio from scratch (OFF)."), + io.String.Input("local_prompts", multiline=True, default="", tooltip="Auto-populated from the timeline editor."), + io.String.Input("segment_lengths", default="", tooltip="Auto-populated from the timeline editor (pixel-space frame counts)."), + io.Float.Input("epsilon", default=0.001, min=0.0001, max=0.99, step=0.0001, tooltip="Penalty decay parameter. Values below ~0.1 all produce sharp boundaries (paper default 0.001). For softer transitions, try 0.5 or higher."), + io.Float.Input("frame_rate", default=24.0, min=1.0, max=240.0, step=1.0, tooltip="Frames per second — only affects how time is displayed in the timeline editor when time_units is set to 'seconds'."), + io.Combo.Input("display_mode", options=["frames", "seconds"], default="seconds", tooltip="Display the ruler, segment ranges, length input, and total in frames or seconds. Internal storage is always pixel-space frames."), + io.String.Input("guide_strength", default="", tooltip="Auto-populated from the timeline editor (comma-separated guide strengths for image segments)."), + io.Int.Input("custom_width", default=0, min=0, max=8192, step=1, tooltip="Target output width for all image segments. Set to 0 to use the original image width."), + io.Int.Input("custom_height", default=0, min=0, max=8192, step=1, tooltip="Target output height for all image segments. Set to 0 to use the original image height."), + io.Combo.Input("resize_method", options=["maintain aspect ratio", "stretch to fit", "pad", "crop"], default="maintain aspect ratio", tooltip="How to resize image segments to fit the target dimensions."), + io.Int.Input("divisible_by", default=32, min=1, max=256, step=1, tooltip="Snap the final output image dimensions to be divisible by this number (e.g. 32 for LTX)."), + io.Int.Input("img_compression", default=18, min=0, max=100, step=1, tooltip="H.264 CRF compression to apply to each guide image. 0 = no compression, higher = more artefacts."), + io.Boolean.Input("save_prompts_to_file", default=False, optional=True, tooltip="Save the timeline prompts and parameters to a text file in your ComfyUI output directory during execution."), + io.Image.Input("reference_image", optional=True, tooltip="Invisible character sheet/style reference. Can also be a Batch of images. Automatically appended to the sequence out-of-bounds."), + io.Image.Input("reference_image_2", optional=True, tooltip="Second optional reference image."), + io.Image.Input("reference_image_3", optional=True, tooltip="Third optional reference image."), + io.Float.Input("reference_strength", default=1.0, min=0.0, max=5.0, step=0.05, optional=True, tooltip="Guide strength for the reference images."), ], outputs=[ io.Model.Output(display_name="model"), @@ -465,20 +561,35 @@ class LTXDirector(io.ComfyNode): GuideData.Output(display_name="guide_data"), io.Float.Output(display_name="frame_rate", tooltip="The frame rate used for the timeline."), io.Audio.Output(display_name="combined_audio", tooltip="Combined timeline audio layout."), + io.Int.Output(display_name="clean_latent_frames", tooltip="Plug this into a CleanLatentSlice node 'length' to effortlessly cut off the invisible reference image."), + io.Int.Output(display_name="clean_pixel_frames", tooltip="Plug this into your Video Combine 'frame_load_cap' to effortlessly cut off the invisible reference image."), ], ) @classmethod def execute(cls, model, clip, global_prompt, duration_frames, duration_seconds, timeline_data, local_prompts, segment_lengths, guide_strength="", epsilon=1e-3, - frame_rate=24, display_mode="seconds", + frame_rate=24.0, display_mode="seconds", custom_width=768, custom_height=512, resize_method="maintain aspect ratio", divisible_by=32, img_compression=0, audio_vae=None, optional_latent=None, - use_custom_audio=False) -> io.NodeOutput: + use_custom_audio=False, save_prompts_to_file=False, + reference_image=None, reference_image_2=None, reference_image_3=None, reference_strength=1.0) -> io.NodeOutput: + + # --- Calculate Clean Output Bounds First --- + clean_pixel_frames = duration_frames + 1 + clean_latent_frames = ((clean_pixel_frames - 1) // 8) + 1 # --- Build guide_data from image segments FIRST (to derive output dimensions) --- - guide_data = {"images": [], "insert_frames": [], "strengths": [], "frame_rate": frame_rate} + guide_data = {"images": [], "insert_frames": [], "strengths": [], "frame_rate": float(frame_rate)} derived_w, derived_h = custom_width, custom_height + + # Consolidate all reference inputs into a flat list, unraveling any image batches. + refs_to_process = [] + for ref_input in (reference_image, reference_image_2, reference_image_3): + if ref_input is not None: + for i in range(ref_input.shape[0]): + refs_to_process.append(ref_input[i:i+1]) + try: tdata = json.loads(timeline_data) if timeline_data else {} img_segs = [ @@ -536,7 +647,7 @@ class LTXDirector(io.ComfyNode): # If no images were loaded from the timeline, create a dummy image at strength 0 # to prevent artifacts in text-to-video mode. - if not guide_data["images"]: + if not guide_data["images"] and not refs_to_process: w = derived_w if derived_w > 0 else 768 h = derived_h if derived_h > 0 else 512 w = (w // 32) * 32 @@ -552,21 +663,60 @@ class LTXDirector(io.ComfyNode): except Exception as e: log.warning("[PromptRelay] Could not build guide_data: %s", e) - # --- Auto-generate LTXV latent if none was provided --- - ltxv_length = duration_frames + 1 + # --- Handle Reference Image Injection --- + if refs_to_process: + if optional_latent is not None: + log.warning("[PromptRelay] You connected reference images AND an external 'optional_latent'. Make sure your custom latent is long enough to fit the appended reference frames!") + + for i, single_ref in enumerate(refs_to_process): + src_h, src_w = single_ref.shape[1], single_ref.shape[2] + def snap(val, div): return max(div, (val // div) * div) + + if custom_width > 0 and custom_height > 0: + ref_tensor = _resize_image(single_ref, custom_width, custom_height, resize_method, divisible_by) + elif custom_width > 0: + tgt_w = snap(custom_width, divisible_by) + tgt_h = snap(int(src_h * tgt_w / src_w), divisible_by) + ref_tensor = _resize_image(single_ref, tgt_w, tgt_h, "stretch to fit", divisible_by) + elif custom_height > 0: + tgt_h = snap(custom_height, divisible_by) + tgt_w = snap(int(src_w * tgt_h / src_h), divisible_by) + ref_tensor = _resize_image(single_ref, tgt_w, tgt_h, "stretch to fit", divisible_by) + else: + ref_tensor = _resize_image(single_ref, src_w, src_h, "maintain aspect ratio", divisible_by) + + if img_compression > 0: + ref_tensor = _compress_image(ref_tensor, img_compression) + + guide_data["images"].append(ref_tensor) + + # Insert safely in the "hidden" padded latent blocks + # We place each ref 8 frames apart so they each get their own pure latent block. + insert_point = (clean_latent_frames + i) * 8 + guide_data["insert_frames"].append(insert_point) + guide_data["strengths"].append(float(reference_strength)) + + # Record dimensions for empty latent generation from the FIRST reference image if none exist + if derived_w <= 0 or derived_h <= 0: + derived_w = ref_tensor.shape[2] + derived_h = ref_tensor.shape[1] + + # --- Auto-generate LTXV latent --- + total_latents = clean_latent_frames + len(refs_to_process) + ltxv_length = ((total_latents - 1) * 8) + 1 # Map back to pixel frames for the empty latent logic + if optional_latent is None: latent_w = max(32, (derived_w // 32) * 32) latent_h = max(32, (derived_h // 32) * 32) - # LTXV temporal: ((length - 1) // 8) + 1 latent frames; invert to get pixel frames -> length - latent_t = ((ltxv_length - 1) // 8) + 1 + samples = torch.zeros( - [1, 128, latent_t, latent_h // 32, latent_w // 32], + [1, 128, total_latents, latent_h // 32, latent_w // 32], device=comfy.model_management.intermediate_device(), ) latent = {"samples": samples} log.info( - "[PromptRelay] Auto-generated LTXV latent: %dx%d, %d pixel frames (%d latent frames)", - latent_w, latent_h, ltxv_length, latent_t, + "[PromptRelay] Auto-generated LTXV latent: %dx%d, %d pixel frames (%d latent frames, %d refs hidden)", + latent_w, latent_h, ltxv_length, total_latents, len(refs_to_process) ) else: latent = optional_latent @@ -582,7 +732,6 @@ class LTXDirector(io.ComfyNode): audio_latent = {} if audio_vae is not None: - # Helper to generate empty latent def get_empty_latent(): # Support both raw AudioVAE objects and ComfyUI VAE wrappers. inner = getattr(audio_vae, "first_stage_model", audio_vae) @@ -598,17 +747,12 @@ class LTXDirector(io.ComfyNode): if use_custom_audio: try: if audio_out is not None: - # 1. Encode audio waveform into latent space waveform = audio_out["waveform"] if waveform.ndim == 2: waveform = waveform.unsqueeze(0) if waveform.ndim != 3: - raise ValueError( - f"Expected custom audio waveform with 2 or 3 dims, got shape {tuple(waveform.shape)}" - ) + raise ValueError(f"Expected custom audio waveform with 2 or 3 dims, got shape {tuple(waveform.shape)}") - # Wrapped ComfyUI VAE expects (batch, samples, channels); - # raw AudioVAE expects a dict with waveform in (batch, channels, samples). if hasattr(audio_vae, "first_stage_model"): latent_samples = audio_vae.encode(waveform.movedim(1, -1)) else: @@ -620,7 +764,6 @@ class LTXDirector(io.ComfyNode): if latent_samples.numel() == 0: raise ValueError("Encoded audio latent is empty (0 elements).") - # 2. Create solid mask with value 0.0 (0 means keep/use conditioning, 1 means generate noise) mask = torch.full( (1, latent_samples.shape[-2], latent_samples.shape[-1]), 0.0, @@ -628,7 +771,6 @@ class LTXDirector(io.ComfyNode): device=comfy.model_management.intermediate_device() ) - # 3. Set Latent Noise Mask audio_latent = { "samples": latent_samples, "type": "audio", @@ -641,7 +783,6 @@ class LTXDirector(io.ComfyNode): log.error("[PromptRelay] Failed to generate custom audio latent: %s", e) raise e else: - # Generate empty latent try: audio_latent = get_empty_latent() log.info("[PromptRelay] Auto-generated empty audio latent.") @@ -649,7 +790,34 @@ class LTXDirector(io.ComfyNode): log.error("[PromptRelay] Could not generate empty audio latent: %s", e) raise e - return io.NodeOutput(patched, conditioning, latent, audio_latent, guide_data, float(frame_rate), audio_out) + # --- Save formatted Prompts logic --- + if save_prompts_to_file: + try: + formatted_text = _format_timeline_to_text( + global_prompt, duration_frames, float(frame_rate), epsilon, + custom_width, custom_height, resize_method, + timeline_data, local_prompts, segment_lengths, guide_strength + ) + out_dir = folder_paths.get_output_directory() + filename = f"ltx_director_prompts_{int(time.time())}.txt" + filepath = os.path.join(out_dir, filename) + with open(filepath, "w", encoding="utf-8") as f: + f.write(formatted_text) + log.info(f"[PromptRelay] Saved timeline prompts to {filepath}") + except Exception as e: + log.warning(f"[PromptRelay] Failed to save prompts to txt: {e}") + + return io.NodeOutput( + patched, + conditioning, + latent, + audio_latent, + guide_data, + float(frame_rate), + audio_out, + clean_latent_frames, + clean_pixel_frames + ) NODE_CLASS_MAPPINGS = { diff --git a/ltx_sequencer.py b/ltx_sequencer.py index 2a440ef..791c662 100644 --- a/ltx_sequencer.py +++ b/ltx_sequencer.py @@ -1,3 +1,4 @@ +import json from comfy_extras.nodes_lt import get_noise_mask, LTXVAddGuide import torch import comfy.utils @@ -55,12 +56,14 @@ class LTXSequencer(LTXVAddGuide): node_id="LTXSequencer", display_name="LTX Sequencer", category="WhatDreamsCost", - description="Add multiple guide images at specified frame indices or seconds with strengths. Number of widgets is dynamically configured.", + description="Add multiple guide images at specified frame indices or seconds. Auto-syncs to Prompt Relay invisibly via the positive wire.", inputs=inputs, outputs=[ io.Conditioning.Output(display_name="positive"), io.Conditioning.Output(display_name="negative"), io.Latent.Output(display_name="latent", tooltip="Video latent with added guides"), + # ---> ADDED SYNC LOG OUTPUT <--- + io.String.Output(display_name="sync_log", tooltip="Outputs a readable text block showing the actual times used for each image"), ], ) @@ -89,29 +92,63 @@ class LTXSequencer(LTXVAddGuide): insert_mode = kwargs.get("insert_mode", "frames") frame_rate = kwargs.get("frame_rate", 24) + # ---> EXTRACT GHOST SYNC DATA <--- + timeline_data = None + if positive is not None and len(positive) > 0: + if "prompt_relay_timeline" in positive[0][1]: + try: + timeline_data = json.loads(positive[0][1]["prompt_relay_timeline"]) + except json.JSONDecodeError: + pass + + # Prepare the log text + sync_log_lines = [] + if timeline_data: + sync_log_lines.append("=== TIMELINE SYNC ENABLED ===") + sync_log_lines.append(f"Invisibly Synced via Positive Wire! Using {insert_mode.upper()}:") + else: + sync_log_lines.append("=== MANUAL MODE ===") + sync_log_lines.append(f"No timeline detected, or Sync turned OFF. Using manual UI inputs ({insert_mode}):") + # Process inputs up to num_images, extracting dynamic frame/strength values from kwargs for i in range(1, num_images + 1): # Skip if this image index exceeds the batch if i > batch_size: + sync_log_lines.append(f"Image #{i}: Skipped (No image loaded in batch)") continue img = multi_input[i-1:i] # Extract the single image frame from the batch if img is None: continue - # Calculate the final frame index based on the chosen mode f_idx = None - if insert_mode == "frames": - f_idx = kwargs.get(f"insert_frame_{i}") - elif insert_mode == "seconds": - sec = kwargs.get(f"insert_second_{i}") - if sec is not None: - f_idx = int(sec * frame_rate) + strength = kwargs.get(f"strength_{i}", 1.0) + + # 1. AUTO-SYNC + if timeline_data and "starts_frames" in timeline_data and (i - 1) < len(timeline_data["starts_frames"]): + display_frame = timeline_data["starts_frames"][i - 1] + display_sec = timeline_data["starts_seconds"][i - 1] + + if insert_mode == "frames": + f_idx = display_frame + sync_log_lines.append(f"-> Image #{i} (Strength: {strength}): Synced to Segment #{i} start @ {display_frame} frames") + elif insert_mode == "seconds": + f_idx = int(display_sec * frame_rate) + sync_log_lines.append(f"-> Image #{i} (Strength: {strength}): Synced to Segment #{i} start @ {display_sec:.2f} seconds (Frame {f_idx})") + + # 2. MANUAL FALLBACK + else: + if insert_mode == "frames": + f_idx = kwargs.get(f"insert_frame_{i}") + sync_log_lines.append(f"-> Image #{i} (Strength: {strength}): Manual input @ {f_idx} frames") + elif insert_mode == "seconds": + sec = kwargs.get(f"insert_second_{i}") + if sec is not None: + f_idx = int(sec * frame_rate) + sync_log_lines.append(f"-> Image #{i} (Strength: {strength}): Manual input @ {sec:.2f} seconds (Frame {f_idx})") if f_idx is None: continue - - strength = kwargs.get(f"strength_{i}", 1.0) # Execution logic mirrored from LTXVAddGuideMulti image_1, t = cls.encode(vae, latent_width, latent_height, img, scale_factors) @@ -130,4 +167,8 @@ class LTXSequencer(LTXVAddGuide): scale_factors, ) - return io.NodeOutput(positive, negative, {"samples": latent_image, "noise_mask": noise_mask}) \ No newline at end of file + sync_log_str = "\n".join(sync_log_lines) + print(f"\n[LTX Sequencer]\n{sync_log_str}\n") + + # Returned the newly formatted sync log string at the end of NodeOutput + return io.NodeOutput(positive, negative, {"samples": latent_image, "noise_mask": noise_mask}, sync_log_str) \ No newline at end of file