goldberg124 FuzzPuppy commited on
Commit
0e89ed3
·
0 Parent(s):

Duplicate from FuzzPuppy/LTX-2.3-Foley-Workflow

Browse files

Co-authored-by: FuzzPuppy <FuzzPuppy@users.noreply.huggingface.co>

.gitattributes ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tennis-no-sound.mp4 filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - comfyui
5
+ - ltx-video
6
+ - ltx-2.3
7
+ - foley
8
+ - video-to-audio
9
+ - audio-generation
10
+ - workflow
11
+ ---
12
+
13
+ # LTX 2.3 Foley V2A ComfyUI Workflow
14
+
15
+ This repository contains a ready-to-test ComfyUI workflow for the
16
+ [`FuzzPuppy/LTX-2.3-Foley-LoRA`](https://huggingface.co/FuzzPuppy/LTX-2.3-Foley-LoRA)
17
+ LoRA. The LoRA adds Foley sound effects to a silent input video using LTX-2.3:
18
+ given a short video and a prompt describing the visible action, the workflow
19
+ generates matching non-speech, non-music sound effects and saves a new MP4.
20
+
21
+ The workflow is intentionally small: it takes one short video clip, keeps the
22
+ first `89` frames, generates matching Foley audio, and saves an MP4 with the
23
+ source frames plus generated audio. It is meant as the fastest public ComfyUI
24
+ test for `FuzzPuppy/LTX-2.3-Foley-LoRA`, not as a full long-video stitching
25
+ pipeline.
26
+
27
+ ## Tutorial
28
+
29
+ [![Watch the tutorial: using the LTX-2.3 Foley LoRA in ComfyUI](https://img.youtube.com/vi/qnHFDlrySmw/hqdefault.jpg)](https://youtu.be/qnHFDlrySmw)
30
+
31
+ [Watch the tutorial on YouTube](https://youtu.be/qnHFDlrySmw)
32
+
33
+ ## What Is Included
34
+
35
+ - `ltx_23_foley_v2a.json`: ComfyUI workflow.
36
+ - `setup_runpod_ltx_foley.sh`: one-command RunPod setup script.
37
+ - `ltx_foley_v2a`: small helper-node package.
38
+ - `tennis-no-sound.mp4`: default silent test video for RunPod setup.
39
+
40
+ The helper-node package handles the workflow-specific pieces that stock ComfyUI
41
+ does not currently cover cleanly:
42
+
43
+ - freezes the uploaded video as LTX video latents while leaving matching audio
44
+ latents empty for Foley generation
45
+ - trims or pads the saved video frames to the same generation window
46
+ - decodes LTX audio VAE output into the Comfy audio tensor layout expected by
47
+ current video saving nodes
48
+
49
+ Prompt text, model loading, LoRA loading, sampling, video creation, and MP4
50
+ saving use normal ComfyUI/LTXVideo nodes.
51
+
52
+ ## Fastest RunPod Test
53
+
54
+ Use the official RunPod **ComfyUI - CUDA 12.8** template:
55
+
56
+ https://console.runpod.io/deploy?template=cw3nka7d08&ref=k7b1cgii
57
+
58
+
59
+ 1. In RunPod, under "Additional Filters" filter CUDA versions to CUDA 12.8.
60
+ 2. Select a 48 GB GPU: A40, RTX A6000, L40/L40S, or A100.
61
+ 3. Make sure the `ComfyUI - CUDA 12.8` template is selected.
62
+ 4. The template's default volume disk is `50 GB`, which is enough for the core
63
+ workflow files, but tight once caches and reruns accumulate. Change the volume
64
+ disk to `100 GB` if you want more breathing room.
65
+ 5. Start the pod and open a terminal.
66
+ 6. Run:
67
+
68
+ ```bash
69
+ cd /workspace && curl -L https://huggingface.co/FuzzPuppy/LTX-2.3-Foley-Workflow/resolve/main/setup_runpod_ltx_foley.sh -o setup_runpod_ltx_foley.sh && bash setup_runpod_ltx_foley.sh
70
+ ```
71
+
72
+ The setup script installs the nodes and models, downloads the tennis test video
73
+ as `input.mp4`, restarts ComfyUI without stopping the pod, and waits until the UI
74
+ responds on port `8188`.
75
+
76
+ After the script finishes:
77
+
78
+ 1. Open ComfyUI from the RunPod web UI.
79
+ 2. Under workflows, select `ltx_23_foley_v2a.json`.
80
+ 3. Hit `Run`.
81
+
82
+ The default input video and prompt are already set:
83
+
84
+ ```text
85
+ Two men are playing tennis. No speech is present. No music is present.
86
+ ```
87
+
88
+ ## What The Script Installs
89
+
90
+ The script assumes the official CUDA 12.8 template layout from
91
+ `runpod-workers/comfyui-base`:
92
+
93
+ - ComfyUI: `/workspace/runpod-slim/ComfyUI`
94
+ - Python environment: `/workspace/runpod-slim/ComfyUI/.venv-cu128`
95
+ - ComfyUI port: `8188`
96
+
97
+ It installs or refreshes:
98
+
99
+ - `Lightricks/ComfyUI-LTXVideo`
100
+ - `ltx_foley_v2a` helper nodes
101
+ - `ltx_23_foley_v2a.json`
102
+ - `tennis-no-sound.mp4`
103
+
104
+ It downloads these model files:
105
+
106
+ - Base checkpoint:
107
+ [`Lightricks/LTX-2.3-fp8/ltx-2.3-22b-dev-fp8.safetensors`](https://huggingface.co/Lightricks/LTX-2.3-fp8/blob/main/ltx-2.3-22b-dev-fp8.safetensors)
108
+ - Text encoder:
109
+ [`Comfy-Org/ltx-2/split_files/text_encoders/gemma_3_12B_it_fp8_scaled.safetensors`](https://huggingface.co/Comfy-Org/ltx-2/blob/main/split_files/text_encoders/gemma_3_12B_it_fp8_scaled.safetensors)
110
+ - Foley LoRA:
111
+ [`FuzzPuppy/LTX-2.3-Foley-LoRA/ltx-2.3-foley-400-steps.safetensors`](https://huggingface.co/FuzzPuppy/LTX-2.3-Foley-LoRA/blob/main/ltx-2.3-foley-400-steps.safetensors)
112
+
113
+ Large model downloads are SHA-256 verified. Completed files are skipped on
114
+ rerun, interrupted downloads resume from `*.part` files, and corrupt partials
115
+ are retried once from scratch.
116
+
117
+ ## Manual ComfyUI Install
118
+
119
+ If you are not using the RunPod script:
120
+
121
+ 1. Install or update ComfyUI.
122
+ 2. Install the official LTXVideo custom nodes:
123
+ `https://github.com/Lightricks/ComfyUI-LTXVideo`
124
+ 3. Copy or symlink `ltx_foley_v2a` into:
125
+ `ComfyUI/custom_nodes/ltx_foley_v2a`
126
+ 4. Put the model files in:
127
+ - checkpoint:
128
+ [`ltx-2.3-22b-dev-fp8.safetensors`](https://huggingface.co/Lightricks/LTX-2.3-fp8/blob/main/ltx-2.3-22b-dev-fp8.safetensors)
129
+ in `ComfyUI/models/checkpoints`
130
+ - text encoder:
131
+ [`gemma_3_12B_it_fp8_scaled.safetensors`](https://huggingface.co/Comfy-Org/ltx-2/blob/main/split_files/text_encoders/gemma_3_12B_it_fp8_scaled.safetensors)
132
+ in `ComfyUI/models/text_encoders`
133
+ - Foley LoRA:
134
+ [`ltx-2.3-foley-400-steps.safetensors`](https://huggingface.co/FuzzPuppy/LTX-2.3-Foley-LoRA/blob/main/ltx-2.3-foley-400-steps.safetensors)
135
+ in `ComfyUI/models/loras`
136
+ 5. Restart ComfyUI.
137
+ 6. Under workflows, select `ltx_23_foley_v2a.json`.
138
+ 7. Hit `Run`.
139
+
140
+ ## Workflow Defaults
141
+
142
+ - Input video: `input.mp4`
143
+ - Prompt: `Two men are playing tennis. No speech is present. No music is present.`
144
+ - Negative prompt: anti-music/anti-vocal prompt
145
+ - Conditioning size: `576x576`
146
+ - Frame window: `89` frames
147
+ - Sampling steps: `30`
148
+ - Guidance: `4.0`
149
+ - STG blocks: `14, 19`
150
+ - LoRA strength: `1.0`
151
+
152
+ The workflow uses the first `89` frames of the uploaded video. Shorter videos are
153
+ padded by repeating the last frame. The saved video is trimmed or padded to the
154
+ same frame count so the output video duration matches the generated audio.
155
+
156
+ ## VRAM Notes
157
+
158
+ Sampling is the VRAM peak. Start with a 48 GB GPU for the first reliable test.
159
+ If you need to reduce memory use, try these changes in order:
160
+
161
+ - reduce frames from `89` to `57`, `41`, or `25`
162
+ - reduce conditioning size from `576x576` to `448x448` or `384x384`
163
+ - reduce sampling steps from `30` to `20`
164
+ - lower or disable STG if quality is acceptable
165
+
166
+ Frame counts should stay one more than a multiple of 8:
167
+
168
+ ```text
169
+ 9, 17, 25, 33, 41, 49, 57, ..., 89, ..., 257
170
+ ```
171
+
172
+ ## Troubleshooting RunPod Setup
173
+
174
+ If you rerun setup after a workflow or node update:
175
+
176
+ ```bash
177
+ cd /workspace && bash setup_runpod_ltx_foley.sh
178
+ ```
179
+
180
+ The script will skip verified model files, refresh the workflow/helper nodes,
181
+ and restart ComfyUI.
182
+
183
+ If model downloads fail with authorization errors, accept the relevant Hugging
184
+ Face model terms and rerun with `HF_TOKEN` set.
185
+
186
+ Logs from the script-managed ComfyUI restart are written to:
187
+
188
+ ```text
189
+ /workspace/runpod-slim/comfyui-restart.log
190
+ ```
191
+
192
+ ## License Scope
193
+
194
+ The files in this workflow repository are released under the Apache-2.0 license.
195
+ That applies to the workflow JSON, setup script, helper-node code, README/model
196
+ card text, and bundled test assets in this repository.
197
+
198
+ This workflow downloads and uses third-party model files that are governed by
199
+ their own licenses and terms, including LTX-2.3, the Gemma text encoder, and the
200
+ `FuzzPuppy/LTX-2.3-Foley-LoRA` weights.
ltx_23_foley_v2a.json ADDED
@@ -0,0 +1,1275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "last_node_id": 22,
3
+ "last_link_id": 38,
4
+ "nodes": [
5
+ {
6
+ "id": 1,
7
+ "type": "LoadVideo",
8
+ "pos": [
9
+ -1280,
10
+ -160
11
+ ],
12
+ "size": [
13
+ 320,
14
+ 90
15
+ ],
16
+ "flags": {},
17
+ "order": 0,
18
+ "mode": 0,
19
+ "inputs": [],
20
+ "outputs": [
21
+ {
22
+ "name": "video",
23
+ "type": "VIDEO",
24
+ "links": [
25
+ 1
26
+ ]
27
+ }
28
+ ],
29
+ "properties": {
30
+ "Node name for S&R": "LoadVideo"
31
+ },
32
+ "widgets_values": [
33
+ "input.mp4"
34
+ ]
35
+ },
36
+ {
37
+ "id": 2,
38
+ "type": "GetVideoComponents",
39
+ "pos": [
40
+ -920,
41
+ -160
42
+ ],
43
+ "size": [
44
+ 220,
45
+ 120
46
+ ],
47
+ "flags": {},
48
+ "order": 1,
49
+ "mode": 0,
50
+ "inputs": [
51
+ {
52
+ "name": "video",
53
+ "type": "VIDEO",
54
+ "link": 1
55
+ }
56
+ ],
57
+ "outputs": [
58
+ {
59
+ "name": "images",
60
+ "type": "IMAGE",
61
+ "links": [
62
+ 2,
63
+ 29
64
+ ]
65
+ },
66
+ {
67
+ "name": "audio",
68
+ "type": "AUDIO",
69
+ "links": null
70
+ },
71
+ {
72
+ "name": "fps",
73
+ "type": "FLOAT",
74
+ "links": [
75
+ 3,
76
+ 30
77
+ ]
78
+ },
79
+ {
80
+ "name": "bit_depth",
81
+ "type": "INT",
82
+ "links": null
83
+ }
84
+ ],
85
+ "properties": {
86
+ "Node name for S&R": "GetVideoComponents"
87
+ },
88
+ "widgets_values": []
89
+ },
90
+ {
91
+ "id": 3,
92
+ "type": "CheckpointLoaderSimple",
93
+ "pos": [
94
+ -1280,
95
+ 120
96
+ ],
97
+ "size": [
98
+ 360,
99
+ 110
100
+ ],
101
+ "flags": {},
102
+ "order": 2,
103
+ "mode": 0,
104
+ "inputs": [],
105
+ "outputs": [
106
+ {
107
+ "name": "MODEL",
108
+ "type": "MODEL",
109
+ "links": [
110
+ 6
111
+ ]
112
+ },
113
+ {
114
+ "name": "CLIP",
115
+ "type": "CLIP",
116
+ "links": null
117
+ },
118
+ {
119
+ "name": "VAE",
120
+ "type": "VAE",
121
+ "links": [
122
+ 7
123
+ ]
124
+ }
125
+ ],
126
+ "properties": {
127
+ "Node name for S&R": "CheckpointLoaderSimple"
128
+ },
129
+ "widgets_values": [
130
+ "ltx-2.3-22b-dev-fp8.safetensors"
131
+ ]
132
+ },
133
+ {
134
+ "id": 4,
135
+ "type": "LTXVAudioVAELoader",
136
+ "pos": [
137
+ -1280,
138
+ 280
139
+ ],
140
+ "size": [
141
+ 360,
142
+ 80
143
+ ],
144
+ "flags": {},
145
+ "order": 3,
146
+ "mode": 0,
147
+ "inputs": [],
148
+ "outputs": [
149
+ {
150
+ "name": "Audio VAE",
151
+ "type": "VAE",
152
+ "links": [
153
+ 8,
154
+ 36
155
+ ]
156
+ }
157
+ ],
158
+ "properties": {
159
+ "Node name for S&R": "LTXVAudioVAELoader"
160
+ },
161
+ "widgets_values": [
162
+ "ltx-2.3-22b-dev-fp8.safetensors"
163
+ ]
164
+ },
165
+ {
166
+ "id": 5,
167
+ "type": "LTXAVTextEncoderLoader",
168
+ "pos": [
169
+ -1280,
170
+ 420
171
+ ],
172
+ "size": [
173
+ 360,
174
+ 120
175
+ ],
176
+ "flags": {},
177
+ "order": 4,
178
+ "mode": 0,
179
+ "inputs": [],
180
+ "outputs": [
181
+ {
182
+ "name": "CLIP",
183
+ "type": "CLIP",
184
+ "links": [
185
+ 9,
186
+ 10
187
+ ]
188
+ }
189
+ ],
190
+ "properties": {
191
+ "Node name for S&R": "LTXAVTextEncoderLoader"
192
+ },
193
+ "widgets_values": [
194
+ "gemma_3_12B_it_fp8_scaled.safetensors",
195
+ "ltx-2.3-22b-dev-fp8.safetensors",
196
+ "default"
197
+ ]
198
+ },
199
+ {
200
+ "id": 6,
201
+ "type": "CLIPTextEncode",
202
+ "pos": [
203
+ -850,
204
+ 380
205
+ ],
206
+ "size": [
207
+ 420,
208
+ 180
209
+ ],
210
+ "flags": {},
211
+ "order": 5,
212
+ "mode": 0,
213
+ "inputs": [
214
+ {
215
+ "name": "clip",
216
+ "type": "CLIP",
217
+ "link": 9
218
+ }
219
+ ],
220
+ "outputs": [
221
+ {
222
+ "name": "CONDITIONING",
223
+ "type": "CONDITIONING",
224
+ "links": [
225
+ 11
226
+ ]
227
+ }
228
+ ],
229
+ "title": "Positive Prompt",
230
+ "properties": {
231
+ "Node name for S&R": "CLIPTextEncode"
232
+ },
233
+ "widgets_values": [
234
+ "Two men are playing tennis. No speech is present. No music is present."
235
+ ]
236
+ },
237
+ {
238
+ "id": 7,
239
+ "type": "CLIPTextEncode",
240
+ "pos": [
241
+ -850,
242
+ 600
243
+ ],
244
+ "size": [
245
+ 420,
246
+ 160
247
+ ],
248
+ "flags": {},
249
+ "order": 6,
250
+ "mode": 0,
251
+ "inputs": [
252
+ {
253
+ "name": "clip",
254
+ "type": "CLIP",
255
+ "link": 10
256
+ }
257
+ ],
258
+ "outputs": [
259
+ {
260
+ "name": "CONDITIONING",
261
+ "type": "CONDITIONING",
262
+ "links": [
263
+ 12
264
+ ]
265
+ }
266
+ ],
267
+ "title": "Negative Prompt",
268
+ "properties": {
269
+ "Node name for S&R": "CLIPTextEncode"
270
+ },
271
+ "widgets_values": [
272
+ "music, melody, song, singing, vocals, score, soundtrack, beat, rhythm bed, instrumental backing, tinny, thin, harsh, clipped, distorted, low bitrate"
273
+ ]
274
+ },
275
+ {
276
+ "id": 8,
277
+ "type": "LTXVConditioning",
278
+ "pos": [
279
+ -360,
280
+ 470
281
+ ],
282
+ "size": [
283
+ 220,
284
+ 90
285
+ ],
286
+ "flags": {},
287
+ "order": 7,
288
+ "mode": 0,
289
+ "inputs": [
290
+ {
291
+ "name": "positive",
292
+ "type": "CONDITIONING",
293
+ "link": 11
294
+ },
295
+ {
296
+ "name": "negative",
297
+ "type": "CONDITIONING",
298
+ "link": 12
299
+ },
300
+ {
301
+ "name": "frame_rate",
302
+ "type": "FLOAT",
303
+ "link": 3
304
+ }
305
+ ],
306
+ "outputs": [
307
+ {
308
+ "name": "positive",
309
+ "type": "CONDITIONING",
310
+ "links": [
311
+ 13
312
+ ]
313
+ },
314
+ {
315
+ "name": "negative",
316
+ "type": "CONDITIONING",
317
+ "links": [
318
+ 14
319
+ ]
320
+ }
321
+ ],
322
+ "properties": {
323
+ "Node name for S&R": "LTXVConditioning"
324
+ },
325
+ "widgets_values": [
326
+ 25.0
327
+ ]
328
+ },
329
+ {
330
+ "id": 9,
331
+ "type": "LTXFoleyVideoToAudioLatent",
332
+ "pos": [
333
+ -360,
334
+ -170
335
+ ],
336
+ "size": [
337
+ 360,
338
+ 340
339
+ ],
340
+ "flags": {},
341
+ "order": 8,
342
+ "mode": 0,
343
+ "inputs": [
344
+ {
345
+ "name": "images",
346
+ "type": "IMAGE",
347
+ "link": 2
348
+ },
349
+ {
350
+ "name": "positive",
351
+ "type": "CONDITIONING",
352
+ "link": 13
353
+ },
354
+ {
355
+ "name": "negative",
356
+ "type": "CONDITIONING",
357
+ "link": 14
358
+ },
359
+ {
360
+ "name": "video_vae",
361
+ "type": "VAE",
362
+ "link": 7
363
+ },
364
+ {
365
+ "name": "audio_vae",
366
+ "type": "VAE",
367
+ "link": 8
368
+ },
369
+ {
370
+ "name": "frame_rate",
371
+ "type": "FLOAT",
372
+ "link": 35
373
+ }
374
+ ],
375
+ "outputs": [
376
+ {
377
+ "name": "positive",
378
+ "type": "CONDITIONING",
379
+ "links": [
380
+ 15
381
+ ]
382
+ },
383
+ {
384
+ "name": "negative",
385
+ "type": "CONDITIONING",
386
+ "links": [
387
+ 16
388
+ ]
389
+ },
390
+ {
391
+ "name": "av_latent",
392
+ "type": "LATENT",
393
+ "links": [
394
+ 17,
395
+ 25,
396
+ 37
397
+ ]
398
+ },
399
+ {
400
+ "name": "preview_images",
401
+ "type": "IMAGE",
402
+ "links": null
403
+ },
404
+ {
405
+ "name": "frame_rate",
406
+ "type": "FLOAT",
407
+ "links": null
408
+ },
409
+ {
410
+ "name": "frames",
411
+ "type": "INT",
412
+ "links": null
413
+ }
414
+ ],
415
+ "properties": {
416
+ "Node name for S&R": "LTXFoleyVideoToAudioLatent"
417
+ },
418
+ "widgets_values": [
419
+ 25.0,
420
+ 576,
421
+ 576,
422
+ 89
423
+ ]
424
+ },
425
+ {
426
+ "id": 10,
427
+ "type": "LoraLoaderModelOnly",
428
+ "pos": [
429
+ -850,
430
+ 120
431
+ ],
432
+ "size": [
433
+ 360,
434
+ 90
435
+ ],
436
+ "flags": {},
437
+ "order": 9,
438
+ "mode": 0,
439
+ "inputs": [
440
+ {
441
+ "name": "model",
442
+ "type": "MODEL",
443
+ "link": 6
444
+ }
445
+ ],
446
+ "outputs": [
447
+ {
448
+ "name": "MODEL",
449
+ "type": "MODEL",
450
+ "links": [
451
+ 20
452
+ ]
453
+ }
454
+ ],
455
+ "properties": {
456
+ "Node name for S&R": "LoraLoaderModelOnly"
457
+ },
458
+ "widgets_values": [
459
+ "ltx-2.3-foley-400-steps.safetensors",
460
+ 1.0
461
+ ]
462
+ },
463
+ {
464
+ "id": 11,
465
+ "type": "ModelSamplingLTXV",
466
+ "pos": [
467
+ -420,
468
+ 220
469
+ ],
470
+ "size": [
471
+ 260,
472
+ 120
473
+ ],
474
+ "flags": {},
475
+ "order": 10,
476
+ "mode": 0,
477
+ "inputs": [
478
+ {
479
+ "name": "model",
480
+ "type": "MODEL",
481
+ "link": 20
482
+ },
483
+ {
484
+ "name": "latent",
485
+ "type": "LATENT",
486
+ "link": 17
487
+ }
488
+ ],
489
+ "outputs": [
490
+ {
491
+ "name": "MODEL",
492
+ "type": "MODEL",
493
+ "links": [
494
+ 21
495
+ ]
496
+ }
497
+ ],
498
+ "properties": {
499
+ "Node name for S&R": "ModelSamplingLTXV"
500
+ },
501
+ "widgets_values": [
502
+ 2.05,
503
+ 0.95
504
+ ]
505
+ },
506
+ {
507
+ "id": 12,
508
+ "type": "STGGuiderNode",
509
+ "pos": [
510
+ 40,
511
+ 240
512
+ ],
513
+ "size": [
514
+ 240,
515
+ 150
516
+ ],
517
+ "flags": {},
518
+ "order": 12,
519
+ "mode": 0,
520
+ "inputs": [
521
+ {
522
+ "name": "model",
523
+ "type": "MODEL",
524
+ "link": 38
525
+ },
526
+ {
527
+ "name": "positive",
528
+ "type": "CONDITIONING",
529
+ "link": 15
530
+ },
531
+ {
532
+ "name": "negative",
533
+ "type": "CONDITIONING",
534
+ "link": 16
535
+ }
536
+ ],
537
+ "outputs": [
538
+ {
539
+ "name": "GUIDER",
540
+ "type": "GUIDER",
541
+ "links": [
542
+ 22
543
+ ]
544
+ }
545
+ ],
546
+ "properties": {
547
+ "Node name for S&R": "STGGuiderNode"
548
+ },
549
+ "widgets_values": [
550
+ 4.0,
551
+ 1.0,
552
+ 0.7
553
+ ]
554
+ },
555
+ {
556
+ "id": 13,
557
+ "type": "RandomNoise",
558
+ "pos": [
559
+ 40,
560
+ -100
561
+ ],
562
+ "size": [
563
+ 240,
564
+ 90
565
+ ],
566
+ "flags": {},
567
+ "order": 13,
568
+ "mode": 0,
569
+ "inputs": [],
570
+ "outputs": [
571
+ {
572
+ "name": "NOISE",
573
+ "type": "NOISE",
574
+ "links": [
575
+ 23
576
+ ]
577
+ }
578
+ ],
579
+ "properties": {
580
+ "Node name for S&R": "RandomNoise"
581
+ },
582
+ "widgets_values": [
583
+ 42,
584
+ "fixed"
585
+ ]
586
+ },
587
+ {
588
+ "id": 14,
589
+ "type": "KSamplerSelect",
590
+ "pos": [
591
+ 40,
592
+ 30
593
+ ],
594
+ "size": [
595
+ 240,
596
+ 80
597
+ ],
598
+ "flags": {},
599
+ "order": 14,
600
+ "mode": 0,
601
+ "inputs": [],
602
+ "outputs": [
603
+ {
604
+ "name": "SAMPLER",
605
+ "type": "SAMPLER",
606
+ "links": [
607
+ 24
608
+ ]
609
+ }
610
+ ],
611
+ "properties": {
612
+ "Node name for S&R": "KSamplerSelect"
613
+ },
614
+ "widgets_values": [
615
+ "euler_ancestral_cfg_pp"
616
+ ]
617
+ },
618
+ {
619
+ "id": 15,
620
+ "type": "LTXVScheduler",
621
+ "pos": [
622
+ 40,
623
+ 430
624
+ ],
625
+ "size": [
626
+ 240,
627
+ 160
628
+ ],
629
+ "flags": {},
630
+ "order": 15,
631
+ "mode": 0,
632
+ "inputs": [
633
+ {
634
+ "name": "latent",
635
+ "type": "LATENT",
636
+ "link": 25
637
+ }
638
+ ],
639
+ "outputs": [
640
+ {
641
+ "name": "SIGMAS",
642
+ "type": "SIGMAS",
643
+ "links": [
644
+ 26
645
+ ]
646
+ }
647
+ ],
648
+ "properties": {
649
+ "Node name for S&R": "LTXVScheduler"
650
+ },
651
+ "widgets_values": [
652
+ 30,
653
+ 2.05,
654
+ 0.95,
655
+ true,
656
+ 0.1
657
+ ]
658
+ },
659
+ {
660
+ "id": 16,
661
+ "type": "SamplerCustomAdvanced",
662
+ "pos": [
663
+ 360,
664
+ 120
665
+ ],
666
+ "size": [
667
+ 230,
668
+ 130
669
+ ],
670
+ "flags": {},
671
+ "order": 16,
672
+ "mode": 0,
673
+ "inputs": [
674
+ {
675
+ "name": "noise",
676
+ "type": "NOISE",
677
+ "link": 23
678
+ },
679
+ {
680
+ "name": "guider",
681
+ "type": "GUIDER",
682
+ "link": 22
683
+ },
684
+ {
685
+ "name": "sampler",
686
+ "type": "SAMPLER",
687
+ "link": 24
688
+ },
689
+ {
690
+ "name": "sigmas",
691
+ "type": "SIGMAS",
692
+ "link": 26
693
+ },
694
+ {
695
+ "name": "latent_image",
696
+ "type": "LATENT",
697
+ "link": 37
698
+ }
699
+ ],
700
+ "outputs": [
701
+ {
702
+ "name": "output",
703
+ "type": "LATENT",
704
+ "links": [
705
+ 27
706
+ ]
707
+ },
708
+ {
709
+ "name": "denoised_output",
710
+ "type": "LATENT",
711
+ "links": null
712
+ }
713
+ ],
714
+ "properties": {
715
+ "Node name for S&R": "SamplerCustomAdvanced"
716
+ },
717
+ "widgets_values": []
718
+ },
719
+ {
720
+ "id": 17,
721
+ "type": "LTXVSeparateAVLatent",
722
+ "pos": [
723
+ 650,
724
+ 120
725
+ ],
726
+ "size": [
727
+ 220,
728
+ 80
729
+ ],
730
+ "flags": {},
731
+ "order": 17,
732
+ "mode": 0,
733
+ "inputs": [
734
+ {
735
+ "name": "av_latent",
736
+ "type": "LATENT",
737
+ "link": 27
738
+ }
739
+ ],
740
+ "outputs": [
741
+ {
742
+ "name": "video_latent",
743
+ "type": "LATENT",
744
+ "links": null
745
+ },
746
+ {
747
+ "name": "audio_latent",
748
+ "type": "LATENT",
749
+ "links": [
750
+ 28
751
+ ]
752
+ }
753
+ ],
754
+ "properties": {
755
+ "Node name for S&R": "LTXVSeparateAVLatent"
756
+ },
757
+ "widgets_values": []
758
+ },
759
+ {
760
+ "id": 18,
761
+ "type": "LTXFoleyAudioVAEDecode",
762
+ "pos": [
763
+ 920,
764
+ 120
765
+ ],
766
+ "size": [
767
+ 240,
768
+ 90
769
+ ],
770
+ "flags": {},
771
+ "order": 18,
772
+ "mode": 0,
773
+ "inputs": [
774
+ {
775
+ "name": "samples",
776
+ "type": "LATENT",
777
+ "link": 28
778
+ },
779
+ {
780
+ "name": "audio_vae",
781
+ "type": "VAE",
782
+ "link": 36
783
+ }
784
+ ],
785
+ "outputs": [
786
+ {
787
+ "name": "Audio",
788
+ "type": "AUDIO",
789
+ "links": [
790
+ 31
791
+ ]
792
+ }
793
+ ],
794
+ "properties": {
795
+ "Node name for S&R": "LTXFoleyAudioVAEDecode"
796
+ },
797
+ "widgets_values": []
798
+ },
799
+ {
800
+ "id": 19,
801
+ "type": "LTXFoleyTrimImages",
802
+ "pos": [
803
+ 920,
804
+ -120
805
+ ],
806
+ "size": [
807
+ 260,
808
+ 140
809
+ ],
810
+ "flags": {},
811
+ "order": 19,
812
+ "mode": 0,
813
+ "inputs": [
814
+ {
815
+ "name": "images",
816
+ "type": "IMAGE",
817
+ "link": 29
818
+ },
819
+ {
820
+ "name": "frame_rate",
821
+ "type": "FLOAT",
822
+ "link": 30
823
+ }
824
+ ],
825
+ "outputs": [
826
+ {
827
+ "name": "images",
828
+ "type": "IMAGE",
829
+ "links": [
830
+ 32
831
+ ]
832
+ },
833
+ {
834
+ "name": "frame_rate",
835
+ "type": "FLOAT",
836
+ "links": [
837
+ 33
838
+ ]
839
+ }
840
+ ],
841
+ "properties": {
842
+ "Node name for S&R": "LTXFoleyTrimImages"
843
+ },
844
+ "widgets_values": [
845
+ 25.0,
846
+ 89
847
+ ]
848
+ },
849
+ {
850
+ "id": 20,
851
+ "type": "CreateVideo",
852
+ "pos": [
853
+ 1220,
854
+ 0
855
+ ],
856
+ "size": [
857
+ 260,
858
+ 140
859
+ ],
860
+ "flags": {},
861
+ "order": 20,
862
+ "mode": 0,
863
+ "inputs": [
864
+ {
865
+ "name": "images",
866
+ "type": "IMAGE",
867
+ "link": 32
868
+ },
869
+ {
870
+ "name": "fps",
871
+ "type": "FLOAT",
872
+ "link": 33
873
+ },
874
+ {
875
+ "name": "audio",
876
+ "type": "AUDIO",
877
+ "link": 31
878
+ }
879
+ ],
880
+ "outputs": [
881
+ {
882
+ "name": "video",
883
+ "type": "VIDEO",
884
+ "links": [
885
+ 34
886
+ ]
887
+ }
888
+ ],
889
+ "properties": {
890
+ "Node name for S&R": "CreateVideo"
891
+ },
892
+ "widgets_values": [
893
+ 25.0,
894
+ 8
895
+ ]
896
+ },
897
+ {
898
+ "id": 21,
899
+ "type": "SaveVideo",
900
+ "pos": [
901
+ 1530,
902
+ 0
903
+ ],
904
+ "size": [
905
+ 260,
906
+ 110
907
+ ],
908
+ "flags": {},
909
+ "order": 21,
910
+ "mode": 0,
911
+ "inputs": [
912
+ {
913
+ "name": "video",
914
+ "type": "VIDEO",
915
+ "link": 34
916
+ }
917
+ ],
918
+ "outputs": [
919
+ {
920
+ "name": "video",
921
+ "type": "VIDEO",
922
+ "links": null
923
+ }
924
+ ],
925
+ "properties": {
926
+ "Node name for S&R": "SaveVideo"
927
+ },
928
+ "widgets_values": [
929
+ "ltx_foley",
930
+ "auto",
931
+ "auto"
932
+ ]
933
+ },
934
+ {
935
+ "id": 22,
936
+ "type": "LTXVApplySTG",
937
+ "pos": [
938
+ -260,
939
+ 260
940
+ ],
941
+ "size": [
942
+ 240,
943
+ 80
944
+ ],
945
+ "flags": {},
946
+ "order": 11,
947
+ "mode": 0,
948
+ "inputs": [
949
+ {
950
+ "name": "model",
951
+ "type": "MODEL",
952
+ "link": 21
953
+ }
954
+ ],
955
+ "outputs": [
956
+ {
957
+ "name": "model",
958
+ "type": "MODEL",
959
+ "links": [
960
+ 38
961
+ ]
962
+ }
963
+ ],
964
+ "properties": {
965
+ "Node name for S&R": "LTXVApplySTG"
966
+ },
967
+ "widgets_values": [
968
+ "14, 19"
969
+ ]
970
+ }
971
+ ],
972
+ "links": [
973
+ [
974
+ 1,
975
+ 1,
976
+ 0,
977
+ 2,
978
+ 0,
979
+ "VIDEO"
980
+ ],
981
+ [
982
+ 2,
983
+ 2,
984
+ 0,
985
+ 9,
986
+ 0,
987
+ "IMAGE"
988
+ ],
989
+ [
990
+ 3,
991
+ 2,
992
+ 2,
993
+ 8,
994
+ 2,
995
+ "FLOAT"
996
+ ],
997
+ [
998
+ 6,
999
+ 3,
1000
+ 0,
1001
+ 10,
1002
+ 0,
1003
+ "MODEL"
1004
+ ],
1005
+ [
1006
+ 7,
1007
+ 3,
1008
+ 2,
1009
+ 9,
1010
+ 3,
1011
+ "VAE"
1012
+ ],
1013
+ [
1014
+ 8,
1015
+ 4,
1016
+ 0,
1017
+ 9,
1018
+ 4,
1019
+ "VAE"
1020
+ ],
1021
+ [
1022
+ 9,
1023
+ 5,
1024
+ 0,
1025
+ 6,
1026
+ 0,
1027
+ "CLIP"
1028
+ ],
1029
+ [
1030
+ 10,
1031
+ 5,
1032
+ 0,
1033
+ 7,
1034
+ 0,
1035
+ "CLIP"
1036
+ ],
1037
+ [
1038
+ 11,
1039
+ 6,
1040
+ 0,
1041
+ 8,
1042
+ 0,
1043
+ "CONDITIONING"
1044
+ ],
1045
+ [
1046
+ 12,
1047
+ 7,
1048
+ 0,
1049
+ 8,
1050
+ 1,
1051
+ "CONDITIONING"
1052
+ ],
1053
+ [
1054
+ 13,
1055
+ 8,
1056
+ 0,
1057
+ 9,
1058
+ 1,
1059
+ "CONDITIONING"
1060
+ ],
1061
+ [
1062
+ 14,
1063
+ 8,
1064
+ 1,
1065
+ 9,
1066
+ 2,
1067
+ "CONDITIONING"
1068
+ ],
1069
+ [
1070
+ 15,
1071
+ 9,
1072
+ 0,
1073
+ 12,
1074
+ 1,
1075
+ "CONDITIONING"
1076
+ ],
1077
+ [
1078
+ 16,
1079
+ 9,
1080
+ 1,
1081
+ 12,
1082
+ 2,
1083
+ "CONDITIONING"
1084
+ ],
1085
+ [
1086
+ 17,
1087
+ 9,
1088
+ 2,
1089
+ 11,
1090
+ 1,
1091
+ "LATENT"
1092
+ ],
1093
+ [
1094
+ 20,
1095
+ 10,
1096
+ 0,
1097
+ 11,
1098
+ 0,
1099
+ "MODEL"
1100
+ ],
1101
+ [
1102
+ 21,
1103
+ 11,
1104
+ 0,
1105
+ 22,
1106
+ 0,
1107
+ "MODEL"
1108
+ ],
1109
+ [
1110
+ 22,
1111
+ 12,
1112
+ 0,
1113
+ 16,
1114
+ 1,
1115
+ "GUIDER"
1116
+ ],
1117
+ [
1118
+ 23,
1119
+ 13,
1120
+ 0,
1121
+ 16,
1122
+ 0,
1123
+ "NOISE"
1124
+ ],
1125
+ [
1126
+ 24,
1127
+ 14,
1128
+ 0,
1129
+ 16,
1130
+ 2,
1131
+ "SAMPLER"
1132
+ ],
1133
+ [
1134
+ 25,
1135
+ 9,
1136
+ 2,
1137
+ 15,
1138
+ 0,
1139
+ "LATENT"
1140
+ ],
1141
+ [
1142
+ 26,
1143
+ 15,
1144
+ 0,
1145
+ 16,
1146
+ 3,
1147
+ "SIGMAS"
1148
+ ],
1149
+ [
1150
+ 27,
1151
+ 16,
1152
+ 0,
1153
+ 17,
1154
+ 0,
1155
+ "LATENT"
1156
+ ],
1157
+ [
1158
+ 28,
1159
+ 17,
1160
+ 1,
1161
+ 18,
1162
+ 0,
1163
+ "LATENT"
1164
+ ],
1165
+ [
1166
+ 29,
1167
+ 2,
1168
+ 0,
1169
+ 19,
1170
+ 0,
1171
+ "IMAGE"
1172
+ ],
1173
+ [
1174
+ 30,
1175
+ 2,
1176
+ 2,
1177
+ 19,
1178
+ 1,
1179
+ "FLOAT"
1180
+ ],
1181
+ [
1182
+ 31,
1183
+ 18,
1184
+ 0,
1185
+ 20,
1186
+ 2,
1187
+ "AUDIO"
1188
+ ],
1189
+ [
1190
+ 32,
1191
+ 19,
1192
+ 0,
1193
+ 20,
1194
+ 0,
1195
+ "IMAGE"
1196
+ ],
1197
+ [
1198
+ 33,
1199
+ 19,
1200
+ 1,
1201
+ 20,
1202
+ 1,
1203
+ "FLOAT"
1204
+ ],
1205
+ [
1206
+ 34,
1207
+ 20,
1208
+ 0,
1209
+ 21,
1210
+ 0,
1211
+ "VIDEO"
1212
+ ],
1213
+ [
1214
+ 35,
1215
+ 2,
1216
+ 2,
1217
+ 9,
1218
+ 5,
1219
+ "FLOAT"
1220
+ ],
1221
+ [
1222
+ 36,
1223
+ 4,
1224
+ 0,
1225
+ 18,
1226
+ 1,
1227
+ "VAE"
1228
+ ],
1229
+ [
1230
+ 37,
1231
+ 9,
1232
+ 2,
1233
+ 16,
1234
+ 4,
1235
+ "LATENT"
1236
+ ],
1237
+ [
1238
+ 38,
1239
+ 22,
1240
+ 0,
1241
+ 12,
1242
+ 0,
1243
+ "MODEL"
1244
+ ]
1245
+ ],
1246
+ "groups": [],
1247
+ "config": {},
1248
+ "extra": {
1249
+ "ds": {
1250
+ "scale": 0.75,
1251
+ "offset": [
1252
+ 1530,
1253
+ 390
1254
+ ]
1255
+ }
1256
+ },
1257
+ "models": [
1258
+ {
1259
+ "name": "ltx-2.3-22b-dev-fp8.safetensors",
1260
+ "url": "https://huggingface.co/Lightricks/LTX-2.3-fp8/resolve/main/ltx-2.3-22b-dev-fp8.safetensors",
1261
+ "directory": "checkpoints"
1262
+ },
1263
+ {
1264
+ "name": "gemma_3_12B_it_fp8_scaled.safetensors",
1265
+ "url": "https://huggingface.co/Comfy-Org/ltx-2/resolve/main/split_files/text_encoders/gemma_3_12B_it_fp8_scaled.safetensors",
1266
+ "directory": "text_encoders"
1267
+ },
1268
+ {
1269
+ "name": "ltx-2.3-foley-400-steps.safetensors",
1270
+ "url": "https://huggingface.co/FuzzPuppy/LTX-2.3-Foley/resolve/main/ltx-2.3-foley-400-steps.safetensors",
1271
+ "directory": "loras"
1272
+ }
1273
+ ],
1274
+ "version": 0.4
1275
+ }
ltx_foley_v2a/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from .nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
2
+
3
+ __all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
ltx_foley_v2a/nodes.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ def _common_upscale(images, width: int, height: int):
4
+ import comfy.utils
5
+
6
+ return comfy.utils.common_upscale(images.movedim(-1, 1), width, height, "bilinear", "center").movedim(1, -1)
7
+
8
+
9
+ def _intermediate_device():
10
+ import comfy.model_management
11
+
12
+ return comfy.model_management.intermediate_device()
13
+
14
+
15
+ def _conditioning_set_values(conditioning, values):
16
+ import node_helpers
17
+
18
+ return node_helpers.conditioning_set_values(conditioning, values)
19
+
20
+
21
+ def _audio_vae_model(audio_vae):
22
+ return getattr(audio_vae, "first_stage_model", audio_vae)
23
+
24
+
25
+ class LTXFoleyVideoToAudioLatent:
26
+ CATEGORY = "LTX/Foley"
27
+ RETURN_TYPES = ("CONDITIONING", "CONDITIONING", "LATENT", "IMAGE", "FLOAT", "INT")
28
+ RETURN_NAMES = ("positive", "negative", "av_latent", "preview_images", "frame_rate", "frames")
29
+ FUNCTION = "prepare"
30
+
31
+ @classmethod
32
+ def INPUT_TYPES(cls) -> dict[str, object]:
33
+ return {
34
+ "required": {
35
+ "images": ("IMAGE",),
36
+ "positive": ("CONDITIONING",),
37
+ "negative": ("CONDITIONING",),
38
+ "video_vae": ("VAE",),
39
+ "audio_vae": ("VAE",),
40
+ "frame_rate": ("FLOAT", {"default": 25.0, "min": 1.0, "max": 120.0, "step": 0.01}),
41
+ "width": ("INT", {"default": 576, "min": 256, "max": 2048, "step": 32}),
42
+ "height": ("INT", {"default": 576, "min": 256, "max": 2048, "step": 32}),
43
+ "frames": ("INT", {"default": 89, "min": 9, "max": 257, "step": 8}),
44
+ }
45
+ }
46
+
47
+ def prepare(
48
+ self,
49
+ images,
50
+ positive,
51
+ negative,
52
+ video_vae,
53
+ audio_vae,
54
+ frame_rate: float,
55
+ width: int,
56
+ height: int,
57
+ frames: int,
58
+ ):
59
+ import torch
60
+
61
+ if frames % 8 != 1:
62
+ raise ValueError("frames must satisfy frames % 8 == 1")
63
+ if images.shape[0] == 0:
64
+ raise ValueError("No video frames were provided")
65
+
66
+ source = images[:frames]
67
+ if source.shape[0] < frames:
68
+ pad = source[-1:].repeat((frames - source.shape[0], 1, 1, 1))
69
+ source = torch.cat([source, pad], dim=0)
70
+
71
+ resized = _common_upscale(source, width, height).clamp(0.0, 1.0)
72
+ video_latent = video_vae.encode(resized[:, :, :, :3])
73
+ video_noise_mask = torch.zeros(
74
+ (1, 1, video_latent.shape[2], 1, 1),
75
+ dtype=torch.float32,
76
+ device=video_latent.device,
77
+ )
78
+
79
+ audio_model = _audio_vae_model(audio_vae)
80
+ z_channels = getattr(audio_vae, "latent_channels", audio_model.latent_channels)
81
+ audio_freq = audio_model.latent_frequency_bins
82
+ audio_latents = audio_model.num_of_latents_from_frames(frames, int(round(frame_rate)))
83
+ audio_latent = torch.zeros(
84
+ (1, z_channels, audio_latents, audio_freq),
85
+ device=_intermediate_device(),
86
+ )
87
+ audio_noise_mask = torch.ones_like(audio_latent)
88
+
89
+ import comfy.nested_tensor
90
+
91
+ av_latent = {
92
+ "samples": comfy.nested_tensor.NestedTensor((video_latent, audio_latent)),
93
+ "noise_mask": comfy.nested_tensor.NestedTensor((video_noise_mask, audio_noise_mask)),
94
+ }
95
+ values = {"frame_rate": frame_rate}
96
+ return (
97
+ _conditioning_set_values(positive, values),
98
+ _conditioning_set_values(negative, values),
99
+ av_latent,
100
+ resized,
101
+ float(frame_rate),
102
+ int(frames),
103
+ )
104
+
105
+
106
+ class LTXFoleyTrimImages:
107
+ CATEGORY = "LTX/Foley"
108
+ RETURN_TYPES = ("IMAGE", "FLOAT")
109
+ RETURN_NAMES = ("images", "frame_rate")
110
+ FUNCTION = "trim"
111
+
112
+ @classmethod
113
+ def INPUT_TYPES(cls) -> dict[str, object]:
114
+ return {
115
+ "required": {
116
+ "images": ("IMAGE",),
117
+ "frame_rate": ("FLOAT", {"default": 25.0, "min": 1.0, "max": 120.0, "step": 0.01}),
118
+ "frames": ("INT", {"default": 89, "min": 9, "max": 257, "step": 8}),
119
+ }
120
+ }
121
+
122
+ def trim(self, images, frame_rate: float, frames: int):
123
+ import torch
124
+
125
+ if images.shape[0] == 0:
126
+ raise ValueError("No video frames were provided")
127
+ trimmed = images[:frames]
128
+ if trimmed.shape[0] < frames:
129
+ pad = trimmed[-1:].repeat((frames - trimmed.shape[0], 1, 1, 1))
130
+ trimmed = torch.cat([trimmed, pad], dim=0)
131
+ return (trimmed, float(frame_rate))
132
+
133
+
134
+ class LTXFoleyAudioVAEDecode:
135
+ CATEGORY = "LTX/Foley"
136
+ RETURN_TYPES = ("AUDIO",)
137
+ RETURN_NAMES = ("audio",)
138
+ FUNCTION = "decode"
139
+
140
+ @classmethod
141
+ def INPUT_TYPES(cls) -> dict[str, object]:
142
+ return {
143
+ "required": {
144
+ "samples": ("LATENT",),
145
+ "audio_vae": ("VAE",),
146
+ }
147
+ }
148
+
149
+ def decode(self, samples, audio_vae):
150
+ audio_latent = samples["samples"]
151
+ if audio_latent.is_nested:
152
+ audio_latent = audio_latent.unbind()[-1]
153
+
154
+ audio = audio_vae.decode(audio_latent).to(audio_latent.device)
155
+ if audio.ndim == 2:
156
+ audio = audio.unsqueeze(1)
157
+ elif audio.ndim != 3:
158
+ raise ValueError(f"Expected decoded audio to have 2 or 3 dimensions, got shape {tuple(audio.shape)}")
159
+
160
+ if audio.shape[1] in (1, 2, 6):
161
+ waveform = audio
162
+ elif audio.shape[2] in (1, 2, 6):
163
+ waveform = audio.movedim(-1, 1)
164
+ else:
165
+ raise ValueError(f"Could not infer audio channel dimension from decoded shape {tuple(audio.shape)}")
166
+
167
+ output_sample_rate = _audio_vae_model(audio_vae).output_sample_rate
168
+ return ({"waveform": waveform, "sample_rate": int(output_sample_rate)},)
169
+
170
+
171
+ NODE_CLASS_MAPPINGS = {
172
+ "LTXFoleyVideoToAudioLatent": LTXFoleyVideoToAudioLatent,
173
+ "LTXFoleyTrimImages": LTXFoleyTrimImages,
174
+ "LTXFoleyAudioVAEDecode": LTXFoleyAudioVAEDecode,
175
+ }
176
+ NODE_DISPLAY_NAME_MAPPINGS = {
177
+ "LTXFoleyVideoToAudioLatent": "LTX Foley Video To Audio Latent",
178
+ "LTXFoleyTrimImages": "LTX Foley Trim Images",
179
+ "LTXFoleyAudioVAEDecode": "LTX Foley Audio VAE Decode",
180
+ }
setup_runpod_ltx_foley.sh ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -Eeuo pipefail
3
+
4
+ LTXVIDEO_REPO="${LTXVIDEO_REPO:-https://github.com/Lightricks/ComfyUI-LTXVideo.git}"
5
+ WORKFLOW_REPO="${WORKFLOW_REPO:-FuzzPuppy/LTX-2.3-Foley-Workflow}"
6
+ WORKFLOW_BASE_URL="${WORKFLOW_BASE_URL:-https://huggingface.co/${WORKFLOW_REPO}/resolve/main}"
7
+
8
+ log() {
9
+ printf '\n[%s] %s\n' "$(date +%H:%M:%S)" "$*"
10
+ }
11
+
12
+ die() {
13
+ printf '\nERROR: %s\n' "$*" >&2
14
+ exit 1
15
+ }
16
+
17
+ download_file() {
18
+ local url="$1"
19
+ local target="$2"
20
+ local token="${HF_TOKEN:-${HUGGINGFACE_TOKEN:-}}"
21
+ local curl_args=(-fL --retry 5 --retry-delay 2)
22
+
23
+ mkdir -p "$(dirname "$target")"
24
+ if [[ -n "$token" ]]; then
25
+ curl_args+=(-H "Authorization: Bearer $token")
26
+ fi
27
+ curl "${curl_args[@]}" "$url" -o "$target"
28
+ }
29
+
30
+ download_model_file() {
31
+ local url="$1"
32
+ local target_path="$2"
33
+ local expected_sha256="$3"
34
+ local partial_path="${target_path}.part"
35
+ local token="${HF_TOKEN:-${HUGGINGFACE_TOKEN:-}}"
36
+ local curl_args=(-fL --retry 5 --retry-delay 2 -C -)
37
+ local attempt
38
+
39
+ if [[ -s "$target_path" ]]; then
40
+ if printf '%s %s\n' "$expected_sha256" "$target_path" | sha256sum -c - >/dev/null 2>&1; then
41
+ printf 'verified: %s\n' "$target_path"
42
+ return
43
+ fi
44
+ printf 'hash mismatch, redownloading: %s\n' "$target_path"
45
+ rm -f "$target_path"
46
+ fi
47
+
48
+ mkdir -p "$(dirname "$target_path")"
49
+ if [[ -n "$token" ]]; then
50
+ curl_args+=(-H "Authorization: Bearer $token")
51
+ fi
52
+
53
+ for attempt in 1 2; do
54
+ curl "${curl_args[@]}" "$url" -o "$partial_path"
55
+ if printf '%s %s\n' "$expected_sha256" "$partial_path" | sha256sum -c -; then
56
+ mv "$partial_path" "$target_path"
57
+ [[ -s "$target_path" ]] || die "Expected download missing: $target_path"
58
+ return
59
+ fi
60
+
61
+ rm -f "$partial_path"
62
+ curl_args=(-fL --retry 5 --retry-delay 2)
63
+ if [[ -n "$token" ]]; then
64
+ curl_args+=(-H "Authorization: Bearer $token")
65
+ fi
66
+ printf 'hash mismatch, retrying clean download: %s\n' "$target_path"
67
+ done
68
+
69
+ die "Downloaded file failed SHA-256 verification: $target_path"
70
+ }
71
+
72
+ build_comfyui_args() {
73
+ COMFYUI_ARGS=(--listen 0.0.0.0 --port 8188 --enable-cors-header)
74
+
75
+ if [[ -s "$ARGS_FILE" ]]; then
76
+ local line
77
+ local line_args
78
+ while IFS= read -r line; do
79
+ [[ -z "$line" || "$line" == \#* ]] && continue
80
+ read -r -a line_args <<< "$line"
81
+ COMFYUI_ARGS+=("${line_args[@]}")
82
+ done < "$ARGS_FILE"
83
+ fi
84
+ }
85
+
86
+ restart_comfyui() {
87
+ log "Restarting ComfyUI"
88
+ build_comfyui_args
89
+
90
+ local pid
91
+ while IFS= read -r pid; do
92
+ [[ -z "$pid" ]] && continue
93
+ kill "$pid" 2>/dev/null || true
94
+ done < <(pgrep -f "python.*${COMFYUI_DIR}/main.py|python.*main.py.*--port 8188" || true)
95
+
96
+ local attempt
97
+ for attempt in {1..20}; do
98
+ if ! pgrep -f "python.*${COMFYUI_DIR}/main.py|python.*main.py.*--port 8188" >/dev/null; then
99
+ break
100
+ fi
101
+ sleep 1
102
+ done
103
+
104
+ if pgrep -f "python.*${COMFYUI_DIR}/main.py|python.*main.py.*--port 8188" >/dev/null; then
105
+ die "Timed out waiting for the old ComfyUI process to stop."
106
+ fi
107
+
108
+ (
109
+ cd "$COMFYUI_DIR"
110
+ nohup "$PYTHON_BIN" main.py "${COMFYUI_ARGS[@]}" > "$LOG_FILE" 2>&1 &
111
+ printf '%s\n' "$!" > "$PID_FILE"
112
+ )
113
+
114
+ sleep 2
115
+ if ! kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
116
+ die "ComfyUI failed to start. Check $LOG_FILE"
117
+ fi
118
+
119
+ for attempt in {1..60}; do
120
+ if curl -fsS http://127.0.0.1:8188/ >/dev/null 2>&1; then
121
+ log "ComfyUI restarted with pid $(cat "$PID_FILE"). Logs: $LOG_FILE"
122
+ return
123
+ fi
124
+ sleep 1
125
+ done
126
+
127
+ die "ComfyUI process started, but port 8188 did not become ready. Check $LOG_FILE"
128
+ }
129
+
130
+ COMFYUI_DIR="${COMFYUI_DIR:-/workspace/runpod-slim/ComfyUI}"
131
+ [[ -f "$COMFYUI_DIR/main.py" ]] || die "Could not find ComfyUI at $COMFYUI_DIR. Use RunPod's official ComfyUI - CUDA 12.8 template or set COMFYUI_DIR=/path/to/ComfyUI."
132
+ CUSTOM_NODES_DIR="$COMFYUI_DIR/custom_nodes"
133
+ MODELS_DIR="$COMFYUI_DIR/models"
134
+ INPUT_DIR="$COMFYUI_DIR/input"
135
+ VENV_DIR="$COMFYUI_DIR/.venv-cu128"
136
+ ARGS_FILE="/workspace/runpod-slim/comfyui_args.txt"
137
+ LOG_FILE="/workspace/runpod-slim/comfyui-restart.log"
138
+ PID_FILE="/workspace/runpod-slim/comfyui-restart.pid"
139
+ PYTHON_BIN="$VENV_DIR/bin/python"
140
+
141
+ if [[ ! -x "$PYTHON_BIN" ]]; then
142
+ PYTHON_BIN="$COMFYUI_DIR/venv/bin/python"
143
+ fi
144
+ if [[ ! -x "$PYTHON_BIN" ]]; then
145
+ PYTHON_BIN="$(command -v python3.12 || command -v python3 || true)"
146
+ fi
147
+ [[ -x "$PYTHON_BIN" ]] || die "Could not find Python. Expected $COMFYUI_DIR/.venv-cu128/bin/python or python3 on PATH."
148
+
149
+ log "Using ComfyUI at $COMFYUI_DIR"
150
+ log "Using Python at $PYTHON_BIN"
151
+
152
+ mkdir -p "$CUSTOM_NODES_DIR" "$MODELS_DIR/checkpoints" "$MODELS_DIR/loras" "$MODELS_DIR/text_encoders" "$INPUT_DIR"
153
+
154
+ command -v curl >/dev/null 2>&1 || die "curl is required. RunPod's official ComfyUI - CUDA 12.8 template includes it."
155
+ command -v git >/dev/null 2>&1 || die "git is required. RunPod's official ComfyUI - CUDA 12.8 template includes it."
156
+ command -v ffmpeg >/dev/null 2>&1 || die "ffmpeg is required. RunPod's official ComfyUI - CUDA 12.8 template includes it."
157
+ command -v sha256sum >/dev/null 2>&1 || die "sha256sum is required. RunPod's official ComfyUI - CUDA 12.8 template includes it."
158
+
159
+ if [[ "${UPDATE_COMFYUI:-0}" == "1" ]]; then
160
+ log "Updating ComfyUI"
161
+ git -C "$COMFYUI_DIR" pull --ff-only || log "ComfyUI git pull was skipped or failed; continuing with the installed version."
162
+ else
163
+ log "Keeping the RunPod template's pinned ComfyUI install"
164
+ fi
165
+
166
+ log "Installing official LTXVideo custom nodes"
167
+ if [[ -d "$CUSTOM_NODES_DIR/ComfyUI-LTXVideo/.git" ]]; then
168
+ git -C "$CUSTOM_NODES_DIR/ComfyUI-LTXVideo" pull --ff-only || log "LTXVideo git pull was skipped or failed; continuing with the installed version."
169
+ else
170
+ rm -rf "$CUSTOM_NODES_DIR/ComfyUI-LTXVideo"
171
+ git clone --depth 1 "$LTXVIDEO_REPO" "$CUSTOM_NODES_DIR/ComfyUI-LTXVideo"
172
+ fi
173
+
174
+ if [[ -f "$CUSTOM_NODES_DIR/ComfyUI-LTXVideo/requirements.txt" ]]; then
175
+ "$PYTHON_BIN" -m pip install -r "$CUSTOM_NODES_DIR/ComfyUI-LTXVideo/requirements.txt"
176
+ fi
177
+ if [[ -f "$CUSTOM_NODES_DIR/ComfyUI-LTXVideo/install.py" ]]; then
178
+ "$PYTHON_BIN" "$CUSTOM_NODES_DIR/ComfyUI-LTXVideo/install.py" || log "LTXVideo install.py returned non-zero; continuing after requirements install."
179
+ fi
180
+
181
+ log "Installing LTX Foley helper node and workflow from $WORKFLOW_REPO"
182
+ NODE_DEST="$CUSTOM_NODES_DIR/ltx_foley_v2a"
183
+ WORKFLOW_DEST="$COMFYUI_DIR/user/default/workflows"
184
+ rm -rf "$NODE_DEST"
185
+ mkdir -p "$NODE_DEST" "$WORKFLOW_DEST"
186
+ download_file "$WORKFLOW_BASE_URL/ltx_foley_v2a/__init__.py" "$NODE_DEST/__init__.py"
187
+ download_file "$WORKFLOW_BASE_URL/ltx_foley_v2a/nodes.py" "$NODE_DEST/nodes.py"
188
+ download_file "$WORKFLOW_BASE_URL/ltx_23_foley_v2a.json" "$WORKFLOW_DEST/ltx_23_foley_v2a.json"
189
+ download_file "$WORKFLOW_BASE_URL/tennis-no-sound.mp4" "$INPUT_DIR/input.mp4"
190
+
191
+ log "Downloading LTX 2.3 Foley model files"
192
+ download_model_file \
193
+ "https://huggingface.co/Lightricks/LTX-2.3-fp8/resolve/main/ltx-2.3-22b-dev-fp8.safetensors" \
194
+ "$MODELS_DIR/checkpoints/ltx-2.3-22b-dev-fp8.safetensors" \
195
+ "28606c5b5a06ce56f896d4dfcb20f212739e07a68fbe48e53638188449d26450"
196
+ download_model_file \
197
+ "https://huggingface.co/Comfy-Org/ltx-2/resolve/main/split_files/text_encoders/gemma_3_12B_it_fp8_scaled.safetensors" \
198
+ "$MODELS_DIR/text_encoders/gemma_3_12B_it_fp8_scaled.safetensors" \
199
+ "60216ce97c01c3a8753c2dfd0a89fc76e16fbe446d1a32ef8f1b528ac8bae466"
200
+ download_model_file \
201
+ "https://huggingface.co/FuzzPuppy/LTX-2.3-Foley/resolve/main/ltx-2.3-foley-400-steps.safetensors" \
202
+ "$MODELS_DIR/loras/ltx-2.3-foley-400-steps.safetensors" \
203
+ "12b37ffff8444ac1348a8c9fb24843a6bd70e77cf4202ac39b1d056b81fa41c9"
204
+
205
+ log "Done"
206
+ restart_comfyui
207
+
208
+ cat <<EOF
209
+
210
+ Next steps:
211
+ 1. Open the RunPod HTTP service on port 8188.
212
+ 2. Load workflow: user/default/workflows/ltx_23_foley_v2a.json
213
+ 3. Queue the workflow. The tennis test video is already installed as input.mp4 and the prompt is prefilled.
214
+
215
+ If model download fails with 401/403, accept the model licenses on Hugging Face and rerun with:
216
+ export HF_TOKEN=hf_...
217
+ bash $0
218
+ EOF
tennis-no-sound.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3eaf7a21d6cb6f061ca368921152b7dc7164a21cd88b25c4b72c1654ebeb49a2
3
+ size 413412