├── Flux.1-dev-Union_CN-jupyter.ipynb ├── Flux.1-dev-XLabs_CN-jupyter.ipynb └── README.md /Flux.1-dev-Union_CN-jupyter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "id": "VjYy0F2gZIPR", 8 | "cellView": "form" 9 | }, 10 | "outputs": [], 11 | "source": [ 12 | "#@markdown

Install

\n", 13 | "\n", 14 | "%cd /content\n", 15 | "!git clone -b totoro5 https://github.com/camenduru/ComfyUI /content/TotoroUI\n", 16 | "!git clone -b totoro https://github.com/LucipherDev/ComfyUI-GGUF /content/TotoroUI/custom_nodes/TotoroUI-GGUF\n", 17 | "%cd /content/TotoroUI\n", 18 | "\n", 19 | "!pip install -q torchsde einops diffusers accelerate xformers==0.0.28.post2\n", 20 | "!pip install -q git+https://github.com/LucipherDev/controlnet_aux.git\n", 21 | "!pip install -q -r /content/TotoroUI/custom_nodes/TotoroUI-GGUF/requirements.txt\n", 22 | "!apt -y install -qq aria2\n", 23 | "\n", 24 | "import nodes\n", 25 | "\n", 26 | "if not nodes.load_custom_node(\"custom_nodes/TotoroUI-GGUF\"):\n", 27 | " raise Exception(\"Failed to load GGUF custom node\")" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "source": [ 33 | "#@markdown

Load Models

\n", 34 | "\n", 35 | "import torch\n", 36 | "from nodes import NODE_CLASS_MAPPINGS\n", 37 | "\n", 38 | "DualCLIPLoaderGGUF = NODE_CLASS_MAPPINGS[\"DualCLIPLoaderGGUF\"]()\n", 39 | "UnetLoaderGGUF = NODE_CLASS_MAPPINGS[\"UnetLoaderGGUF\"]()\n", 40 | "VAELoader = NODE_CLASS_MAPPINGS[\"VAELoader\"]()\n", 41 | "ControlNetLoader = NODE_CLASS_MAPPINGS[\"ControlNetLoader\"]()\n", 42 | "\n", 43 | "system_ram = \"low ram (Q2_K)\" # @param [\"low ram (Q2_K)\", \"high ram (Q8_0)\"]\n", 44 | "\n", 45 | "if system_ram == \"low ram (Q2_K)\":\n", 46 | " print(f\"Downloading Flux1-dev-Q2_K...\")\n", 47 | " !aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/city96/FLUX.1-dev-gguf/resolve/main/flux1-dev-Q2_K.gguf -d /content/TotoroUI/models/unet -o flux1-dev.gguf\n", 48 | "elif system_ram == \"high ram (Q8_0)\":\n", 49 | " print(f\"Downloading Flux1-dev-Q8_0...\")\n", 50 | " !aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/city96/FLUX.1-dev-gguf/resolve/main/flux1-dev-Q8_0.gguf -d /content/TotoroUI/models/unet -o flux1-dev.gguf\n", 51 | "\n", 52 | "print(\"Downloading VAE...\")\n", 53 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/camenduru/FLUX.1-dev/resolve/main/ae.sft -d /content/TotoroUI/models/vae -o ae.sft\n", 54 | "\n", 55 | "print(\"Downloading Clips...\")\n", 56 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/camenduru/FLUX.1-dev/resolve/main/clip_l.safetensors -d /content/TotoroUI/models/clip -o clip_l.safetensors\n", 57 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/city96/t5-v1_1-xxl-encoder-gguf/resolve/main/t5-v1_1-xxl-encoder-Q3_K_L.gguf -d /content/TotoroUI/models/clip -o t5-v1_1-xxl-encoder-Q3_K_L.gguf\n", 58 | "\n", 59 | "print(\"Downloading Controlnet Preprocessors...\")\n", 60 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/Kijai/DepthAnythingV2-safetensors/resolve/main/depth_anything_v2_vitl_fp16.safetensors -d /content/TotoroUI/models/controlnet_preprocessors -o depth_anything_v2_vitl_fp16.safetensors\n", 61 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/lllyasviel/Annotators/resolve/main/ControlNetHED.pth -d /content/TotoroUI/models/controlnet_preprocessors -o ControlNetHED.pth\n", 62 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/lllyasviel/Annotators/resolve/main/body_pose_model.pth -d /content/TotoroUI/models/controlnet_preprocessors -o body_pose_model.pth\n", 63 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/lllyasviel/Annotators/resolve/main/hand_pose_model.pth -d /content/TotoroUI/models/controlnet_preprocessors -o hand_pose_model.pth\n", 64 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/lllyasviel/Annotators/resolve/main/facenet.pth -d /content/TotoroUI/models/controlnet_preprocessors -o facenet.pth\n", 65 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/lllyasviel/Annotators/resolve/main/sk_model.pth -d /content/TotoroUI/models/controlnet_preprocessors -o sk_model.pth\n", 66 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/lllyasviel/Annotators/resolve/main/sk_model2.pth -d /content/TotoroUI/models/controlnet_preprocessors -o sk_model2.pth\n", 67 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/fal/teed/resolve/main/5_model.pth -d /content/TotoroUI/models/controlnet_preprocessors -o 5_model.pth\n", 68 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/lllyasviel/Annotators/resolve/main/table5_pidinet.pth -d /content/TotoroUI/models/controlnet_preprocessors -o table5_pidinet.pth\n", 69 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/lllyasviel/Annotators/resolve/main/scannet.pt -d /content/TotoroUI/models/controlnet_preprocessors -o scannet.pt\n", 70 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/lllyasviel/Annotators/resolve/main/mlsd_large_512_fp32.pth -d /content/TotoroUI/models/controlnet_preprocessors -omlsd_large_512_fp32.pth\n", 71 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/lllyasviel/Annotators/resolve/main/netG.pth -d /content/TotoroUI/models/controlnet_preprocessors -o netG.pth\n", 72 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/ybelkada/segment-anything/resolve/main/checkpoints/sam_vit_b_01ec64.pth -d /content/TotoroUI/models/controlnet_preprocessors -o sam_vit_b.pth\n", 73 | "\n", 74 | "print(\"Downloading Controlnet Union...\")\n", 75 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/Shakker-Labs/FLUX.1-dev-ControlNet-Union-Pro/resolve/main/diffusion_pytorch_model.safetensors -d /content/TotoroUI/models/controlnet -o FLUX.1-dev-Controlnet-Union-Pro.safetensors\n", 76 | "\n", 77 | "with torch.inference_mode():\n", 78 | " print(\"Loading Clips...\")\n", 79 | " clip = DualCLIPLoaderGGUF.load_clip(\"t5-v1_1-xxl-encoder-Q3_K_L.gguf\", \"clip_l.safetensors\", \"flux\")[0]\n", 80 | " print(\"Loading VAE...\")\n", 81 | " vae = VAELoader.load_vae(\"ae.sft\")[0]\n", 82 | " print(f\"Loading Flux.1-dev...\")\n", 83 | " unet = UnetLoaderGGUF.load_unet(f\"flux1-dev.gguf\")[0]\n", 84 | " print(\"Loading Controlnet Union...\")\n", 85 | " controlnet = ControlNetLoader.load_controlnet(\"FLUX.1-dev-Controlnet-Union-Pro.safetensors\")[0]\n", 86 | "\n", 87 | " unet_f, clip_f = unet, clip\n", 88 | "\n", 89 | "print(\"All Models Loaded!\")\n", 90 | "\n", 91 | "import warnings\n", 92 | "warnings.simplefilter(action='ignore', category=FutureWarning)\n", 93 | "warnings.simplefilter(action='ignore', category=UserWarning)\n", 94 | "\n", 95 | "import re\n", 96 | "import os\n", 97 | "import gc\n", 98 | "import random\n", 99 | "import numpy as np\n", 100 | "from PIL import Image\n", 101 | "from google.colab import files\n", 102 | "\n", 103 | "import nodes\n", 104 | "from totoro_extras import nodes_custom_sampler\n", 105 | "from totoro_extras import nodes_post_processing\n", 106 | "from totoro_extras import nodes_flux\n", 107 | "from totoro_extras import nodes_controlnet\n", 108 | "from totoro import model_management\n", 109 | "\n", 110 | "from controlnet_aux import CannyDetector, DepthAnythingDetector, HEDdetector, OpenposeDetector, PidiNetDetector, TEEDdetector, LineartDetector, LineartAnimeDetector, MLSDdetector, NormalBaeDetector, SamDetector\n", 111 | "\n", 112 | "CLIPTextEncodeFlux = nodes_flux.NODE_CLASS_MAPPINGS[\"CLIPTextEncodeFlux\"]()\n", 113 | "RandomNoise = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"RandomNoise\"]()\n", 114 | "BasicGuider = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"BasicGuider\"]()\n", 115 | "KSamplerSelect = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"KSamplerSelect\"]()\n", 116 | "BasicScheduler = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"BasicScheduler\"]()\n", 117 | "SamplerCustomAdvanced = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"SamplerCustomAdvanced\"]()\n", 118 | "LoraLoader = NODE_CLASS_MAPPINGS[\"LoraLoader\"]()\n", 119 | "VAEDecode = NODE_CLASS_MAPPINGS[\"VAEDecode\"]()\n", 120 | "VAEEncode = NODE_CLASS_MAPPINGS[\"VAEEncode\"]()\n", 121 | "LoadImage = NODE_CLASS_MAPPINGS[\"LoadImage\"]()\n", 122 | "EmptyLatentImage = NODE_CLASS_MAPPINGS[\"EmptyLatentImage\"]()\n", 123 | "ImageScaleToTotalPixels = nodes_post_processing.NODE_CLASS_MAPPINGS[\"ImageScaleToTotalPixels\"]()\n", 124 | "SetUnionControlNetType = nodes_controlnet.NODE_CLASS_MAPPINGS[\"SetUnionControlNetType\"]()\n", 125 | "ControlNetApplyAdvanced = NODE_CLASS_MAPPINGS[\"ControlNetApplyAdvanced\"]()" 126 | ], 127 | "metadata": { 128 | "id": "k3aTOrdb8HxC", 129 | "cellView": "form" 130 | }, 131 | "execution_count": null, 132 | "outputs": [] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "source": [ 137 | "# @markdown

Functions

\n", 138 | "\n", 139 | "loras = {\n", 140 | " \"xlabs_flux_anime\":\n", 141 | " {\n", 142 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/anime_lora_comfy_converted.safetensors\",\n", 143 | " \"filename\": \"xlabs_anime_lora.safetensors\",\n", 144 | " \"triggers\": \"anime\"\n", 145 | " },\n", 146 | " \"xlabs_flux_art\":\n", 147 | " {\n", 148 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/art_lora_comfy_converted.safetensors\",\n", 149 | " \"filename\": \"xlabs_art_lora.safetensors\",\n", 150 | " \"triggers\": \"art\"\n", 151 | " },\n", 152 | " \"xlabs_flux_disney\":\n", 153 | " {\n", 154 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/disney_lora_comfy_converted.safetensors\",\n", 155 | " \"filename\": \"xlabs_disney_lora.safetensors\",\n", 156 | " \"triggers\": \"disney style\"\n", 157 | " },\n", 158 | " \"xlabs_flux_mjv6\":\n", 159 | " {\n", 160 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/mjv6_lora_comfy_converted.safetensors\",\n", 161 | " \"filename\": \"xlabs_mjv6_lora.safetensors\"\n", 162 | " },\n", 163 | " \"xlabs_flux_realism\":\n", 164 | " {\n", 165 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/realism_lora_comfy_converted.safetensors\",\n", 166 | " \"filename\": \"xlabs_realism_lora.safetensors\"\n", 167 | " },\n", 168 | " \"xlabs_flux_scenery\":\n", 169 | " {\n", 170 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/scenery_lora_comfy_converted.safetensors\",\n", 171 | " \"filename\": \"xlabs_scenery_lora.safetensors\",\n", 172 | " \"triggers\": \"scenery style\"\n", 173 | " },\n", 174 | " \"xlabs_flux_furry\":\n", 175 | " {\n", 176 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/furry_lora.safetensors\",\n", 177 | " \"filename\": \"xlabs_flux_furry_lora.safetensors\"\n", 178 | " }\n", 179 | "}\n", 180 | "\n", 181 | "\n", 182 | "def load_loras(prompt):\n", 183 | " # @markdown \n", 184 | "\n", 185 | " global unet, clip, unet_f, clip_f\n", 186 | "\n", 187 | " unet_f, clip_f = unet, clip\n", 188 | "\n", 189 | " matches = re.findall(r\"<\\s*([^:]+?)\\s*:\\s*([0-9.]+)\\s*>\", prompt)\n", 190 | "\n", 191 | " loras_list = [(name.strip(), float(value)) for name, value in matches]\n", 192 | "\n", 193 | " if len(loras_list):\n", 194 | " print(\"Loading Loras...\")\n", 195 | "\n", 196 | " for lora_tuple in loras_list:\n", 197 | " lora = loras.get(lora_tuple[0], None)\n", 198 | "\n", 199 | " if lora:\n", 200 | " !aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M {lora[\"url\"]} -d /content/TotoroUI/models/loras -o {lora[\"filename\"]}\n", 201 | "\n", 202 | " with torch.inference_mode():\n", 203 | " unet_f, clip_f = LoraLoader.load_lora(unet_f, clip_f, lora[\"filename\"], lora_tuple[1], lora_tuple[1])\n", 204 | "\n", 205 | " print(f\"Loaded Lora: {lora_tuple[0]}\")\n", 206 | " else:\n", 207 | " print(f\"Lora not listed: {lora_tuple[0]}\")\n", 208 | "\n", 209 | "def clean_prompt(prompt):\n", 210 | " cleaned_prompt = re.sub(r\"<.*?>\", \"\", prompt)\n", 211 | "\n", 212 | " return cleaned_prompt\n", 213 | "\n", 214 | "def cuda_gc():\n", 215 | " try:\n", 216 | " model_management.soft_empty_cache()\n", 217 | " gc.collect()\n", 218 | " torch.cuda.empty_cache()\n", 219 | " torch.cuda.ipc_collect()\n", 220 | " except:\n", 221 | " pass\n", 222 | "\n", 223 | "def img_tensor_to_np(img_tensor):\n", 224 | " img_tensor = img_tensor.clone() * 255.0\n", 225 | " return img_tensor.squeeze().numpy().astype(np.uint8)\n", 226 | "\n", 227 | "def img_np_to_tensor(img_np_list):\n", 228 | " return torch.from_numpy(img_np_list.astype(np.float32) / 255.0).unsqueeze(0)\n", 229 | "\n", 230 | "def controlnet_preprocess(width, height):\n", 231 | " # @markdown \n", 232 | "\n", 233 | " process_image = True # @param {\"type\":\"boolean\"}\n", 234 | " preprocessor_type = \"openpose\" # @param [\"none\", \"openpose\", \"depth\", \"hed\", \"pidi\", \"scribble\", \"ted\", \"canny\", \"lineart\", \"anime_lineart\", \"mlsd\", \"normal\", \"segment\"]\n", 235 | " input_image = \"/content/test.png\" # @param {\"type\":\"string\"}\n", 236 | " resolution = 512 # @param {\"type\":\"slider\",\"min\":512,\"max\":2048,\"step\":1}\n", 237 | " resize_mode = \"Just Resize\" # @param [\"Just Resize\",\"Resize and Fill\",\"Crop and Resize\"]\n", 238 | "\n", 239 | " image_input = LoadImage.load_image(input_image)[0]\n", 240 | "\n", 241 | " if process_image:\n", 242 | " image_np = img_tensor_to_np(image_input)\n", 243 | " img = Image.fromarray(image_np)\n", 244 | "\n", 245 | " if resize_mode == \"Just Resize\":\n", 246 | " img = img.resize((width, height), Image.Resampling.LANCZOS)\n", 247 | "\n", 248 | " elif resize_mode == \"Resize and Fill\":\n", 249 | " img.thumbnail((width, height), Image.ANTIALIAS)\n", 250 | " result = Image.new(\"RGB\", (width, height), (0, 0, 0))\n", 251 | " offset = ((width - img.width) // 2, (height - img.height) // 2)\n", 252 | " result.paste(img, offset)\n", 253 | " img = result\n", 254 | "\n", 255 | " elif resize_mode == \"Crop and Resize\":\n", 256 | " src_width, src_height = img.size\n", 257 | " src_aspect = src_width / src_height\n", 258 | " target_aspect = width / height\n", 259 | "\n", 260 | " if src_aspect > target_aspect:\n", 261 | " new_width = int(src_height * target_aspect)\n", 262 | " left = (src_width - new_width) // 2\n", 263 | " img = img.crop((left, 0, left + new_width, src_height))\n", 264 | " else:\n", 265 | " new_height = int(src_width / target_aspect)\n", 266 | " top = (src_height - new_height) // 2\n", 267 | " img = img.crop((0, top, src_width, top + new_height))\n", 268 | "\n", 269 | " img = img.resize((width, height), Image.Resampling.LANCZOS)\n", 270 | "\n", 271 | " image_np = np.array(img).astype(np.uint8)\n", 272 | "\n", 273 | " if preprocessor_type == \"none\":\n", 274 | " processed_image = Image.fromarray(image_np)\n", 275 | "\n", 276 | " if preprocessor_type == \"canny\":\n", 277 | " canny = CannyDetector()\n", 278 | " processed_image = canny(image_np, detect_resolution=resolution, image_resolution=resolution)\n", 279 | "\n", 280 | " elif preprocessor_type == \"depth\":\n", 281 | " depth = DepthAnythingDetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"depth_anything_v2_vitl_fp16.safetensors\")\n", 282 | " processed_image = depth(image_np, detect_resolution=resolution, image_resolution=resolution)\n", 283 | "\n", 284 | " elif preprocessor_type == \"hed\":\n", 285 | " hed = HEDdetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"ControlNetHED.pth\")\n", 286 | " processed_image = hed(image_np, detect_resolution=resolution, image_resolution=resolution)\n", 287 | "\n", 288 | " elif preprocessor_type == \"openpose\":\n", 289 | " openpose = OpenposeDetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"body_pose_model.pth\", hand_filename=\"hand_pose_model.pth\", face_filename=\"facenet.pth\")\n", 290 | " processed_image = openpose(image_np, detect_resolution=resolution, image_resolution=resolution, include_hand=True, include_face=True)\n", 291 | "\n", 292 | " elif preprocessor_type == \"pidi\":\n", 293 | " pidi = PidiNetDetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"table5_pidinet.pth\")\n", 294 | " processed_image = pidi(image_np, detect_resolution=resolution, image_resolution=resolution, safe=True)\n", 295 | "\n", 296 | " elif preprocessor_type == \"scribble\":\n", 297 | " scribble = HEDdetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"ControlNetHED.pth\")\n", 298 | " processed_image = scribble(image_np, detect_resolution=resolution, image_resolution=resolution, scribble=True)\n", 299 | "\n", 300 | " elif preprocessor_type == \"ted\":\n", 301 | " ted = TEEDdetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"5_model.pth\")\n", 302 | " processed_image = ted(image_np, detect_resolution=resolution)\n", 303 | "\n", 304 | " elif preprocessor_type == \"lineart\":\n", 305 | " lineart = LineartDetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"sk_model.pth\", coarse_filename=\"sk_model2.pth\")\n", 306 | " processed_image = lineart(image_np, detect_resolution=resolution, image_resolution=resolution, coarse=True)\n", 307 | "\n", 308 | " elif preprocessor_type == \"anime_lineart\":\n", 309 | " anime_lineart = LineartAnimeDetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"netG.pth\")\n", 310 | " processed_image = anime_lineart(image_np, detect_resolution=resolution, image_resolution=resolution)\n", 311 | "\n", 312 | " elif preprocessor_type == \"mlsd\":\n", 313 | " mlsd = MLSDdetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"mlsd_large_512_fp32.pth\")\n", 314 | " processed_image = mlsd(image_np, detect_resolution=resolution, image_resolution=resolution)\n", 315 | "\n", 316 | " elif preprocessor_type == \"normal\":\n", 317 | " normal = NormalBaeDetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"scannet.pt\")\n", 318 | " processed_image = normal(image_np, detect_resolution=resolution, image_resolution=resolution)\n", 319 | "\n", 320 | " elif preprocessor_type == \"segment\":\n", 321 | " segment = SamDetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", model_type=\"vit_b\", filename=\"sam_vit_b.pth\")\n", 322 | " processed_image = segment(image_np, detect_resolution=resolution, image_resolution=resolution)\n", 323 | "\n", 324 | " processed_image_np = np.array(processed_image)\n", 325 | " processed_image_tensor = img_np_to_tensor(processed_image_np)\n", 326 | "\n", 327 | " display(Image.fromarray(processed_image_np))\n", 328 | "\n", 329 | " return processed_image_tensor\n", 330 | "\n", 331 | " else:\n", 332 | " return image_input\n", 333 | "\n", 334 | "def apply_controlnet(cond, width, height):\n", 335 | " # @markdown \n", 336 | "\n", 337 | " controlnet_type = \"openpose\" # @param [\"openpose\", \"depth\", \"hed/pidi/scribble/ted\", \"canny/lineart/anime_lineart/mlsd\", \"normal\", \"segment\", \"tile\", \"repaint\" ]\n", 338 | " strength = 0.5 # @param {\"type\":\"slider\",\"min\":0.0,\"max\":10.0,\"step\":0.01}\n", 339 | " start_percent = 0 # @param {\"type\":\"slider\",\"min\":0.0,\"max\":1.0,\"step\":0.001}\n", 340 | " end_percent = 0.225 # @param {\"type\":\"slider\",\"min\":0.0,\"max\":1.0,\"step\":0.001}\n", 341 | "\n", 342 | " cond_neg = CLIPTextEncodeFlux.encode(clip_f, \"\", \"\", 0)[0]\n", 343 | "\n", 344 | " print(\"Loading Controlnet...\")\n", 345 | "\n", 346 | " preprocessed_image = controlnet_preprocess(width, height)\n", 347 | "\n", 348 | " controlnet_f = SetUnionControlNetType.set_controlnet_type(controlnet, controlnet_type)[0]\n", 349 | "\n", 350 | " cond = ControlNetApplyAdvanced.apply_controlnet(cond, cond_neg, controlnet_f, preprocessed_image, strength, start_percent, end_percent, vae)[0]\n", 351 | "\n", 352 | " del controlnet_f\n", 353 | "\n", 354 | " return cond\n", 355 | "\n", 356 | "def closestNumber(n, m):\n", 357 | " q = int(n / m)\n", 358 | " n1 = m * q\n", 359 | " if (n * m) > 0:\n", 360 | " n2 = m * (q + 1)\n", 361 | " else:\n", 362 | " n2 = m * (q - 1)\n", 363 | " if abs(n - n1) < abs(n - n2):\n", 364 | " return n1\n", 365 | " return n2\n", 366 | "\n", 367 | "def save_image(decoded, path, name, download=False):\n", 368 | " full_path = os.path.abspath(os.path.join(path, name))\n", 369 | " Image.fromarray(np.array(decoded*255, dtype=np.uint8)[0]).save( full_path)\n", 370 | "\n", 371 | " img = Image.open(full_path)\n", 372 | " display(img)\n", 373 | "\n", 374 | " if download:\n", 375 | " files.download(full_path)\n", 376 | "\n", 377 | "@torch.inference_mode()\n", 378 | "def generate(prompt, width, height, fixed_seed, guidance, steps, sampler_name, scheduler, batch_size, auto_download, mode=\"t2i\", input_img=None, denoise=1.0):\n", 379 | " global unet, clip, unet_f, clip_f\n", 380 | "\n", 381 | " print(\"Prompt Received\")\n", 382 | "\n", 383 | " load_loras(prompt)\n", 384 | " prompt = clean_prompt(prompt)\n", 385 | "\n", 386 | " if mode == \"t2i\":\n", 387 | " latent_image = EmptyLatentImage.generate(closestNumber(width, 16), closestNumber(height, 16))[0]\n", 388 | "\n", 389 | " elif mode == \"i2i\":\n", 390 | " image = LoadImage.load_image(input_img)[0]\n", 391 | " latent_image = ImageScaleToTotalPixels.upscale(image, \"lanczos\", 1.0)[0]\n", 392 | " latent_image = VAEEncode.encode(vae, latent_image)[0]\n", 393 | "\n", 394 | " cond = CLIPTextEncodeFlux.encode(clip_f, prompt, prompt, guidance)[0]\n", 395 | "\n", 396 | " cond = apply_controlnet(cond, width, height)\n", 397 | "\n", 398 | " guider = BasicGuider.get_guider(unet_f, cond)[0]\n", 399 | " sampler = KSamplerSelect.get_sampler(sampler_name)[0]\n", 400 | " sigmas = BasicScheduler.get_sigmas(unet_f, scheduler, steps, denoise)[0]\n", 401 | "\n", 402 | " for i in range(0, batch_size):\n", 403 | " if fixed_seed == 0:\n", 404 | " seed = random.randint(0, 18446744073709551615)\n", 405 | " else:\n", 406 | " seed = fixed_seed\n", 407 | "\n", 408 | " print(\"Seed:\", seed)\n", 409 | "\n", 410 | " noise = RandomNoise.get_noise(seed)[0]\n", 411 | " sample, sample_denoised = SamplerCustomAdvanced.sample(noise, guider, sampler, sigmas, latent_image)\n", 412 | " model_management.soft_empty_cache()\n", 413 | " decoded = VAEDecode.decode(vae, sample)[0].detach()\n", 414 | "\n", 415 | " save_image(decoded, \"/content\", f\"flux_{mode}_{seed}_{i}.png\", auto_download)\n", 416 | "\n", 417 | " cuda_gc()\n", 418 | "\n", 419 | "print(f\"{'Lora Name':<40} {'Trigger Words':<40}\")\n", 420 | "print(\"-\" * 80)\n", 421 | "\n", 422 | "for key_name, details in loras.items():\n", 423 | " trigger_words = details.get(\"triggers\", \"N/A\")\n", 424 | " print(f\"{key_name:<40} {trigger_words:<40}\")" 425 | ], 426 | "metadata": { 427 | "id": "mLGPKWvopwnC", 428 | "cellView": "form" 429 | }, 430 | "execution_count": null, 431 | "outputs": [] 432 | }, 433 | { 434 | "cell_type": "code", 435 | "execution_count": null, 436 | "metadata": { 437 | "cellView": "form", 438 | "id": "Ur9TmMNwC2kR" 439 | }, 440 | "outputs": [], 441 | "source": [ 442 | "#@markdown

Txt2Img

\n", 443 | "\n", 444 | "positive_prompt = \"\" # @param {\"type\":\"string\"}\n", 445 | "width = 512 # @param {\"type\":\"slider\",\"min\":256,\"max\":2048,\"step\":1}\n", 446 | "height = 512 # @param {\"type\":\"slider\",\"min\":256,\"max\":2048,\"step\":1}\n", 447 | "fixed_seed = 0 # @param {\"type\":\"slider\",\"min\":0,\"max\":18446744073709552000,\"step\":1}\n", 448 | "guidance = 4.5 # @param {\"type\":\"slider\",\"min\":0,\"max\":20,\"step\":0.5}\n", 449 | "steps = 25 # @param {\"type\":\"slider\",\"min\":4,\"max\":50,\"step\":1}\n", 450 | "sampler_name = \"euler\" # @param [\"euler\",\"heun\",\"heunpp2\",\"heunpp2\",\"dpm_2\",\"lms\",\"dpmpp_2m\",\"ipndm\",\"deis\",\"ddim\",\"uni_pc\",\"uni_pc_bh2\"]\n", 451 | "scheduler = \"simple\" # @param [\"normal\",\"sgm_uniform\",\"simple\",\"ddim_uniform\"]\n", 452 | "batch_size = 1 # @param {\"type\":\"slider\",\"min\":1,\"max\":20,\"step\":1}\n", 453 | "auto_download = False # @param {\"type\":\"boolean\"}\n", 454 | "\n", 455 | "generate(positive_prompt, width, height, fixed_seed, guidance, steps, sampler_name, scheduler, batch_size, auto_download)" 456 | ] 457 | }, 458 | { 459 | "cell_type": "code", 460 | "execution_count": null, 461 | "metadata": { 462 | "cellView": "form", 463 | "id": "Dpd2sfrePYoA" 464 | }, 465 | "outputs": [], 466 | "source": [ 467 | "#@markdown

Img2Img

\n", 468 | "\n", 469 | "positive_prompt = \"anime style\" # @param {\"type\":\"string\"}\n", 470 | "fixed_seed = 0 # @param {\"type\":\"slider\",\"min\":0,\"max\":18446744073709552000,\"step\":1}\n", 471 | "guidance = 4.5 # @param {\"type\":\"slider\",\"min\":0,\"max\":20,\"step\":0.5}\n", 472 | "steps = 25 # @param {\"type\":\"slider\",\"min\":4,\"max\":50,\"step\":1}\n", 473 | "sampler_name = \"euler\" # @param [\"euler\",\"heun\",\"heunpp2\",\"heunpp2\",\"dpm_2\",\"lms\",\"dpmpp_2m\",\"ipndm\",\"deis\",\"ddim\",\"uni_pc\",\"uni_pc_bh2\"]\n", 474 | "scheduler = \"simple\" # @param [\"normal\",\"sgm_uniform\",\"simple\",\"ddim_uniform\"]\n", 475 | "input_img = \"/content/test.png\" # @param {\"type\":\"string\"}\n", 476 | "denoise = 0.85 # @param {\"type\":\"slider\",\"min\":0,\"max\":1,\"step\":0.01}\n", 477 | "batch_size = 1 # @param {\"type\":\"slider\",\"min\":1,\"max\":20,\"step\":1}\n", 478 | "auto_download = False # @param {\"type\":\"boolean\"}\n", 479 | "\n", 480 | "\n", 481 | "generate(positive_prompt, 0, 0, fixed_seed, guidance, steps, sampler_name, scheduler, batch_size, auto_download, \"i2i\", input_img, denoise)" 482 | ] 483 | } 484 | ], 485 | "metadata": { 486 | "accelerator": "GPU", 487 | "colab": { 488 | "gpuType": "T4", 489 | "provenance": [] 490 | }, 491 | "kernelspec": { 492 | "display_name": "Python 3", 493 | "name": "python3" 494 | }, 495 | "language_info": { 496 | "name": "python" 497 | } 498 | }, 499 | "nbformat": 4, 500 | "nbformat_minor": 0 501 | } -------------------------------------------------------------------------------- /Flux.1-dev-XLabs_CN-jupyter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "id": "VjYy0F2gZIPR", 8 | "cellView": "form" 9 | }, 10 | "outputs": [], 11 | "source": [ 12 | "#@markdown

Install

\n", 13 | "\n", 14 | "%cd /content\n", 15 | "!git clone -b totoro6 https://github.com/LucipherDev/ComfyUI /content/TotoroUI\n", 16 | "!git clone -b totoro https://github.com/LucipherDev/ComfyUI-GGUF /content/TotoroUI/custom_nodes/TotoroUI-GGUF\n", 17 | "%cd /content/TotoroUI\n", 18 | "\n", 19 | "!pip install -q torchsde einops diffusers accelerate xformers==0.0.28.post2\n", 20 | "!pip install -q git+https://github.com/LucipherDev/controlnet_aux.git\n", 21 | "!pip install -q -r /content/TotoroUI/custom_nodes/TotoroUI-GGUF/requirements.txt\n", 22 | "!apt -y install -qq aria2\n", 23 | "\n", 24 | "import nodes\n", 25 | "\n", 26 | "if not nodes.load_custom_node(\"custom_nodes/TotoroUI-GGUF\"):\n", 27 | " raise Exception(\"Failed to load GGUF custom node\")" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": { 34 | "id": "k3aTOrdb8HxC", 35 | "cellView": "form" 36 | }, 37 | "outputs": [], 38 | "source": [ 39 | "#@markdown

Load Models

\n", 40 | "\n", 41 | "import torch\n", 42 | "from nodes import NODE_CLASS_MAPPINGS\n", 43 | "\n", 44 | "DualCLIPLoaderGGUF = NODE_CLASS_MAPPINGS[\"DualCLIPLoaderGGUF\"]()\n", 45 | "UnetLoaderGGUF = NODE_CLASS_MAPPINGS[\"UnetLoaderGGUF\"]()\n", 46 | "VAELoader = NODE_CLASS_MAPPINGS[\"VAELoader\"]()\n", 47 | "ControlNetLoader = NODE_CLASS_MAPPINGS[\"ControlNetLoader\"]()\n", 48 | "\n", 49 | "print(f\"Downloading Flux1-dev-Q4_K_S...\")\n", 50 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/city96/FLUX.1-dev-gguf/resolve/main/flux1-dev-Q4_K_S.gguf -d /content/TotoroUI/models/unet -o flux1-dev-Q4_K_S.gguf\n", 51 | "\n", 52 | "print(\"Downloading VAE...\")\n", 53 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/camenduru/FLUX.1-dev/resolve/main/ae.sft -d /content/TotoroUI/models/vae -o ae.sft\n", 54 | "\n", 55 | "print(\"Downloading Clips...\")\n", 56 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/camenduru/FLUX.1-dev/resolve/main/clip_l.safetensors -d /content/TotoroUI/models/clip -o clip_l.safetensors\n", 57 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/city96/t5-v1_1-xxl-encoder-gguf/resolve/main/t5-v1_1-xxl-encoder-Q6_K.gguf -d /content/TotoroUI/models/clip -o t5-v1_1-xxl-encoder-Q6_K.gguf\n", 58 | "\n", 59 | "print(\"Downloading Controlnet Preprocessors...\")\n", 60 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/Kijai/DepthAnythingV2-safetensors/resolve/main/depth_anything_v2_vitl_fp16.safetensors -d /content/TotoroUI/models/controlnet_preprocessors -o depth_anything_v2_vitl_fp16.safetensors\n", 61 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/lllyasviel/Annotators/resolve/main/ControlNetHED.pth -d /content/TotoroUI/models/controlnet_preprocessors -o ControlNetHED.pth\n", 62 | "\n", 63 | "print(\"Downloading X-Labs Controlnets...\")\n", 64 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/XLabs-AI/flux-controlnet-collections/resolve/main/flux-canny-controlnet-v3.safetensors -d /content/TotoroUI/models/controlnet -o flux-canny-controlnet-v3.safetensors\n", 65 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/XLabs-AI/flux-controlnet-collections/resolve/main/flux-depth-controlnet-v3.safetensors -d /content/TotoroUI/models/controlnet -o flux-depth-controlnet-v3.safetensors\n", 66 | "!aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M https://huggingface.co/XLabs-AI/flux-controlnet-collections/resolve/main/flux-hed-controlnet-v3.safetensors -d /content/TotoroUI/models/controlnet -o flux-hed-controlnet-v3.safetensors\n", 67 | "\n", 68 | "with torch.inference_mode():\n", 69 | " print(\"Loading VAE...\")\n", 70 | " vae = VAELoader.load_vae(\"ae.sft\")[0]\n", 71 | " print(f\"Loading Flux1-dev-Q4_K_S...\")\n", 72 | " unet = UnetLoaderGGUF.load_unet(f\"flux1-dev-Q4_K_S.gguf\")[0]\n", 73 | " print(\"Loading Clips...\")\n", 74 | " clip = DualCLIPLoaderGGUF.load_clip(\"t5-v1_1-xxl-encoder-Q6_K.gguf\", \"clip_l.safetensors\", \"flux\")[0]\n", 75 | "\n", 76 | " unet_f, clip_f = unet, clip\n", 77 | "\n", 78 | "print(\"All Models Loaded!\")\n", 79 | "\n", 80 | "import warnings\n", 81 | "warnings.simplefilter(action='ignore', category=FutureWarning)\n", 82 | "warnings.simplefilter(action='ignore', category=UserWarning)\n", 83 | "\n", 84 | "import re\n", 85 | "import os\n", 86 | "import random\n", 87 | "import numpy as np\n", 88 | "import gc\n", 89 | "from PIL import Image\n", 90 | "from google.colab import files\n", 91 | "\n", 92 | "import nodes\n", 93 | "from totoro_extras import nodes_custom_sampler\n", 94 | "from totoro_extras import nodes_post_processing\n", 95 | "from totoro_extras import nodes_flux\n", 96 | "from totoro_extras import nodes_controlnet\n", 97 | "from totoro import model_management\n", 98 | "\n", 99 | "from controlnet_aux import CannyDetector, DepthAnythingDetector, HEDdetector\n", 100 | "\n", 101 | "CLIPTextEncodeFlux = nodes_flux.NODE_CLASS_MAPPINGS[\"CLIPTextEncodeFlux\"]()\n", 102 | "RandomNoise = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"RandomNoise\"]()\n", 103 | "BasicGuider = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"BasicGuider\"]()\n", 104 | "KSamplerSelect = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"KSamplerSelect\"]()\n", 105 | "BasicScheduler = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"BasicScheduler\"]()\n", 106 | "SamplerCustomAdvanced = nodes_custom_sampler.NODE_CLASS_MAPPINGS[\"SamplerCustomAdvanced\"]()\n", 107 | "LoraLoader = NODE_CLASS_MAPPINGS[\"LoraLoader\"]()\n", 108 | "VAEDecode = NODE_CLASS_MAPPINGS[\"VAEDecode\"]()\n", 109 | "VAEEncode = NODE_CLASS_MAPPINGS[\"VAEEncode\"]()\n", 110 | "LoadImage = NODE_CLASS_MAPPINGS[\"LoadImage\"]()\n", 111 | "EmptyLatentImage = NODE_CLASS_MAPPINGS[\"EmptyLatentImage\"]()\n", 112 | "ImageScaleToTotalPixels = nodes_post_processing.NODE_CLASS_MAPPINGS[\"ImageScaleToTotalPixels\"]()\n", 113 | "ControlNetApplyAdvanced = NODE_CLASS_MAPPINGS[\"ControlNetApplyAdvanced\"]()" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": null, 119 | "metadata": { 120 | "id": "mLGPKWvopwnC", 121 | "cellView": "form" 122 | }, 123 | "outputs": [], 124 | "source": [ 125 | "# @markdown

Functions

\n", 126 | "\n", 127 | "loras = {\n", 128 | " \"xlabs_flux_anime\":\n", 129 | " {\n", 130 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/anime_lora_comfy_converted.safetensors\",\n", 131 | " \"filename\": \"xlabs_anime_lora.safetensors\",\n", 132 | " \"triggers\": \"anime\"\n", 133 | " },\n", 134 | " \"xlabs_flux_art\":\n", 135 | " {\n", 136 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/art_lora_comfy_converted.safetensors\",\n", 137 | " \"filename\": \"xlabs_art_lora.safetensors\",\n", 138 | " \"triggers\": \"art\"\n", 139 | " },\n", 140 | " \"xlabs_flux_disney\":\n", 141 | " {\n", 142 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/disney_lora_comfy_converted.safetensors\",\n", 143 | " \"filename\": \"xlabs_disney_lora.safetensors\",\n", 144 | " \"triggers\": \"disney style\"\n", 145 | " },\n", 146 | " \"xlabs_flux_mjv6\":\n", 147 | " {\n", 148 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/mjv6_lora_comfy_converted.safetensors\",\n", 149 | " \"filename\": \"xlabs_mjv6_lora.safetensors\"\n", 150 | " },\n", 151 | " \"xlabs_flux_realism\":\n", 152 | " {\n", 153 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/realism_lora_comfy_converted.safetensors\",\n", 154 | " \"filename\": \"xlabs_realism_lora.safetensors\"\n", 155 | " },\n", 156 | " \"xlabs_flux_scenery\":\n", 157 | " {\n", 158 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/scenery_lora_comfy_converted.safetensors\",\n", 159 | " \"filename\": \"xlabs_scenery_lora.safetensors\",\n", 160 | " \"triggers\": \"scenery style\"\n", 161 | " },\n", 162 | " \"xlabs_flux_furry\":\n", 163 | " {\n", 164 | " \"url\": \"https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/furry_lora.safetensors\",\n", 165 | " \"filename\": \"xlabs_flux_furry_lora.safetensors\"\n", 166 | " }\n", 167 | "}\n", 168 | "\n", 169 | "\n", 170 | "def load_loras(prompt):\n", 171 | " # @markdown \n", 172 | "\n", 173 | " global unet, clip, unet_f, clip_f\n", 174 | "\n", 175 | " unet_f, clip_f = unet, clip\n", 176 | "\n", 177 | " matches = re.findall(r\"<\\s*([^:]+?)\\s*:\\s*([0-9.]+)\\s*>\", prompt)\n", 178 | "\n", 179 | " loras_list = [(name.strip(), float(value)) for name, value in matches]\n", 180 | "\n", 181 | " if len(loras_list):\n", 182 | " print(\"Loading Loras...\")\n", 183 | "\n", 184 | " for lora_tuple in loras_list:\n", 185 | " lora = loras.get(lora_tuple[0], None)\n", 186 | "\n", 187 | " if lora:\n", 188 | " !aria2c --quiet --console-log-level=error --auto-file-renaming=false --allow-overwrite=false -c -x 16 -s 16 -k 1M {lora[\"url\"]} -d /content/TotoroUI/models/loras -o {lora[\"filename\"]}\n", 189 | "\n", 190 | " with torch.inference_mode():\n", 191 | " unet_f, clip_f = LoraLoader.load_lora(unet_f, clip_f, lora[\"filename\"], lora_tuple[1], lora_tuple[1])\n", 192 | "\n", 193 | " print(f\"Loaded Lora: {lora_tuple[0]}\")\n", 194 | " else:\n", 195 | " print(f\"Lora not listed: {lora_tuple[0]}\")\n", 196 | "\n", 197 | "def clean_prompt(prompt):\n", 198 | " cleaned_prompt = re.sub(r\"<.*?>\", \"\", prompt)\n", 199 | "\n", 200 | " return cleaned_prompt\n", 201 | "\n", 202 | "def cuda_gc():\n", 203 | " try:\n", 204 | " model_management.soft_empty_cache()\n", 205 | " gc.collect()\n", 206 | " torch.cuda.empty_cache()\n", 207 | " torch.cuda.ipc_collect()\n", 208 | " except:\n", 209 | " pass\n", 210 | "\n", 211 | "def img_tensor_to_np(img_tensor):\n", 212 | " img_tensor = img_tensor.clone() * 255.0\n", 213 | " return img_tensor.squeeze().numpy().astype(np.uint8)\n", 214 | "\n", 215 | "def img_np_to_tensor(img_np_list):\n", 216 | " return torch.from_numpy(img_np_list.astype(np.float32) / 255.0).unsqueeze(0)\n", 217 | "\n", 218 | "def controlnet_preprocess(preprocessor_type, width, height):\n", 219 | " # @markdown \n", 220 | "\n", 221 | " process_image = True # @param {\"type\":\"boolean\"}\n", 222 | " input_image = \"/content/test.png\" # @param {\"type\":\"string\"}\n", 223 | " resolution = 512 # @param {\"type\":\"slider\",\"min\":512,\"max\":2048,\"step\":1}\n", 224 | " resize_mode = \"Just Resize\" # @param [\"Just Resize\",\"Resize and Fill\",\"Crop and Resize\"]\n", 225 | "\n", 226 | " image_input = LoadImage.load_image(input_image)[0]\n", 227 | "\n", 228 | " if process_image:\n", 229 | " image_np = img_tensor_to_np(image_input)\n", 230 | " img = Image.fromarray(image_np)\n", 231 | "\n", 232 | " if resize_mode == \"Just Resize\":\n", 233 | " img = img.resize((width, height), Image.Resampling.LANCZOS)\n", 234 | "\n", 235 | " elif resize_mode == \"Resize and Fill\":\n", 236 | " img.thumbnail((width, height), Image.ANTIALIAS)\n", 237 | " result = Image.new(\"RGB\", (width, height), (0, 0, 0))\n", 238 | " offset = ((width - img.width) // 2, (height - img.height) // 2)\n", 239 | " result.paste(img, offset)\n", 240 | " img = result\n", 241 | "\n", 242 | " elif resize_mode == \"Crop and Resize\":\n", 243 | " src_width, src_height = img.size\n", 244 | " src_aspect = src_width / src_height\n", 245 | " target_aspect = width / height\n", 246 | "\n", 247 | " if src_aspect > target_aspect:\n", 248 | " new_width = int(src_height * target_aspect)\n", 249 | " left = (src_width - new_width) // 2\n", 250 | " img = img.crop((left, 0, left + new_width, src_height))\n", 251 | " else:\n", 252 | " new_height = int(src_width / target_aspect)\n", 253 | " top = (src_height - new_height) // 2\n", 254 | " img = img.crop((0, top, src_width, top + new_height))\n", 255 | "\n", 256 | " img = img.resize((width, height), Image.Resampling.LANCZOS)\n", 257 | "\n", 258 | " image_np = np.array(img).astype(np.uint8)\n", 259 | "\n", 260 | " if preprocessor_type == \"canny\":\n", 261 | " canny = CannyDetector()\n", 262 | " processed_image = canny(image_np, detect_resolution=resolution, image_resolution=resolution)\n", 263 | "\n", 264 | " elif preprocessor_type == \"depth\":\n", 265 | " depth = DepthAnythingDetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"depth_anything_v2_vitl_fp16.safetensors\")\n", 266 | " processed_image = depth(image_np, detect_resolution=resolution, image_resolution=resolution)\n", 267 | "\n", 268 | " elif preprocessor_type == \"hed\":\n", 269 | " hed = HEDdetector.from_pretrained(\"/content/TotoroUI/models/controlnet_preprocessors\", filename=\"ControlNetHED.pth\")\n", 270 | " processed_image = hed(image_np, detect_resolution=resolution, image_resolution=resolution)\n", 271 | "\n", 272 | " processed_image_np = np.array(processed_image)\n", 273 | " processed_image_tensor = img_np_to_tensor(processed_image_np)\n", 274 | "\n", 275 | " display(Image.fromarray(processed_image_np))\n", 276 | "\n", 277 | " return processed_image_tensor\n", 278 | "\n", 279 | " else:\n", 280 | " return image_input\n", 281 | "\n", 282 | "\n", 283 | "def apply_controlnet(cond, width, height):\n", 284 | " # @markdown \n", 285 | "\n", 286 | " controlnet_type = \"canny\" # @param [\"canny\", \"depth\", \"hed\"]\n", 287 | " strength = 0.5 # @param {\"type\":\"slider\",\"min\":0.0,\"max\":10.0,\"step\":0.01}\n", 288 | " start_percent = 0 # @param {\"type\":\"slider\",\"min\":0.0,\"max\":1.0,\"step\":0.001}\n", 289 | " end_percent = 0.225 # @param {\"type\":\"slider\",\"min\":0.0,\"max\":1.0,\"step\":0.001}\n", 290 | "\n", 291 | " cond_neg = CLIPTextEncodeFlux.encode(clip_f, \"\", \"\", 0)[0]\n", 292 | "\n", 293 | " print(\"Loading Controlnet...\")\n", 294 | "\n", 295 | " preprocessed_image = controlnet_preprocess(controlnet_type, width, height)\n", 296 | "\n", 297 | " if controlnet_type == \"canny\":\n", 298 | " controlnet = ControlNetLoader.load_controlnet(\"flux-canny-controlnet-v3.safetensors\")[0]\n", 299 | " elif controlnet_type == \"depth\":\n", 300 | " controlnet = ControlNetLoader.load_controlnet(\"flux-depth-controlnet-v3.safetensors\")[0]\n", 301 | " elif controlnet_type == \"hed\":\n", 302 | " controlnet = ControlNetLoader.load_controlnet(\"flux-hed-controlnet-v3.safetensors\")[0]\n", 303 | "\n", 304 | " cond = ControlNetApplyAdvanced.apply_controlnet(cond, cond_neg, controlnet, preprocessed_image, strength, start_percent, end_percent)[0]\n", 305 | "\n", 306 | " del controlnet\n", 307 | "\n", 308 | " return cond\n", 309 | "\n", 310 | "def closestNumber(n, m):\n", 311 | " q = int(n / m)\n", 312 | " n1 = m * q\n", 313 | " if (n * m) > 0:\n", 314 | " n2 = m * (q + 1)\n", 315 | " else:\n", 316 | " n2 = m * (q - 1)\n", 317 | " if abs(n - n1) < abs(n - n2):\n", 318 | " return n1\n", 319 | " return n2\n", 320 | "\n", 321 | "def save_image(decoded, path, name, download=False):\n", 322 | " full_path = os.path.abspath(os.path.join(path, name))\n", 323 | " Image.fromarray(np.array(decoded*255, dtype=np.uint8)[0]).save(full_path)\n", 324 | "\n", 325 | " img = Image.open(full_path)\n", 326 | " display(img)\n", 327 | "\n", 328 | " if download:\n", 329 | " files.download(full_path)\n", 330 | "\n", 331 | "@torch.inference_mode()\n", 332 | "def generate(prompt, width, height, fixed_seed, guidance, steps, sampler_name, scheduler, batch_size, auto_download, mode=\"t2i\", input_img=None, denoise=1.0):\n", 333 | " global unet, clip, unet_f, clip_f\n", 334 | "\n", 335 | " print(\"Prompt Received\")\n", 336 | "\n", 337 | " load_loras(prompt)\n", 338 | " prompt = clean_prompt(prompt)\n", 339 | "\n", 340 | " if mode == \"t2i\":\n", 341 | " latent_image = EmptyLatentImage.generate(closestNumber(width, 16), closestNumber(height, 16))[0]\n", 342 | "\n", 343 | " elif mode == \"i2i\":\n", 344 | " image = LoadImage.load_image(input_img)[0]\n", 345 | " latent_image = ImageScaleToTotalPixels.upscale(image, \"lanczos\", 1.0)[0]\n", 346 | " latent_image = VAEEncode.encode(vae, latent_image)[0]\n", 347 | "\n", 348 | " image_np = img_tensor_to_np(image)\n", 349 | " img = Image.fromarray(image_np)\n", 350 | " width, height = img.width, img.height\n", 351 | "\n", 352 | " cond = CLIPTextEncodeFlux.encode(clip_f, prompt, prompt, guidance)[0]\n", 353 | "\n", 354 | " cond = apply_controlnet(cond, width, height)\n", 355 | "\n", 356 | " guider = BasicGuider.get_guider(unet_f, cond)[0]\n", 357 | " sampler = KSamplerSelect.get_sampler(sampler_name)[0]\n", 358 | " sigmas = BasicScheduler.get_sigmas(unet_f, scheduler, steps, denoise)[0]\n", 359 | "\n", 360 | " for i in range(0, batch_size):\n", 361 | " if fixed_seed == 0:\n", 362 | " seed = random.randint(0, 18446744073709551615)\n", 363 | " else:\n", 364 | " seed = fixed_seed\n", 365 | "\n", 366 | " print(\"Seed:\", seed)\n", 367 | "\n", 368 | " noise = RandomNoise.get_noise(seed)[0]\n", 369 | " sample, sample_denoised = SamplerCustomAdvanced.sample(noise, guider, sampler, sigmas, latent_image)\n", 370 | " model_management.soft_empty_cache()\n", 371 | " decoded = VAEDecode.decode(vae, sample)[0].detach()\n", 372 | "\n", 373 | " save_image(decoded, \"/content\", f\"flux_{mode}_{seed}_{i}.png\", auto_download)\n", 374 | "\n", 375 | " cuda_gc()\n", 376 | "\n", 377 | "print(f\"{'Lora Name':<40} {'Trigger Words':<40}\")\n", 378 | "print(\"-\" * 80)\n", 379 | "\n", 380 | "for key_name, details in loras.items():\n", 381 | " trigger_words = details.get(\"triggers\", \"N/A\")\n", 382 | " print(f\"{key_name:<40} {trigger_words:<40}\")" 383 | ] 384 | }, 385 | { 386 | "cell_type": "code", 387 | "execution_count": null, 388 | "metadata": { 389 | "cellView": "form", 390 | "id": "Ur9TmMNwC2kR" 391 | }, 392 | "outputs": [], 393 | "source": [ 394 | "#@markdown

Txt2Img

\n", 395 | "\n", 396 | "positive_prompt = \"\" # @param {\"type\":\"string\"}\n", 397 | "width = 1024 # @param {\"type\":\"slider\",\"min\":256,\"max\":2048,\"step\":1}\n", 398 | "height = 1024 # @param {\"type\":\"slider\",\"min\":256,\"max\":2048,\"step\":1}\n", 399 | "fixed_seed = 0 # @param {\"type\":\"slider\",\"min\":0,\"max\":18446744073709552000,\"step\":1}\n", 400 | "guidance = 4.5 # @param {\"type\":\"slider\",\"min\":0,\"max\":20,\"step\":0.5}\n", 401 | "steps = 25 # @param {\"type\":\"slider\",\"min\":4,\"max\":50,\"step\":1}\n", 402 | "sampler_name = \"euler\" # @param [\"euler\",\"heun\",\"heunpp2\",\"heunpp2\",\"dpm_2\",\"lms\",\"dpmpp_2m\",\"ipndm\",\"deis\",\"ddim\",\"uni_pc\",\"uni_pc_bh2\"]\n", 403 | "scheduler = \"simple\" # @param [\"normal\",\"sgm_uniform\",\"simple\",\"ddim_uniform\"]\n", 404 | "batch_size = 1 # @param {\"type\":\"slider\",\"min\":1,\"max\":20,\"step\":1}\n", 405 | "auto_download = False # @param {\"type\":\"boolean\"}\n", 406 | "\n", 407 | "generate(positive_prompt, width, height, fixed_seed, guidance, steps, sampler_name, scheduler, batch_size, auto_download)" 408 | ] 409 | }, 410 | { 411 | "cell_type": "code", 412 | "execution_count": null, 413 | "metadata": { 414 | "cellView": "form", 415 | "id": "Dpd2sfrePYoA" 416 | }, 417 | "outputs": [], 418 | "source": [ 419 | "#@markdown

Img2Img

\n", 420 | "\n", 421 | "positive_prompt = \"anime style\" # @param {\"type\":\"string\"}\n", 422 | "fixed_seed = 0 # @param {\"type\":\"slider\",\"min\":0,\"max\":18446744073709552000,\"step\":1}\n", 423 | "guidance = 4.5 # @param {\"type\":\"slider\",\"min\":0,\"max\":20,\"step\":0.5}\n", 424 | "steps = 25 # @param {\"type\":\"slider\",\"min\":4,\"max\":50,\"step\":1}\n", 425 | "sampler_name = \"euler\" # @param [\"euler\",\"heun\",\"heunpp2\",\"heunpp2\",\"dpm_2\",\"lms\",\"dpmpp_2m\",\"ipndm\",\"deis\",\"ddim\",\"uni_pc\",\"uni_pc_bh2\"]\n", 426 | "scheduler = \"simple\" # @param [\"normal\",\"sgm_uniform\",\"simple\",\"ddim_uniform\"]\n", 427 | "input_img = \"/content/test.png\" # @param {\"type\":\"string\"}\n", 428 | "denoise = 0.85 # @param {\"type\":\"slider\",\"min\":0,\"max\":1,\"step\":0.01}\n", 429 | "batch_size = 1 # @param {\"type\":\"slider\",\"min\":1,\"max\":20,\"step\":1}\n", 430 | "auto_download = False # @param {\"type\":\"boolean\"}\n", 431 | "\n", 432 | "\n", 433 | "generate(positive_prompt, 0, 0, fixed_seed, guidance, steps, sampler_name, scheduler, batch_size, auto_download, \"i2i\", input_img, denoise)" 434 | ] 435 | } 436 | ], 437 | "metadata": { 438 | "accelerator": "GPU", 439 | "colab": { 440 | "gpuType": "T4", 441 | "provenance": [] 442 | }, 443 | "kernelspec": { 444 | "display_name": "Python 3", 445 | "name": "python3" 446 | }, 447 | "language_info": { 448 | "name": "python" 449 | } 450 | }, 451 | "nbformat": 4, 452 | "nbformat_minor": 0 453 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flux.1-dev-ControlNet-jupyter 2 | 3 | - Flux ControlNets with Txt2Img | Img2Img | + Multiple LoRAs, All in one notebook 4 | - Works in Google Colab Free Teir T4 GPU 🥳🥳 5 | - Uses [Flux.1-dev GGUF](https://huggingface.co/city96/FLUX.1-dev-gguf) models 6 | 7 | ## Notebooks 8 | 9 | | Notebook | Info | 10 | | ------------- |:-------------:| 11 | | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/LucipherDev/Flux.1-dev-ControlNet-jupyter/blob/main/Flux.1-dev-XLabs_CN-jupyter.ipynb) | Flux.1-dev-XLabs_CN-jupyter ([flux1-dev-Q4_K_S.gguf](https://huggingface.co/city96/FLUX.1-dev-gguf/blob/main/flux1-dev-Q4_K_S.gguf)) | 12 | | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/LucipherDev/Flux.1-dev-ControlNet-jupyter/blob/main/Flux.1-dev-Union_CN-jupyter.ipynb) | Flux.1-dev-Union_CN-jupyter (flux1-dev-[Q2_K.gguf](https://huggingface.co/city96/FLUX.1-dev-gguf/blob/main/flux1-dev-Q2_K.gguf)/[Q8_0.gguf](https://huggingface.co/city96/FLUX.1-dev-gguf/blob/main/flux1-dev-Q8_0.gguf)) | 13 | 14 | ###### * *This is still unstable in google colab free tier and prone to crashing because of low system RAM. Use at your own risk.* 15 | 16 | ## Features 17 | 18 | *Basic Functions [Txt2Img | Img2Img | + Multiple LoRAs] are as shown in [LucipherDev/Flux.1-fp8-jupyter](https://github.com/LucipherDev/Flux.1-fp8-jupyter)* 19 | 20 | ## X-Labs ControlNet 21 | 22 | ### Preprocessors 23 | - Canny 24 | - Depth (DepthAnythingV2) 25 | - HED 26 | 27 | ![ss1](https://github.com/user-attachments/assets/4cec4bb8-f89a-4e7f-b3f6-935c6b2f21b8) 28 | 29 | ![preprocessor_examples_1](https://github.com/user-attachments/assets/8ef1063c-0267-4002-8b3d-d14cebefca03) 30 | 31 | ![ss2](https://github.com/user-attachments/assets/3f71dd12-94a7-40e7-9ea9-ac632cfb1cf5) 32 | 33 | ![xlabs-cn-examples](https://github.com/user-attachments/assets/b7e1108e-9367-4ee3-b568-015a244d8a36) 34 | 35 | ## Union-Pro ControlNet 36 | 37 | *Low RAM uses flux1-dev-Q2_K.gguf and gives low quality results, so using high RAM is advised as it uses flux1-dev-Q8_0.gguf* 38 | 39 | ### Preprocessors 40 | - Openpose 41 | - Depth (DepthAnythingV2) 42 | - HED 43 | - Pidi 44 | - Scribble 45 | - Ted 46 | - Canny 47 | - Lineart 48 | - Anime_lineart 49 | - MLSD 50 | - Normal 51 | - Segment 52 | 53 | ![ss3](https://github.com/user-attachments/assets/14bb781b-4966-435b-afa4-87d6aa71c60f) 54 | 55 | ![preprocessor_examples_1](https://github.com/user-attachments/assets/8eb55a5c-deb9-4193-be68-bd81f069e64a) 56 | 57 | ![ss4](https://github.com/user-attachments/assets/968f8c2a-bc0c-4890-b1a2-5b910cac1d32) 58 | --------------------------------------------------------------------------------