From bb703951d50e557cdb715d3d1df81bfa5f3bc7aa Mon Sep 17 00:00:00 2001 From: Meisoftcoltd <38667978+Meisoftcoltd@users.noreply.github.com> Date: Sun, 29 Mar 2026 16:08:21 +0000 Subject: [PATCH] feat: Implement lazy evaluation Cycle 0 architecture - Introduced global state memory (`global_source_frame_count`, `global_target_frames`, `global_stride`) in `loop.py`. - Removed visual `source_frame_count` wire from `AutoLoopCalculator` in `video.py` - Upgraded `AutoLoopCalculator` to execute as a blind "Explorer" in Cycle 0. - Updated `LoadVideoWithSourceAudio` to intercept real `source_frame_count` directly from VHS payloads. - Added dynamic calculation of total cycles based on intercepted frames at the end of Cycle 0. --- __pycache__/__init__.cpython-312.pyc | Bin 0 -> 1374 bytes __pycache__/image.cpython-312.pyc | Bin 0 -> 6308 bytes __pycache__/loop.cpython-312.pyc | Bin 0 -> 5706 bytes __pycache__/video.cpython-312.pyc | Bin 0 -> 9834 bytes loop.py | 5 ++ .../test_batch.cpython-312-pytest-9.0.2.pyc | Bin 0 -> 3971 bytes tests/test_batch.py | 73 ----------------- video.py | 77 ++++++++++++------ 8 files changed, 57 insertions(+), 98 deletions(-) create mode 100644 __pycache__/__init__.cpython-312.pyc create mode 100644 __pycache__/image.cpython-312.pyc create mode 100644 __pycache__/loop.cpython-312.pyc create mode 100644 __pycache__/video.cpython-312.pyc create mode 100644 tests/__pycache__/test_batch.cpython-312-pytest-9.0.2.pyc delete mode 100644 tests/test_batch.py diff --git a/__pycache__/__init__.cpython-312.pyc b/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ddf9de0dd71c528d358d46ad4c8c4ddb4cb67c1 GIT binary patch literal 1374 zcmah}&u<(x6t;I~car^)goM&0ZBs81&;ex|4n4Fgg;f)^Tct~y2}GTXHLRVjtJ#^Y z$5S;?4r#@S13hqPf)Ke-Ar$_AmJ4UZWdo5|SsW^H;zS@wNSv@|cbXIxVad2Ss5|>)ftGNd6z_0+d&gU>hA)!AXk23%pSgG3TE3=#j{2U4eXMO`M2a!(@^Fu*h zf`VlvqLxR?mML>A)Na?WQ(0J;U3_n$h8M5T&)PDrVxPKdm8;4%QhRr17GIpJ*fzde znV+xLF4?jVW8ZC3jOBO?&s6RCxyp5{L!Pp%l!SFzAS`To?n)dG>SiPK_t0s#)jEwa z^O?Z7+**-EP8&=~<=77hXHb@qp;OOLL7>pXULjfst0TdSL^JI3psd}00azB&c`s_%@I zmKoM`8&n!z5VU0GHX}5Mjwxtw>ywAbreVkeA5}F6Ezmk;w<(Xty7(9W!fooSVxm%v ze*F1wkM5(YU+1(*ec^hj5{Y2S7EIJ{DAq)m^$^Vk>V>_p&qZ$_JBWClDk@`qlM@QoX_wRNATew`HQ&pwlj@3*4>3SDi{S;Rm((VQ4|}^6$*?G@_4^87OYu0na5alUcU^C53u;=NWh0QS^s4Cure|mwTLUIG%?fceOHYoU?TnvMj?xV5pm(~@$Io<5y!HE7aWeHMD8lsK1Spi+FJEZq-o9(b G0{#JiQf)H; literal 0 HcmV?d00001 diff --git a/__pycache__/image.cpython-312.pyc b/__pycache__/image.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0eec31289391d3be794b5c4fb0b26730c782d490 GIT binary patch literal 6308 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 DVjs81 literal 0 HcmV?d00001 diff --git a/__pycache__/loop.cpython-312.pyc b/__pycache__/loop.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..825b82b06de79d8d3a19c4e2893f19974e079060 GIT binary patch literal 5706 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 spr&)|;^uV{s=w7;Cdnha1j;jg_yPQ(2 0: Matemática proporcional para el resto del vídeo + effective_total = math.ceil(source_frames / select_every_nth) + + if effective_total <= target_frames_per_loop: + return (target_frames_per_loop, 0, select_every_nth) + + remaining_effective = effective_total - target_frames_per_loop + remaining_loops = math.ceil(remaining_effective / target_frames_per_loop) + + base_frames = remaining_effective // remaining_loops + remainder = remaining_effective % remaining_loops + + plan = [target_frames_per_loop] # El Ciclo 0 ya se llevó su parte + for i in range(remaining_loops): plan.append(base_frames + (1 if i < remainder else 0)) - safe_index = min(current_loop_index, total_loops - 1) + safe_index = min(current_loop_index, len(plan) - 1) chunk_frames = plan[safe_index] - # 3. Calcular el salto de frames originales - # Sumamos los frames efectivos de ciclos anteriores y los multiplicamos por el salto effective_skip = sum(plan[:safe_index]) skip_frames = effective_skip * select_every_nth - # Guardamos en la memoria fantasma - loop.global_total_loops = total_loops - - print(f"\n📊 [Auto Calculator] Video Original: {source_frame_count} frames | Stride: {select_every_nth}") - print(f" -> Frames efectivos a procesar: {effective_source_frames}") - print(f" -> Planificando {total_loops} ciclos: {plan}") - print(f" -> 🚀 Ciclo {current_loop_index}: Cargando {chunk_frames} frames (Saltando {skip_frames} frames de origen)") + print(f"\n📊 [Auto Calculator] Video Original: {source_frames} frames | Efectivos: {effective_total}") + print(f" -> Plan maestro: {plan}") + print(f" -> 🚀 Ciclo {current_loop_index}: Cargando {chunk_frames} frames (Saltando {skip_frames})") return (chunk_frames, skip_frames, select_every_nth) @@ -109,6 +112,30 @@ class LoadVideoWithSourceAudio: res = list(vhs_output) ui = {} + # 🎯 NUEVO: INTERCEPTACIÓN DEL TOTAL DE FRAMES + video_info_dict = res[3] if len(res) > 3 else {} + source_frame_count = video_info_dict.get("source_frame_count", 0) if isinstance(video_info_dict, dict) else 0 + + if source_frame_count > 0: + from . import loop + import math + loop.global_source_frame_count = source_frame_count + + # Solo fijamos el número total de ciclos durante el Ciclo 0 + if loop.global_loop_index == 0: + target = loop.global_target_frames + stride = loop.global_stride + eff_total = math.ceil(source_frame_count / stride) + + if eff_total <= target: + loop.global_total_loops = 1 + else: + remaining = eff_total - target + rem_loops = math.ceil(remaining / target) + loop.global_total_loops = 1 + rem_loops + + print(f"🎥 [Video Loader] Interceptado: {source_frame_count} frames. Total Loops fijado en: {loop.global_total_loops}") + raw_video = kwargs.get("video") video_name = raw_video[0] if isinstance(raw_video, (list, tuple)) else raw_video video_path = folder_paths.get_annotated_filepath(video_name) if video_name else ""