Upload ltxv-t2v.ipynb
Browse files- ComfyUI/ltxv-t2v.ipynb +204 -0
ComfyUI/ltxv-t2v.ipynb
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "code",
|
| 5 |
+
"execution_count": null,
|
| 6 |
+
"metadata": {},
|
| 7 |
+
"outputs": [],
|
| 8 |
+
"source": [
|
| 9 |
+
"%cd /content\n",
|
| 10 |
+
"!apt install -qqy\n",
|
| 11 |
+
"!pip install torchsde einops pyaml diffusers transformers peft accelerate aiohttp kornia spandrel sentencepiece ipywidgets termcolor moviepy==1.0.3\n",
|
| 12 |
+
"\n",
|
| 13 |
+
"!git clone https://github.com/comfyanonymous/ComfyUI /content/ComfyUI\n",
|
| 14 |
+
"!git clone https://github.com/ltdrdata/ComfyUI-Manager /content/ComfyUI/custom_nodes/ComfyUI-Manager\n",
|
| 15 |
+
"!git clone -b dev https://github.com/camenduru/ComfyUI-Fluxpromptenhancer /content/ComfyUI/custom_nodes/ComfyUI-Fluxpromptenhancer\n",
|
| 16 |
+
"\n",
|
| 17 |
+
"!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/camenduru/FLUX.1-dev/resolve/main/t5xxl_fp16.safetensors -d /content/ComfyUI/models/clip -o t5xxl_fp16.safetensors\n",
|
| 18 |
+
"!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/Lightricks/LTX-Video/resolve/main/ltx-video-2b-v0.9.safetensors -d /content/ComfyUI/models/checkpoints -o ltx-video-2b-v0.9.safetensors\n",
|
| 19 |
+
"\n",
|
| 20 |
+
"!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/gokaygokay/Flux-Prompt-Enhance/raw/main/config.json -d /content/ComfyUI/models/LLM/Flux-Prompt-Enhance -o config.json\n",
|
| 21 |
+
"!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/gokaygokay/Flux-Prompt-Enhance/raw/main/generation_config.json -d /content/ComfyUI/models/LLM/Flux-Prompt-Enhance -o generation_config.json\n",
|
| 22 |
+
"!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/gokaygokay/Flux-Prompt-Enhance/resolve/main/model.safetensors -d /content/ComfyUI/models/LLM/Flux-Prompt-Enhance -o model.safetensors\n",
|
| 23 |
+
"!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/gokaygokay/Flux-Prompt-Enhance/raw/main/special_tokens_map.json -d /content/ComfyUI/models/LLM/Flux-Prompt-Enhance -o special_tokens_map.json\n",
|
| 24 |
+
"!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/gokaygokay/Flux-Prompt-Enhance/resolve/main/spiece.model -d /content/ComfyUI/models/LLM/Flux-Prompt-Enhance -o spiece.model\n",
|
| 25 |
+
"!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/gokaygokay/Flux-Prompt-Enhance/raw/main/tokenizer.json -d /content/ComfyUI/models/LLM/Flux-Prompt-Enhance -o tokenizer.json\n",
|
| 26 |
+
"!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/gokaygokay/Flux-Prompt-Enhance/raw/main/tokenizer_config.json -d /content/ComfyUI/models/LLM/Flux-Prompt-Enhance -o tokenizer_config.json"
|
| 27 |
+
]
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
"cell_type": "code",
|
| 31 |
+
"execution_count": null,
|
| 32 |
+
"metadata": {},
|
| 33 |
+
"outputs": [],
|
| 34 |
+
"source": [
|
| 35 |
+
"%cd /content/ComfyUI\n",
|
| 36 |
+
"\n",
|
| 37 |
+
"import os, shutil, json, requests, random, time\n",
|
| 38 |
+
"from urllib.parse import urlsplit\n",
|
| 39 |
+
"\n",
|
| 40 |
+
"import torch\n",
|
| 41 |
+
"from PIL import Image\n",
|
| 42 |
+
"from moviepy.editor import ImageSequenceClip\n",
|
| 43 |
+
"import numpy as np\n",
|
| 44 |
+
"\n",
|
| 45 |
+
"from nodes import NODE_CLASS_MAPPINGS, load_custom_node\n",
|
| 46 |
+
"from comfy_extras import nodes_images, nodes_lt, nodes_custom_sampler\n",
|
| 47 |
+
"\n",
|
| 48 |
+
"load_custom_node(\"/content/ComfyUI/custom_nodes/ComfyUI-Fluxpromptenhancer\")\n",
|
| 49 |
+
"\n",
|
| 50 |
+
"FluxPromptEnhance = NODE_CLASS_MAPPINGS[\"FluxPromptEnhance\"]()\n",
|
| 51 |
+
"CLIPLoader = NODE_CLASS_MAPPINGS[\"CLIPLoader\"]()\n",
|
| 52 |
+
"CLIPTextEncode = NODE_CLASS_MAPPINGS[\"CLIPTextEncode\"]()\n",
|
| 53 |
+
"CheckpointLoaderSimple = NODE_CLASS_MAPPINGS[\"CheckpointLoaderSimple\"]()\n",
|
| 54 |
+
"LTXVConditioning = nodes_lt.NODE_CLASS_MAPPINGS[\"LTXVConditioning\"]()\n",
|
| 55 |
+
"SamplerCustom = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"SamplerCustom\"]()\n",
|
| 56 |
+
"KSamplerSelect = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"KSamplerSelect\"]()\n",
|
| 57 |
+
"LTXVScheduler = nodes_lt.NODE_CLASS_MAPPINGS[\"LTXVScheduler\"]()\n",
|
| 58 |
+
"EmptyLTXVLatentVideo = nodes_lt.NODE_CLASS_MAPPINGS[\"EmptyLTXVLatentVideo\"]()\n",
|
| 59 |
+
"VAEDecode = NODE_CLASS_MAPPINGS[\"VAEDecode\"]()\n",
|
| 60 |
+
"SaveAnimatedWEBP = nodes_images.NODE_CLASS_MAPPINGS[\"SaveAnimatedWEBP\"]()\n",
|
| 61 |
+
"\n",
|
| 62 |
+
"with torch.inference_mode():\n",
|
| 63 |
+
" clip = CLIPLoader.load_clip(\"t5xxl_fp16.safetensors\", type=\"ltxv\")[0]\n",
|
| 64 |
+
" model, _, vae = CheckpointLoaderSimple.load_checkpoint(\"ltx-video-2b-v0.9.safetensors\")\n",
|
| 65 |
+
"\n",
|
| 66 |
+
"def download_file(url, save_dir, file_name):\n",
|
| 67 |
+
" os.makedirs(save_dir, exist_ok=True)\n",
|
| 68 |
+
" file_suffix = os.path.splitext(urlsplit(url).path)[1]\n",
|
| 69 |
+
" file_name_with_suffix = file_name + file_suffix\n",
|
| 70 |
+
" file_path = os.path.join(save_dir, file_name_with_suffix)\n",
|
| 71 |
+
" response = requests.get(url)\n",
|
| 72 |
+
" response.raise_for_status()\n",
|
| 73 |
+
" with open(file_path, 'wb') as file:\n",
|
| 74 |
+
" file.write(response.content)\n",
|
| 75 |
+
" return file_path\n",
|
| 76 |
+
"\n",
|
| 77 |
+
"def webp_to_mp4(input_webp, output_mp4, fps=10):\n",
|
| 78 |
+
" with Image.open(input_webp) as img:\n",
|
| 79 |
+
" frames = []\n",
|
| 80 |
+
" try:\n",
|
| 81 |
+
" while True:\n",
|
| 82 |
+
" frame = img.copy()\n",
|
| 83 |
+
" frames.append(frame)\n",
|
| 84 |
+
" img.seek(img.tell() + 1)\n",
|
| 85 |
+
" except EOFError:\n",
|
| 86 |
+
" pass\n",
|
| 87 |
+
" temp_dir = \"temp_frames\"\n",
|
| 88 |
+
" os.makedirs(temp_dir, exist_ok=True)\n",
|
| 89 |
+
" temp_frame_paths = []\n",
|
| 90 |
+
" for i, frame in enumerate(frames):\n",
|
| 91 |
+
" frame_path = os.path.join(temp_dir, f\"frame_{i:04d}.png\")\n",
|
| 92 |
+
" frame.save(frame_path)\n",
|
| 93 |
+
" temp_frame_paths.append(frame_path)\n",
|
| 94 |
+
" clip = ImageSequenceClip(temp_frame_paths, fps=fps)\n",
|
| 95 |
+
" clip.write_videofile(output_mp4, codec=\"libx264\", fps=fps)\n",
|
| 96 |
+
" for path in temp_frame_paths:\n",
|
| 97 |
+
" os.remove(path)\n",
|
| 98 |
+
" os.rmdir(temp_dir)\n",
|
| 99 |
+
"\n",
|
| 100 |
+
"@torch.inference_mode()\n",
|
| 101 |
+
"def generate(input):\n",
|
| 102 |
+
" values = input[\"input\"]\n",
|
| 103 |
+
"\n",
|
| 104 |
+
" positive_prompt = values['positive_prompt']\n",
|
| 105 |
+
" negative_prompt = values['negative_prompt']\n",
|
| 106 |
+
" frame_rate = values['frame_rate']\n",
|
| 107 |
+
" sampler_name = values['sampler_name']\n",
|
| 108 |
+
" steps = values['steps']\n",
|
| 109 |
+
" max_shift = values['max_shift']\n",
|
| 110 |
+
" base_shift = values['base_shift']\n",
|
| 111 |
+
" stretch = values['stretch']\n",
|
| 112 |
+
" terminal = values['terminal']\n",
|
| 113 |
+
" width = values['width']\n",
|
| 114 |
+
" height = values['height']\n",
|
| 115 |
+
" length = values['length']\n",
|
| 116 |
+
" add_noise = values['add_noise']\n",
|
| 117 |
+
" noise_seed = values['noise_seed']\n",
|
| 118 |
+
" cfg = values['cfg']\n",
|
| 119 |
+
" fps = values['fps']\n",
|
| 120 |
+
" prompt_enhance = values['prompt_enhance']\n",
|
| 121 |
+
"\n",
|
| 122 |
+
" if noise_seed == 0:\n",
|
| 123 |
+
" random.seed(int(time.time()))\n",
|
| 124 |
+
" noise_seed = random.randint(0, 18446744073709551615)\n",
|
| 125 |
+
" print(noise_seed)\n",
|
| 126 |
+
"\n",
|
| 127 |
+
" if prompt_enhance:\n",
|
| 128 |
+
" positive_prompt = FluxPromptEnhance.enhance_prompt(positive_prompt, noise_seed)[0]\n",
|
| 129 |
+
" print(positive_prompt)\n",
|
| 130 |
+
" conditioning_positive = CLIPTextEncode.encode(clip, positive_prompt)[0]\n",
|
| 131 |
+
" conditioning_negative = CLIPTextEncode.encode(clip, negative_prompt)[0]\n",
|
| 132 |
+
" positive, negative = LTXVConditioning.append(conditioning_positive, conditioning_negative, frame_rate)\n",
|
| 133 |
+
" sampler = KSamplerSelect.get_sampler(sampler_name)[0]\n",
|
| 134 |
+
" sigmas = LTXVScheduler.get_sigmas(steps, max_shift, base_shift, stretch, terminal, latent=None)[0]\n",
|
| 135 |
+
" latent_image = EmptyLTXVLatentVideo.generate(width, height, length, batch_size=1)[0]\n",
|
| 136 |
+
" samples = SamplerCustom.sample(model, add_noise, noise_seed, cfg, positive, negative, sampler, sigmas, latent_image)[0]\n",
|
| 137 |
+
" images = VAEDecode.decode(vae, samples)[0].detach()\n",
|
| 138 |
+
" video = SaveAnimatedWEBP.save_images(images, fps, filename_prefix=f\"ltx-video-{noise_seed}-tost\", lossless=False, quality=90, method=\"default\")\n",
|
| 139 |
+
" source = video['ui']['images'][0]['filename']\n",
|
| 140 |
+
" source = f\"/content/ComfyUI/output/{source}\"\n",
|
| 141 |
+
" destination = f\"/content/ltx-video-{noise_seed}-tost.webp\"\n",
|
| 142 |
+
" shutil.move(source, destination)\n",
|
| 143 |
+
" webp_to_mp4(f\"/content/ltx-video-{noise_seed}-tost.webp\", f\"/content/ltx-video-{noise_seed}-tost.mp4\", fps=fps)\n",
|
| 144 |
+
" \n",
|
| 145 |
+
" result = f\"/content/ltx-video-{noise_seed}-tost.mp4\"\n",
|
| 146 |
+
"\n",
|
| 147 |
+
" return result"
|
| 148 |
+
]
|
| 149 |
+
},
|
| 150 |
+
{
|
| 151 |
+
"cell_type": "code",
|
| 152 |
+
"execution_count": null,
|
| 153 |
+
"metadata": {},
|
| 154 |
+
"outputs": [],
|
| 155 |
+
"source": [
|
| 156 |
+
"input = { \n",
|
| 157 |
+
" \"input\": {\n",
|
| 158 |
+
" \"positive_prompt\": \"The camera follows behind a white vintage SUV with a black roof rack as it speeds up a steep dirt road surrounded by pine trees on a steep mountain slope, dust kicks up from it’s tires, the sunlight shines on the SUV as it speeds along the dirt road, casting a warm glow over the scene. The dirt road curves gently into the distance, with no other cars or vehicles in sight. The trees on either side of the road are redwoods, with patches of greenery scattered throughout. The car is seen from the rear following the curve with ease, making it seem as if it is on a rugged drive through the rugged terrain. The dirt road itself is surrounded by steep hills and mountains, with a clear blue sky above with wispy clouds.\",\n",
|
| 159 |
+
" \"negative_prompt\": \"low quality, worst quality, deformed, distorted, disfigured, motion smear, motion artifacts, fused fingers, bad anatomy, weird hand, ugly\",\n",
|
| 160 |
+
" \"frame_rate\": 25,\n",
|
| 161 |
+
" \"sampler_name\": \"euler\",\n",
|
| 162 |
+
" \"steps\": 30,\n",
|
| 163 |
+
" \"max_shift\": 2.05,\n",
|
| 164 |
+
" \"base_shift\": 0.95,\n",
|
| 165 |
+
" \"stretch\": True,\n",
|
| 166 |
+
" \"terminal\": 0.10,\n",
|
| 167 |
+
" \"width\": 768,\n",
|
| 168 |
+
" \"height\": 512,\n",
|
| 169 |
+
" \"length\": 97,\n",
|
| 170 |
+
" \"add_noise\": True,\n",
|
| 171 |
+
" \"noise_seed\": 0,\n",
|
| 172 |
+
" \"cfg\": 3.0,\n",
|
| 173 |
+
" \"fps\": 24,\n",
|
| 174 |
+
" \"prompt_enhance\": True\n",
|
| 175 |
+
" }\n",
|
| 176 |
+
"}\n",
|
| 177 |
+
"video = generate(input)\n",
|
| 178 |
+
"from IPython.display import Video\n",
|
| 179 |
+
"Video(video, embed=True)"
|
| 180 |
+
]
|
| 181 |
+
}
|
| 182 |
+
],
|
| 183 |
+
"metadata": {
|
| 184 |
+
"kernelspec": {
|
| 185 |
+
"display_name": "ComfyUI0-venv",
|
| 186 |
+
"language": "python",
|
| 187 |
+
"name": "python3"
|
| 188 |
+
},
|
| 189 |
+
"language_info": {
|
| 190 |
+
"codemirror_mode": {
|
| 191 |
+
"name": "ipython",
|
| 192 |
+
"version": 3
|
| 193 |
+
},
|
| 194 |
+
"file_extension": ".py",
|
| 195 |
+
"mimetype": "text/x-python",
|
| 196 |
+
"name": "python",
|
| 197 |
+
"nbconvert_exporter": "python",
|
| 198 |
+
"pygments_lexer": "ipython3",
|
| 199 |
+
"version": "3.10.12"
|
| 200 |
+
}
|
| 201 |
+
},
|
| 202 |
+
"nbformat": 4,
|
| 203 |
+
"nbformat_minor": 2
|
| 204 |
+
}
|