diff --git a/__init__.py b/__init__.py index 6c42fbd..316c82e 100644 --- a/__init__.py +++ b/__init__.py @@ -6,13 +6,8 @@ import os from pathlib import Path import logging import folder_paths -import shutil from collections import defaultdict import hashlib -import tempfile -import subprocess -import gc -from safetensors.torch import save_file, load_file import comfy.utils from typing import Dict, List @@ -36,21 +31,29 @@ current_device = mm.get_torch_device() current_text_encoder_device = mm.text_encoder_device() model_allocation_store = {} +def _has_xpu(): + try: + return hasattr(torch, "xpu") and hasattr(torch.xpu, "is_available") and torch.xpu.is_available() + except Exception: + return False + def get_torch_device_patched(): device = None - if (not torch.cuda.is_available() or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_device).lower()): + if (not (torch.cuda.is_available() or _has_xpu()) or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_device).lower()): device = torch.device("cpu") else: - device = torch.device(current_device) + devs = set(get_device_list()) + device = torch.device(current_device) if str(current_device) in devs else torch.device("cpu") logging.info(f"[MultiGPU get_torch_device_patched] Returning device: {device} (current_device={current_device})") return device def text_encoder_device_patched(): device = None - if (not torch.cuda.is_available() or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_text_encoder_device).lower()): + if (not (torch.cuda.is_available() or _has_xpu()) or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_text_encoder_device).lower()): device = torch.device("cpu") else: - device = torch.device(current_text_encoder_device) + devs = set(get_device_list()) + device = torch.device(current_text_encoder_device) if str(current_text_encoder_device) in devs else torch.device("cpu") logging.info(f"[MultiGPU text_encoder_device_patched] Returning device: {device} (current_text_encoder_device={current_text_encoder_device})") return device @@ -331,8 +334,18 @@ def calculate_vvram_allocation_string(model, virtual_vram_str): return allocation_string def get_device_list(): - import torch - return ["cpu"] + [f"cuda:{i}" for i in range(torch.cuda.device_count())] + devs = ["cpu"] + try: + if hasattr(torch, "cuda") and hasattr(torch.cuda, "is_available") and torch.cuda.is_available(): + devs += [f"cuda:{i}" for i in range(torch.cuda.device_count())] + except Exception: + pass + try: + if _has_xpu(): + devs += [f"xpu:{i}" for i in range(torch.xpu.device_count())] + except Exception: + pass + return devs class DeviceSelectorMultiGPU: @classmethod @@ -385,138 +398,6 @@ class HunyuanVideoEmbeddingsAdapter: return ([[cond, pooled_dict]],) -class MergeFluxLoRAsQuantizeAndLoad: - @classmethod - def INPUT_TYPES(cls): - unet_name = folder_paths.get_filename_list("diffusion_models") - loras = ["None"] + folder_paths.get_filename_list("loras") - inputs = { - "required": { - "unet_name": (unet_name,), - "switch_1": (["Off", "On"],), - "lora_name_1": (loras,), - "lora_weight_1": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}), - "switch_2": (["Off", "On"],), - "lora_name_2": (loras,), - "lora_weight_2": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}), - "switch_3": (["Off", "On"],), - "lora_name_3": (loras,), - "lora_weight_3": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}), - "switch_4": (["Off", "On"],), - "lora_name_4": (loras,), - "lora_weight_4": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}), - "quantization": (["Q2_K", "Q3_K_S", "Q4_0", "Q4_1", "Q4_K_S", "Q5_0", "Q5_1", "Q5_K_S", "Q6_K", "Q8_0", "FP16"], {"default": "Q4_K_S"}), - "delete_final_gguf": ("BOOLEAN", {"default": False}), - "new_model_name": ("STRING", {"default": "merged_model"}), - } - } - return inputs - - RETURN_TYPES = ("MODEL",) - FUNCTION = "load_and_quantize" - CATEGORY = "loaders" - - def merge_flux_loras(self, model_sd: dict, lora_paths: list, weights: list, device="cuda") -> dict: - for lora_path, weight in zip(lora_paths, weights): - logging.info(f"[DEBUG] Merging LoRA file: {lora_path} with weight: {weight}") - lora_sd = load_file(lora_path, device=device) - for key in list(lora_sd.keys()): - if "lora_down" not in key: - continue - base_name = key[: key.rfind(".lora_down")] - up_key = key.replace("lora_down", "lora_up") - module_name = base_name.replace("_", ".") - alpha_key = f"{base_name}.alpha" - if module_name not in model_sd: - logging.info(f"[DEBUG] Module {module_name} not found in model_sd; skipping key {key}") - continue - down_weight = lora_sd[key].float() - up_weight = lora_sd[up_key].float() - alpha = float(lora_sd.get(alpha_key, up_weight.shape[0])) - scale = weight * alpha / up_weight.shape[0] - logging.info(f"[DEBUG] Merging module: {module_name} with alpha: {alpha}, scale: {scale}") - target_weight = model_sd[module_name] - if len(target_weight.shape) == 2: - update = (up_weight @ down_weight) * scale - else: - if down_weight.shape[2:4] == (1, 1): - update = (up_weight.squeeze(3).squeeze(2) @ down_weight.squeeze(3).squeeze(2)) - update = update.unsqueeze(2).unsqueeze(3) * scale - else: - update = torch.nn.functional.conv2d( - down_weight.permute(1, 0, 2, 3), up_weight - ).permute(1, 0, 2, 3) * scale - model_sd[module_name] = target_weight + update.to(target_weight.dtype) - logging.info(f"[DEBUG] Updated module: {module_name}") - del up_weight, down_weight, update - del lora_sd - torch.cuda.empty_cache() - return model_sd - - def convert_to_gguf(self, model_path, working_dir): - base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - convert_script = os.path.join(base_path, "ComfyUI-GGUF", "tools", "convert.py") - temp_gguf = os.path.join(working_dir, "temp_converted.gguf") - logging.info("[DEBUG] Running conversion script: " + convert_script) - subprocess.run([sys.executable, convert_script, "--src", model_path, "--dst", temp_gguf], check=True) - logging.info("[DEBUG] Conversion complete.") - return temp_gguf - - def load_and_quantize(self, unet_name, quantization, delete_final_gguf, new_model_name, **kwargs): - mapping = {"FP16": "F16"} - logging.info(f"[DEBUG] Starting load_and_quantize: {new_model_name} | Quantization: {quantization}") - with tempfile.TemporaryDirectory() as merge_dir: - merged_model_path = os.path.join(merge_dir, "merged_model.safetensors") - model_path = folder_paths.get_full_path("diffusion_models", unet_name) - lora_list = [] - for i in range(1, 5): - name = kwargs.get(f"lora_name_{i}", "None") - switch = kwargs.get(f"switch_{i}", "Off") - logging.info(f"[DEBUG] Processing LoRA slot {i}: name = {name}, switch = {switch}") - if switch == "On" and name and name != "None": - lora_file_path = folder_paths.get_full_path("loras", name) - weight = kwargs.get(f"lora_weight_{i}", 1.0) - lora_list.append((lora_file_path, weight)) - logging.info(f"[DEBUG] Slot {i} active: path = {lora_file_path}, weight = {weight}") - else: - logging.info(f"[DEBUG] Slot {i} is inactive") - logging.info(f"[DEBUG] Total active LoRAs: {len(lora_list)}") - if lora_list: - model_sd = load_file(model_path, device="cuda") - model_sd = self.merge_flux_loras( - model_sd, - [lp for lp, _ in lora_list], - [w for _, w in lora_list] - ) - save_file(model_sd, merged_model_path) - del model_sd - torch.cuda.empty_cache() - else: - shutil.copy2(model_path, merged_model_path) - initial_gguf = self.convert_to_gguf(merged_model_path, merge_dir) - logging.info("[DEBUG] Initial GGUF file created.") - if quantization == "FP16": - final_gguf = os.path.join(merge_dir, f"{new_model_name}-{mapping.get(quantization, quantization)}.gguf") - shutil.copy2(initial_gguf, final_gguf) - logging.info("[DEBUG] FP16 selected; conversion skipped.") - else: - binary = os.path.join(os.path.dirname(os.path.abspath(__file__)), "binaries", "linux", "llama-quantize") - final_gguf = os.path.join(merge_dir, f"quantized_{quantization}.gguf") - subprocess.run([binary, initial_gguf, final_gguf, quantization], check=True) - logging.info("[DEBUG] Quantization completed.") - models_dir = os.path.join(folder_paths.models_dir, "unet") - os.makedirs(models_dir, exist_ok=True) - final_name = f"{new_model_name}-{mapping.get(quantization, quantization)}.gguf" - final_path = os.path.join(models_dir, final_name) - shutil.copy2(final_gguf, final_path) - logging.info("[DEBUG] Final model file copied to: " + final_path) - logging.info("[DEBUG] Loading final model.") - loader = UnetLoaderGGUF() - result = loader.load_unet(final_name) - logging.info("[DEBUG] Final model loaded.") - if delete_final_gguf: - os.unlink(final_path) - return result def override_class(cls): @@ -611,7 +492,7 @@ def override_class_with_distorch(cls): vram_string = "" if virtual_vram_gb > 0: if use_other_vram: - available_devices = [d for d in get_device_list() if d.startswith('cuda')] + available_devices = [d for d in get_device_list() if d.startswith(("cuda", "xpu"))] other_devices = [d for d in available_devices if d != device] other_devices.sort(key=lambda x: int(x.split(':')[1] if ':' in x else x[-1]), reverse=False) device_string = ','.join(other_devices + ['cpu']) @@ -667,7 +548,7 @@ def override_class_with_distorch_clip(cls): vram_string = "" if virtual_vram_gb > 0: if use_other_vram: - available_devices = [d for d in get_device_list() if d.startswith('cuda')] + available_devices = [d for d in get_device_list() if d.startswith(("cuda", "xpu"))] other_devices = [d for d in available_devices if d != device] other_devices.sort(key=lambda x: int(x.split(':')[1] if ':' in x else x[-1]), reverse=False) device_string = ','.join(other_devices + ['cpu']) @@ -704,7 +585,6 @@ NODE_CLASS_MAPPINGS = { "HunyuanVideoEmbeddingsAdapter": HunyuanVideoEmbeddingsAdapter, } -NODE_CLASS_MAPPINGS["MergeFluxLoRAsQuantizeAndLoaddMultiGPU"] = override_class(MergeFluxLoRAsQuantizeAndLoad) NODE_CLASS_MAPPINGS["UNETLoaderMultiGPU"] = override_class(GLOBAL_NODE_CLASS_MAPPINGS["UNETLoader"]) NODE_CLASS_MAPPINGS["VAELoaderMultiGPU"] = override_class(GLOBAL_NODE_CLASS_MAPPINGS["VAELoader"]) diff --git a/claude_json.json b/claude_json.json deleted file mode 100755 index 87b50f4..0000000 --- a/claude_json.json +++ /dev/null @@ -1,1387 +0,0 @@ -{ - "id": "c6e410bc-5e2c-460b-ae81-c91b6094fbb1", - "revision": 0, - "last_node_id": 62, - "last_link_id": 67, - "nodes": [ - { - "id": 11, - "type": "LoadWanVideoT5TextEncoder", - "pos": [ - -390, - -70 - ], - "size": [ - 377.1661376953125, - 130 - ], - "flags": {}, - "order": 0, - "mode": 0, - "inputs": [], - "outputs": [ - { - "name": "wan_t5_model", - "type": "WANTEXTENCODER", - "slot_index": 0, - "links": [ - 15 - ] - } - ], - "properties": { - "Node name for S&R": "LoadWanVideoT5TextEncoder", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [ - "umt5-xxl-enc-bf16.safetensors", - "bf16", - "offload_device", - "disabled" - ], - "color": "#332922", - "bgcolor": "#593930" - }, - { - "id": 37, - "type": "WanVideoEmptyEmbeds", - "pos": [ - 1305.26708984375, - -571.7843627929688 - ], - "size": [ - 315, - 126 - ], - "flags": {}, - "order": 1, - "mode": 0, - "inputs": [ - { - "name": "control_embeds", - "shape": 7, - "type": "WANVIDIMAGE_EMBEDS", - "link": null - }, - { - "name": "extra_latents", - "shape": 7, - "type": "LATENT", - "link": null - } - ], - "outputs": [ - { - "name": "image_embeds", - "type": "WANVIDIMAGE_EMBEDS", - "links": [ - 42 - ] - } - ], - "properties": { - "Node name for S&R": "WanVideoEmptyEmbeds", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [ - 832, - 480, - 81 - ] - }, - { - "id": 50, - "type": "CLIPTextEncode", - "pos": [ - 450.84735107421875, - 852.1167602539062 - ], - "size": [ - 400, - 200 - ], - "flags": {}, - "order": 19, - "mode": 2, - "inputs": [ - { - "name": "clip", - "type": "CLIP", - "link": 53 - } - ], - "outputs": [ - { - "name": "CONDITIONING", - "type": "CONDITIONING", - "slot_index": 0, - "links": [ - 55 - ] - } - ], - "properties": { - "Node name for S&R": "CLIPTextEncode", - "cnr_id": "comfy-core", - "ver": "0.3.47" - }, - "widgets_values": [ - "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" - ], - "color": "#432", - "bgcolor": "#653" - }, - { - "id": 48, - "type": "CLIPLoader", - "pos": [ - 90.8473129272461, - 602.1166381835938 - ], - "size": [ - 315, - 106 - ], - "flags": {}, - "order": 2, - "mode": 2, - "inputs": [], - "outputs": [ - { - "name": "CLIP", - "type": "CLIP", - "slot_index": 0, - "links": [ - 52, - 53 - ] - } - ], - "properties": { - "Node name for S&R": "CLIPLoader", - "cnr_id": "comfy-core", - "ver": "0.3.47" - }, - "widgets_values": [ - "umt5_xxl_fp16.safetensors", - "wan", - "default" - ], - "color": "#432", - "bgcolor": "#653" - }, - { - "id": 51, - "type": "Note", - "pos": [ - 120.8473129272461, - 432.1158752441406 - ], - "size": [ - 253.16725158691406, - 88 - ], - "flags": {}, - "order": 3, - "mode": 0, - "inputs": [], - "outputs": [], - "properties": {}, - "widgets_values": [ - "You can also use native ComfyUI text encoding with these nodes instead of the original, the models are node specific and can't otherwise be mixed." - ], - "color": "#432", - "bgcolor": "#653" - }, - { - "id": 49, - "type": "CLIPTextEncode", - "pos": [ - 450.84735107421875, - 602.1166381835938 - ], - "size": [ - 400, - 200 - ], - "flags": {}, - "order": 18, - "mode": 2, - "inputs": [ - { - "name": "clip", - "type": "CLIP", - "link": 52 - } - ], - "outputs": [ - { - "name": "CONDITIONING", - "type": "CONDITIONING", - "slot_index": 0, - "links": [ - 54 - ] - } - ], - "properties": { - "Node name for S&R": "CLIPTextEncode", - "cnr_id": "comfy-core", - "ver": "0.3.47" - }, - "widgets_values": [ - "high quality nature video featuring a red panda balancing on a bamboo stem while a bird lands on it's head, on the background there is a waterfall" - ], - "color": "#432", - "bgcolor": "#653" - }, - { - "id": 33, - "type": "Note", - "pos": [ - -760, - -50 - ], - "size": [ - 359.0753479003906, - 88 - ], - "flags": {}, - "order": 4, - "mode": 0, - "inputs": [], - "outputs": [], - "properties": {}, - "widgets_values": [ - "Models:\nhttps://huggingface.co/Kijai/WanVideo_comfy/tree/main" - ], - "color": "#432", - "bgcolor": "#653" - }, - { - "id": 35, - "type": "WanVideoTorchCompileSettings", - "pos": [ - -390, - -710 - ], - "size": [ - 390.5999755859375, - 202 - ], - "flags": {}, - "order": 5, - "mode": 0, - "inputs": [], - "outputs": [ - { - "name": "torch_compile_args", - "type": "WANCOMPILEARGS", - "slot_index": 0, - "links": [] - } - ], - "properties": { - "Node name for S&R": "WanVideoTorchCompileSettings", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [ - "inductor", - false, - "default", - false, - 64, - true, - 128 - ] - }, - { - "id": 44, - "type": "Note", - "pos": [ - -710, - -710 - ], - "size": [ - 303.0501403808594, - 88 - ], - "flags": {}, - "order": 6, - "mode": 0, - "inputs": [], - "outputs": [], - "properties": {}, - "widgets_values": [ - "If you have Triton installed, connect this for ~30% speed increase" - ], - "color": "#432", - "bgcolor": "#653" - }, - { - "id": 30, - "type": "VHS_VideoCombine", - "pos": [ - 2068.651611328125, - -582.5413818359375 - ], - "size": [ - 1245.8460693359375, - 1055.2188720703125 - ], - "flags": {}, - "order": 25, - "mode": 0, - "inputs": [ - { - "name": "images", - "type": "IMAGE", - "link": 36 - }, - { - "name": "audio", - "shape": 7, - "type": "AUDIO", - "link": null - }, - { - "name": "meta_batch", - "shape": 7, - "type": "VHS_BatchManager", - "link": null - }, - { - "name": "vae", - "shape": 7, - "type": "VAE", - "link": null - } - ], - "outputs": [ - { - "name": "Filenames", - "type": "VHS_FILENAMES", - "links": null - } - ], - "properties": { - "Node name for S&R": "VHS_VideoCombine", - "cnr_id": "comfyui-videohelpersuite", - "ver": "330bce6c3c0d47ebdedcc0348d9ab355707b7523" - }, - "widgets_values": { - "frame_rate": 16, - "loop_count": 0, - "filename_prefix": "WanVideo2_1_T2V", - "format": "video/h264-mp4", - "pix_fmt": "yuv420p", - "crf": 19, - "save_metadata": true, - "trim_to_audio": false, - "pingpong": false, - "save_output": true, - "videopreview": { - "hidden": false, - "paused": false, - "params": { - "filename": "WanVideo2_1_T2V_00003.mp4", - "subfolder": "", - "type": "output", - "format": "video/h264-mp4", - "frame_rate": 16, - "workflow": "WanVideo2_1_T2V_00003.png", - "fullpath": "/home/johnj/ComfyUI/output/WanVideo2_1_T2V_00003.mp4" - } - } - } - }, - { - "id": 46, - "type": "WanVideoTextEmbedBridge", - "pos": [ - 900.8475341796875, - 592.1166381835938 - ], - "size": [ - 315, - 46 - ], - "flags": {}, - "order": 21, - "mode": 2, - "inputs": [ - { - "name": "positive", - "type": "CONDITIONING", - "link": 54 - }, - { - "name": "negative", - "shape": 7, - "type": "CONDITIONING", - "link": 55 - } - ], - "outputs": [ - { - "name": "text_embeds", - "type": "WANVIDEOTEXTEMBEDS", - "links": null - } - ], - "properties": { - "Node name for S&R": "WanVideoTextEmbedBridge", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [] - }, - { - "id": 28, - "type": "WanVideoDecode", - "pos": [ - 1692.973876953125, - -404.8614501953125 - ], - "size": [ - 315, - 198 - ], - "flags": {}, - "order": 24, - "mode": 0, - "inputs": [ - { - "name": "vae", - "type": "WANVAE", - "link": 43 - }, - { - "name": "samples", - "type": "LATENT", - "link": 33 - } - ], - "outputs": [ - { - "name": "images", - "type": "IMAGE", - "slot_index": 0, - "links": [ - 36 - ] - } - ], - "properties": { - "Node name for S&R": "WanVideoDecode", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [ - false, - 272, - 272, - 144, - 128, - "default" - ], - "color": "#322", - "bgcolor": "#533" - }, - { - "id": 56, - "type": "WanVideoSetBlockSwap", - "pos": [ - 882.7855834960938, - -362.668701171875 - ], - "size": [ - 201.76815795898438, - 46 - ], - "flags": {}, - "order": 22, - "mode": 4, - "inputs": [ - { - "name": "model", - "type": "WANVIDEOMODEL", - "link": 62 - }, - { - "name": "block_swap_args", - "shape": 7, - "type": "BLOCKSWAPARGS", - "link": 58 - } - ], - "outputs": [ - { - "name": "model", - "type": "WANVIDEOMODEL", - "links": [ - 60 - ] - } - ], - "properties": { - "Node name for S&R": "WanVideoSetBlockSwap", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [], - "color": "#223", - "bgcolor": "#335" - }, - { - "id": 58, - "type": "WanVideoSetLoRAs", - "pos": [ - 630.5015869140625, - -367.1865234375 - ], - "size": [ - 174.53378295898438, - 46 - ], - "flags": {}, - "order": 20, - "mode": 0, - "inputs": [ - { - "name": "model", - "type": "WANVIDEOMODEL", - "link": 67 - }, - { - "name": "lora", - "shape": 7, - "type": "WANVIDLORA", - "link": 64 - } - ], - "outputs": [ - { - "name": "model", - "type": "WANVIDEOMODEL", - "links": [ - 62 - ] - } - ], - "properties": { - "Node name for S&R": "WanVideoSetLoRAs", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [], - "color": "#223", - "bgcolor": "#335" - }, - { - "id": 27, - "type": "WanVideoSampler", - "pos": [ - 1315.2401123046875, - -401.48028564453125 - ], - "size": [ - 315, - 902 - ], - "flags": {}, - "order": 23, - "mode": 0, - "inputs": [ - { - "name": "model", - "type": "WANVIDEOMODEL", - "link": 60 - }, - { - "name": "image_embeds", - "type": "WANVIDIMAGE_EMBEDS", - "link": 42 - }, - { - "name": "text_embeds", - "shape": 7, - "type": "WANVIDEOTEXTEMBEDS", - "link": 30 - }, - { - "name": "samples", - "shape": 7, - "type": "LATENT", - "link": null - }, - { - "name": "feta_args", - "shape": 7, - "type": "FETAARGS", - "link": 57 - }, - { - "name": "context_options", - "shape": 7, - "type": "WANVIDCONTEXT", - "link": null - }, - { - "name": "cache_args", - "shape": 7, - "type": "CACHEARGS", - "link": null - }, - { - "name": "flowedit_args", - "shape": 7, - "type": "FLOWEDITARGS", - "link": null - }, - { - "name": "slg_args", - "shape": 7, - "type": "SLGARGS", - "link": null - }, - { - "name": "loop_args", - "shape": 7, - "type": "LOOPARGS", - "link": null - }, - { - "name": "experimental_args", - "shape": 7, - "type": "EXPERIMENTALARGS", - "link": null - }, - { - "name": "sigmas", - "shape": 7, - "type": "SIGMAS", - "link": null - }, - { - "name": "unianimate_poses", - "shape": 7, - "type": "UNIANIMATE_POSE", - "link": null - }, - { - "name": "fantasytalking_embeds", - "shape": 7, - "type": "FANTASYTALKING_EMBEDS", - "link": null - }, - { - "name": "uni3c_embeds", - "shape": 7, - "type": "UNI3C_EMBEDS", - "link": null - }, - { - "name": "multitalk_embeds", - "shape": 7, - "type": "MULTITALK_EMBEDS", - "link": null - }, - { - "name": "freeinit_args", - "shape": 7, - "type": "FREEINITARGS", - "link": null - } - ], - "outputs": [ - { - "name": "samples", - "type": "LATENT", - "slot_index": 0, - "links": [ - 33 - ] - }, - { - "name": "denoised_samples", - "type": "LATENT", - "links": null - } - ], - "properties": { - "Node name for S&R": "WanVideoSampler", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [ - 6, - 1, - 5, - 42, - "fixed", - true, - "dpm++_sde", - 0, - 1, - false, - "comfy", - 0, - -1, - false - ] - }, - { - "id": 55, - "type": "WanVideoEnhanceAVideo", - "pos": [ - 1292.82177734375, - -760.1163330078125 - ], - "size": [ - 315, - 106 - ], - "flags": {}, - "order": 7, - "mode": 0, - "inputs": [], - "outputs": [ - { - "name": "feta_args", - "type": "FETAARGS", - "links": [ - 57 - ] - } - ], - "properties": { - "Node name for S&R": "WanVideoEnhanceAVideo", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [ - 2, - 0, - 1 - ] - }, - { - "id": 54, - "type": "Note", - "pos": [ - 1279.785888671875, - -927.4588012695312 - ], - "size": [ - 327.61932373046875, - 88 - ], - "flags": {}, - "order": 8, - "mode": 0, - "inputs": [], - "outputs": [], - "properties": {}, - "widgets_values": [ - "Enhance-a-video can increase the fidelity of the results, too high values lead to noisy results." - ], - "color": "#432", - "bgcolor": "#653" - }, - { - "id": 42, - "type": "Note", - "pos": [ - -340.0147399902344, - -394.8644104003906 - ], - "size": [ - 312.98052978515625, - 92.32489013671875 - ], - "flags": {}, - "order": 9, - "mode": 0, - "inputs": [], - "outputs": [], - "properties": {}, - "widgets_values": [ - "Adjust the blocks to swap based on your VRAM, this is a tradeoff between speed and memory usage." - ], - "color": "#432", - "bgcolor": "#653" - }, - { - "id": 61, - "type": "MarkdownNote", - "pos": [ - 30.22911262512207, - -955.12451171875 - ], - "size": [ - 510.2661437988281, - 245.62203979492188 - ], - "flags": {}, - "order": 10, - "mode": 0, - "inputs": [], - "outputs": [], - "properties": {}, - "widgets_values": [ - "Models:\n\n[https://huggingface.co/Kijai/WanVideo_comfy_fp8_scaled/blob/main/T2V/Wan2_1-T2V-14B_fp8_e4m3fn_scaled_KJ.safetensors](https://huggingface.co/Kijai/WanVideo_comfy_fp8_scaled/blob/main/T2V/Wan2_1-T2V-14B_fp8_e4m3fn_scaled_KJ.safetensors)\n\nIf you want to use torch compile on GPUs prior to 4000 series:\n\n[https://huggingface.co/Kijai/WanVideo_comfy_fp8_scaled/blob/main/T2V/Wan2_1-T2V-14B_fp8_e5m2_scaled_KJ.safetensors](https://huggingface.co/Kijai/WanVideo_comfy_fp8_scaled/blob/main/T2V/Wan2_1-T2V-14B_fp8_e5m2_scaled_KJ.safetensors)\n\nLoRA:\n\n[https://huggingface.co/Kijai/WanVideo_comfy/blob/main/Lightx2v/lightx2v_T2V_14B_cfg_step_distill_v2_lora_rank64_bf16.safetensors](https://huggingface.co/Kijai/WanVideo_comfy/blob/main/Lightx2v/lightx2v_T2V_14B_cfg_step_distill_v2_lora_rank64_bf16.safetensors)" - ], - "color": "#432", - "bgcolor": "#653" - }, - { - "id": 36, - "type": "Note", - "pos": [ - 110, - -630 - ], - "size": [ - 374.3061828613281, - 171.9547576904297 - ], - "flags": {}, - "order": 11, - "mode": 0, - "inputs": [], - "outputs": [], - "properties": {}, - "widgets_values": [ - "fp_16_fast enables \"Full FP16 Accmumulation in FP16 GEMMs\" feature available in the very latest pytorch nightly, this is around 20% speed boost. \n\nSageattn if you have it installed can be used for almost double inference speed at higher resolutions\n\nRadial attention is even faster but has worst quality, it should be used along with Set Radial Attention node to control which steps/blocks it's applied on to balance quality and speed." - ], - "color": "#432", - "bgcolor": "#653" - }, - { - "id": 38, - "type": "WanVideoVAELoader", - "pos": [ - 1687.4093017578125, - -582.2750854492188 - ], - "size": [ - 315, - 82 - ], - "flags": {}, - "order": 12, - "mode": 0, - "inputs": [ - { - "name": "compile_args", - "shape": 7, - "type": "WANCOMPILEARGS", - "link": null - } - ], - "outputs": [ - { - "name": "vae", - "type": "WANVAE", - "slot_index": 0, - "links": [ - 43 - ] - } - ], - "properties": { - "Node name for S&R": "WanVideoVAELoader", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [ - "wan_2.1_vae.safetensors", - "bf16" - ], - "color": "#322", - "bgcolor": "#533" - }, - { - "id": 60, - "type": "WanVideoLoraSelectMulti", - "pos": [ - 573.026123046875, - -824.0180053710938 - ], - "size": [ - 332.3269348144531, - 342 - ], - "flags": {}, - "order": 13, - "mode": 0, - "inputs": [ - { - "name": "prev_lora", - "shape": 7, - "type": "WANVIDLORA", - "link": null - }, - { - "name": "blocks", - "shape": 7, - "type": "SELECTEDBLOCKS", - "link": null - } - ], - "outputs": [ - { - "name": "lora", - "type": "WANVIDLORA", - "links": [ - 64 - ] - } - ], - "properties": { - "Node name for S&R": "WanVideoLoraSelectMulti", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [ - "Wan21_T2V_14B_lightx2v_cfg_step_distill_lora_rank32.safetensors", - 1, - "none", - 1, - "none", - 1, - "none", - 1, - "none", - 1, - false, - false - ], - "color": "#223", - "bgcolor": "#335" - }, - { - "id": 22, - "type": "WanVideoModelLoader", - "pos": [ - 10, - -390 - ], - "size": [ - 477.4410095214844, - 274 - ], - "flags": {}, - "order": 14, - "mode": 0, - "inputs": [ - { - "name": "compile_args", - "shape": 7, - "type": "WANCOMPILEARGS", - "link": null - }, - { - "name": "block_swap_args", - "shape": 7, - "type": "BLOCKSWAPARGS", - "link": null - }, - { - "name": "lora", - "shape": 7, - "type": "WANVIDLORA", - "link": null - }, - { - "name": "vram_management_args", - "shape": 7, - "type": "VRAM_MANAGEMENTARGS", - "link": null - }, - { - "name": "vace_model", - "shape": 7, - "type": "VACEPATH", - "link": null - }, - { - "name": "fantasytalking_model", - "shape": 7, - "type": "FANTASYTALKINGMODEL", - "link": null - }, - { - "name": "multitalk_model", - "shape": 7, - "type": "MULTITALKMODEL", - "link": null - } - ], - "outputs": [ - { - "name": "model", - "type": "WANVIDEOMODEL", - "slot_index": 0, - "links": [] - } - ], - "properties": { - "Node name for S&R": "WanVideoModelLoader", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [ - "Wan2_1-T2V-14B_fp8_e5m2.safetensors", - "fp16", - "fp8_e5m2", - "main_device", - "sdpa" - ], - "color": "#223", - "bgcolor": "#335" - }, - { - "id": 39, - "type": "WanVideoBlockSwap", - "pos": [ - 569.0033569335938, - -245.12271118164062 - ], - "size": [ - 315, - 154 - ], - "flags": {}, - "order": 15, - "mode": 0, - "inputs": [], - "outputs": [ - { - "name": "block_swap_args", - "type": "BLOCKSWAPARGS", - "slot_index": 0, - "links": [ - 58 - ] - } - ], - "properties": { - "Node name for S&R": "WanVideoBlockSwap", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [ - 20, - false, - false, - false, - 0 - ], - "color": "#223", - "bgcolor": "#335" - }, - { - "id": 16, - "type": "WanVideoTextEncode", - "pos": [ - 70, - -70 - ], - "size": [ - 420.30511474609375, - 261.5306701660156 - ], - "flags": {}, - "order": 17, - "mode": 0, - "inputs": [ - { - "name": "t5", - "shape": 7, - "type": "WANTEXTENCODER", - "link": 15 - }, - { - "name": "model_to_offload", - "shape": 7, - "type": "WANVIDEOMODEL", - "link": null - } - ], - "outputs": [ - { - "name": "text_embeds", - "type": "WANVIDEOTEXTEMBEDS", - "slot_index": 0, - "links": [ - 30 - ] - } - ], - "properties": { - "Node name for S&R": "WanVideoTextEncode", - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652" - }, - "widgets_values": [ - "high quality nature video featuring a red panda balancing on a bamboo stem while a bird lands on it's head, on the background there is a waterfall", - "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走", - true, - false, - "cpu" - ], - "color": "#332922", - "bgcolor": "#593930" - }, - { - "id": 62, - "type": "WanVideoModelLoaderMultiGPU", - "pos": [ - 806.5021362304688, - -18.34801483154297 - ], - "size": [ - 361.5178527832031, - 298 - ], - "flags": {}, - "order": 16, - "mode": 0, - "inputs": [ - { - "name": "compile_args", - "shape": 7, - "type": "WANCOMPILEARGS", - "link": null - }, - { - "name": "block_swap_args", - "shape": 7, - "type": "BLOCKSWAPARGS", - "link": null - }, - { - "name": "lora", - "shape": 7, - "type": "WANVIDLORA", - "link": null - }, - { - "name": "vram_management_args", - "shape": 7, - "type": "VRAM_MANAGEMENTARGS", - "link": null - }, - { - "name": "vace_model", - "shape": 7, - "type": "VACEPATH", - "link": null - }, - { - "name": "fantasytalking_model", - "shape": 7, - "type": "FANTASYTALKINGMODEL", - "link": null - }, - { - "name": "multitalk_model", - "shape": 7, - "type": "MULTITALKMODEL", - "link": null - } - ], - "outputs": [ - { - "name": "model", - "type": "WANVIDEOMODEL", - "links": [ - 67 - ] - } - ], - "properties": { - "Node name for S&R": "WanVideoModelLoaderMultiGPU" - }, - "widgets_values": [ - "Wan2_1-T2V-14B_fp8_e5m2.safetensors", - "fp16", - "fp8_e5m2", - "main_device", - "sdpa", - "cuda:1" - ] - } - ], - "links": [ - [ - 15, - 11, - 0, - 16, - 0, - "WANTEXTENCODER" - ], - [ - 30, - 16, - 0, - 27, - 2, - "WANVIDEOTEXTEMBEDS" - ], - [ - 33, - 27, - 0, - 28, - 1, - "LATENT" - ], - [ - 36, - 28, - 0, - 30, - 0, - "IMAGE" - ], - [ - 42, - 37, - 0, - 27, - 1, - "WANVIDIMAGE_EMBEDS" - ], - [ - 43, - 38, - 0, - 28, - 0, - "VAE" - ], - [ - 52, - 48, - 0, - 49, - 0, - "CLIP" - ], - [ - 53, - 48, - 0, - 50, - 0, - "CLIP" - ], - [ - 54, - 49, - 0, - 46, - 0, - "CONDITIONING" - ], - [ - 55, - 50, - 0, - 46, - 1, - "CONDITIONING" - ], - [ - 57, - 55, - 0, - 27, - 4, - "FETAARGS" - ], - [ - 58, - 39, - 0, - 56, - 1, - "BLOCKSWAPARGS" - ], - [ - 60, - 56, - 0, - 27, - 0, - "WANVIDEOMODEL" - ], - [ - 62, - 58, - 0, - 56, - 0, - "WANVIDEOMODEL" - ], - [ - 64, - 60, - 0, - 58, - 1, - "WANVIDLORA" - ], - [ - 67, - 62, - 0, - 58, - 0, - "WANVIDEOMODEL" - ] - ], - "groups": [ - { - "id": 1, - "title": "ComfyUI text encoding alternative", - "bounding": [ - 28.03142547607422, - 288.1825866699219, - 1210.621337890625, - 805.9080810546875 - ], - "color": "#3f789e", - "font_size": 24, - "flags": {} - } - ], - "config": {}, - "extra": { - "ds": { - "scale": 0.8954302432552947, - "offset": [ - 573.1206723177218, - 778.9430746140687 - ] - }, - "frontendVersion": "1.23.4", - "node_versions": { - "ComfyUI-WanVideoWrapper": "5a2383621a05825d0d0437781afcb8552d9590fd", - "comfy-core": "0.3.26", - "ComfyUI-VideoHelperSuite": "0a75c7958fe320efcb052f1d9f8451fd20c730a8" - }, - "VHS_latentpreview": false, - "VHS_latentpreviewrate": 0, - "VHS_MetadataImage": true, - "VHS_KeepIntermediate": true - }, - "version": 0.4 -} \ No newline at end of file diff --git a/pr.html b/pr.html new file mode 100644 index 0000000..d066e40 --- /dev/null +++ b/pr.html @@ -0,0 +1,4796 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Support XPU prefix by Nuitari · Pull Request #75 · pollockjj/ComfyUI-MultiGPU · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ Skip to content + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + +
+ +
+ + +
+
+
+

+ Support XPU prefix + #75 +

+ +
+
+
+ + + + +
+ + + New issue + + +
+
+ +
+ +
+

+ Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community. +

+ + + +

By clicking “Sign up for GitHub”, you agree to our terms of service and + privacy statement. We’ll occasionally send you account related emails.

+ +

+ Already on GitHub? + Sign in + to your account +

+
+ +
+
+
+ +
+
+
+ +
+
+ + Open + +
+ + + + +
+ + + wants to merge + 1 + commit into + + + + +
+
+ + base: + main + + + + +
+
+
+ Choose a base branch + +
+ + +
+ +
+ + + + +
+ + + + + + + + + + + + + + +
+ + +
+
+
+
+ + +
+
+ +
+ +
+ +from + + + + + +
+
+ + + + + + + + + +
+
+ + +
+ +
+
+
+ + + + + + + +
+
+
+
+
+ + Open + +
+ + + + +
+

+ + Support XPU prefix + + #75 +

+ +
+ + + wants to merge + 1 + commit into + + + + +from + + + + + +
+
+ + + + +
+
+
+
+
+
+
+
+ + + + + + + + + +
+
+

Conversation

+
+ + + +
+ +
+ +
+ Nuitari + + +
+
+
+
+
+ + + + + + + + + + + + Copy link + +
+
+
+
+ +
+ + + + + + +
+ +

+
+ @Nuitari + + + Nuitari + + + + + + + commented + + + Jul 20, 2025 + + + + • + + + + +
+ +

+
+ +
+
+ + +
+

Intel GPU's are detected with the prefix of xpu: instead of cuda:
+This PR allows the xpu: entries to show up in the selector.

+

Summary by Sourcery

+

Enable detection and selection of Intel XPU devices by adding torch.xpu availability checks, listing xpu devices, and updating allocation routines to include XPU alongside CUDA

+

New Features:

+
    +
  • Add support for torch.xpu device availability alongside CUDA for main and text encoder device selection
  • +
  • Include xpu:{i} entries in the global device list
  • +
  • Extend VRAM allocation logic to consider XPU devices when building available device selections
  • +
+
+
+ +
+ +
+ +
+ + +

+ + + + + +

+ + + +
+
+
+ +
+ +
+
+
+ + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+
+ + @sbakhos +
+
+ +
+ + Support XPU + + +
+ +
+ + + + + + + + +
+ +
+
+ + + + + + + + +
+ +
+ +
+
+
+ +
+ + 04f94f8 + +
+
+
+
+ +
+
+
+ + +
+ +
+ + +
+ +
+ @sourcery-ai + + + Sourcery AI + +
+ + + +
+ +
+
+
+
+ + + + + + + + + + + + Copy link + +
+
+
+
+ +
+ + + + + + +
+ +

+
+ + + + sourcery-ai + bot + + + + + + commented + + + Jul 20, 2025 + + + + • + + + + +
+ +

+
+ + +
+ + + + + + + + + +
+ +

Reviewer's Guide

+

This PR integrates support for the Intel GPU prefix “xpu:” by expanding device availability checks, updating the device list, and extending allocation logic to include xpu alongside cuda.

+

Class diagram for device selection and allocation changes

+
+
+
+
classDiagram
+    class DeviceSelectorMultiGPU {
+        +override(*args, device=None, expert_mode_allocations=None, use_other_vram=None)
+    }
+    class Torch {
+        +cuda.is_available()
+        +cuda.device_count()
+        +xpu.is_available()
+        +xpu.device_count()
+    }
+    class mm {
+        CPUState
+        cpu_state
+    }
+    class get_torch_device_patched {
+        +get_torch_device_patched()
+    }
+    class text_encoder_device_patched {
+        +text_encoder_device_patched()
+    }
+    class get_device_list {
+        +get_device_list()
+    }
+    DeviceSelectorMultiGPU --|> get_device_list
+    get_torch_device_patched --|> Torch
+    text_encoder_device_patched --|> Torch
+    get_device_list --|> Torch
+
+
+
+ + + Loading + + +
+ +

File-Level Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ChangeDetailsFiles
Include xpu availability in device selection functions
  • Add torch.xpu.is_available() to the get_torch_device_patched condition
  • Add torch.xpu.is_available() to the text_encoder_device_patched condition
__init__.py
Add xpu devices to the global device list
  • Extend get_device_list return value with f"xpu:{i}" entries based on torch.xpu.device_count()
__init__.py
Extend device filtering in VRAM allocation to include xpu
  • Include xpu-prefixed devices in available_devices filter in the first override block
  • Include xpu-prefixed devices in available_devices filter in the second override block
__init__.py
+
+
+Tips and commands +

Interacting with Sourcery

+
    +
  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • +
  • Continue discussions: Reply directly to Sourcery's review comments.
  • +
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    +issue from a review comment by replying to it. You can also reply to a
    +review comment with @sourcery-ai issue to create an issue from it.
  • +
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    +request title to generate a title at any time. You can also comment
    +@sourcery-ai title on the pull request to (re-)generate the title at any time.
  • +
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    +the pull request body to generate a PR summary at any time exactly where you
    +want it. You can also comment @sourcery-ai summary on the pull request to
    +(re-)generate the summary at any time.
  • +
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    +request to (re-)generate the reviewer's guide at any time.
  • +
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    +pull request to resolve all Sourcery comments. Useful if you've already
    +addressed all the comments and don't want to see them anymore.
  • +
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    +request to dismiss all existing Sourcery reviews. Especially useful if you
    +want to start fresh with a new review - don't forget to comment
    +@sourcery-ai review to trigger a new review!
  • +
+

Customizing Your Experience

+

Access your dashboard to:

+
    +
  • Enable or disable review features such as the Sourcery-generated pull request
    +summary, the reviewer's guide, and others.
  • +
  • Change the review language.
  • +
  • Add, remove or edit custom review instructions.
  • +
  • Adjust other review settings.
  • +
+

Getting Help

+ +
+ +
+
+ + +
+ + + + +
+ +
+
+
+ +
+ + +

+ + + + + +

+ + + +
+
+
+ +
+ + +
+ + +
+ +
+
+
+ sourcery-ai[bot] +
+
+ + sourcery-ai + bot + + + + reviewed + + + + + Jul 20, 2025 + + + +
+ + +
+
+
+ + +
+
+
+
+ + + + + + + + + + + + Copy link + +
+
+
+
+ +
+ + + + + + +
+ +

+
+ @sourcery-ai + + + sourcery-ai + bot + + + + + + left a comment + + + + + +
+ +

+
+ + +
+
+ +
+ + + +

Choose a reason for hiding this comment

+ +

+ The reason will be displayed to describe this comment to others. Learn more. +

+ +
+ + +
+ + +
+ + +
+

Hey @Nuitari - I've reviewed your changes - here's some feedback:

+
    +
  • Wrap direct torch.xpu calls in hasattr or try/except blocks to avoid runtime errors on PyTorch builds without XPU support.
  • +
  • Extract the repeated (cuda or xpu) availability check and device-list construction into a shared helper to reduce duplication.
  • +
+
+Prompt for AI Agents +
Please address the comments from this code review:
+## Overall Comments
+- Wrap direct torch.xpu calls in hasattr or try/except blocks to avoid runtime errors on PyTorch builds without XPU support.
+- Extract the repeated (cuda or xpu) availability check and device-list construction into a shared helper to reduce duplication.
+
+## Individual Comments
+
+### Comment 1
+<location> `__init__.py:40` </location>
+<code_context>
+ def get_torch_device_patched():
+     device = None
+-    if (not torch.cuda.is_available() or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_device).lower()):
++    if (not (torch.cuda.is_available() or torch.xpu.is_available()) or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_device).lower()):
+         device = torch.device("cpu")
+     else:
+</code_context>
+
+<issue_to_address>
+Potential AttributeError if torch.xpu is not available in all environments.
+
+To avoid errors, use hasattr(torch, 'xpu') before accessing torch.xpu methods.
+</issue_to_address>
+
+### Comment 2
+<location> `__init__.py:48` </location>
+<code_context>
+ def text_encoder_device_patched():
+     device = None
+-    if (not torch.cuda.is_available() or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_text_encoder_device).lower()):
++    if (not (torch.cuda.is_available() or torch.xpu.is_available()) or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_text_encoder_device).lower()):
+         device = torch.device("cpu")
+     else:
+</code_context>
+
+<issue_to_address>
+torch.xpu usage may not be safe on all platforms.
+
+Add a check like hasattr(torch, 'xpu') before using torch.xpu to prevent errors on systems where it is unavailable.
+</issue_to_address>
+
+### Comment 3
+<location> `__init__.py:328` </location>
+<code_context>
+ def get_device_list():
+     import torch
+-    return ["cpu"] + [f"cuda:{i}" for i in range(torch.cuda.device_count())]
++    return ["cpu"] + [f"cuda:{i}" for i in range(torch.cuda.device_count())] + [f"xpu:{i}" for i in range(torch.xpu.device_count())]
+
+ class DeviceSelectorMultiGPU:
+</code_context>
+
+<issue_to_address>
+Unconditional torch.xpu.device_count() may cause errors if xpu is not present.
+
+Check for 'xpu' in torch with hasattr(torch, 'xpu') before calling torch.xpu.device_count() to avoid AttributeError on systems without xpu support.
+</issue_to_address>
+
+
+
+Sourcery is free for open source - if you like our reviews please consider sharing them ✨ + +
+ +Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews. + +
+
+ +
+ + +
+ + +

+ + + + + +

+ + + +
+
+
+ +
+ +
+
+
+
+ + +
+ + +
+
+ + __init__.py + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -37,15 +37,15 @@
+
+ +
+ def get_torch_device_patched(): + +
+ device = None + +
+ if (not torch.cuda.is_available() or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_device).lower()): + +
+ if (not (torch.cuda.is_available() or torch.xpu.is_available()) or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_device).lower()): + +
+ +
+ + +
+
+
+
+
+
+
+ + + + + + + + + + + + Copy link + +
+
+
+
+ +
+ + + + + + +
+ +

+
+ @sourcery-ai + + + sourcery-ai + bot + + + + + + + + + Jul 20, 2025 + + + +
+ +

+
+ +
+
+
+ +
+ + + +

Choose a reason for hiding this comment

+ +

+ The reason will be displayed to describe this comment to others. Learn more. +

+ +
+ + +
+ + +
+ + +
+

issue (bug_risk): Potential AttributeError if torch.xpu is not available in all environments.

+

To avoid errors, use hasattr(torch, 'xpu') before accessing torch.xpu methods.

+
+
+ + +
+
+ +
+ + +

+ + + + + +

+ + + +
+
+
+ +
+ +
+ + + + +
+ +
+ +
+ +
+
+
+
+ + + + +
+
+ + __init__.py + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ device = torch.device("cpu") + +
+ else: + +
+ device = torch.device(current_device) + +
+ return device + +
+
+ +
+ def text_encoder_device_patched(): + +
+ device = None + +
+ if (not torch.cuda.is_available() or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_text_encoder_device).lower()): + +
+ if (not (torch.cuda.is_available() or torch.xpu.is_available()) or mm.cpu_state == mm.CPUState.CPU or "cpu" in str(current_text_encoder_device).lower()): + +
+ +
+ + +
+
+
+
+
+
+
+ + + + + + + + + + + + Copy link + +
+
+
+
+ +
+ + + + + + +
+ +

+
+ @sourcery-ai + + + sourcery-ai + bot + + + + + + + + + Jul 20, 2025 + + + +
+ +

+
+ +
+
+
+ +
+ + + +

Choose a reason for hiding this comment

+ +

+ The reason will be displayed to describe this comment to others. Learn more. +

+ +
+ + +
+ + +
+ + +
+

issue (bug_risk): torch.xpu usage may not be safe on all platforms.

+

Add a check like hasattr(torch, 'xpu') before using torch.xpu to prevent errors on systems where it is unavailable.

+
+
+ + +
+
+ +
+ + +

+ + + + + +

+ + + +
+
+
+ +
+ +
+ + + + +
+ +
+ +
+ +
+
+
+
+ + + + +
+
+ + __init__.py + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -325,7 +325,7 @@ def calculate_vvram_allocation_string(model, virtual_vram_str):
+
+ +
+ def get_device_list(): + +
+ import torch + +
+ return ["cpu"] + [f"cuda:{i}" for i in range(torch.cuda.device_count())] + +
+ return ["cpu"] + [f"cuda:{i}" for i in range(torch.cuda.device_count())] + [f"xpu:{i}" for i in range(torch.xpu.device_count())] + +
+ +
+ + +
+
+
+
+
+
+
+ + + + + + + + + + + + Copy link + +
+
+
+
+ +
+ + + + + + +
+ +

+
+ @sourcery-ai + + + sourcery-ai + bot + + + + + + + + + Jul 20, 2025 + + + +
+ +

+
+ +
+
+
+ +
+ + + +

Choose a reason for hiding this comment

+ +

+ The reason will be displayed to describe this comment to others. Learn more. +

+ +
+ + +
+ + +
+ + +
+

issue (bug_risk): Unconditional torch.xpu.device_count() may cause errors if xpu is not present.

+

Check for 'xpu' in torch with hasattr(torch, 'xpu') before calling torch.xpu.device_count() to avoid AttributeError on systems without xpu support.

+
+
+ + +
+
+ +
+ + +

+ + + + + +

+ + + +
+
+
+ +
+ +
+ + + + +
+ +
+ +
+ +
+
+
+
+ + + + +
+
+
+ + +
+ + + + + + +
+
+ +
+ + + +
+ +
+ +
+
+ +
+ + Sign up for free + to join this conversation on GitHub. + Already have an account? + Sign in to comment + + + +
+ +
+
+
+ +
+
+
+ + + + + + + + +
+ + + +
+ Labels +
+ + +
+ None yet +
+ +
+ + + + +
+
+
+ Projects +
+ +
+
+ + None yet + + + +
+ + + + + + + + + +
+
+
+ +
+ +
+ Development +
+ + + + +

Successfully merging this pull request may close these issues.

+ + + + + + + + +
+
+
+
+ +
+ + + + +
+
+
+ 2 participants +
+ +
+
+ + + + + + + + + + + + +
+ + +
+ +
+
+ + + +
+ + +
+ +
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + diff --git a/precompiled_binaries/linux/llama-quantize b/precompiled_binaries/linux/llama-quantize deleted file mode 100755 index 04708cb..0000000 Binary files a/precompiled_binaries/linux/llama-quantize and /dev/null differ diff --git a/precompiled_binaries/win64/llama-quantize.exe b/precompiled_binaries/win64/llama-quantize.exe deleted file mode 100755 index 6c0eb2c..0000000 Binary files a/precompiled_binaries/win64/llama-quantize.exe and /dev/null differ diff --git a/pyproject.toml b/pyproject.toml index 1331023..02ac2a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui-multigpu" description = "Adds full multi-GPU support for WanVideoWrapper, enabling model loading and block-swapping on any device. Provides a suite of custom nodes to manage multiple GPUs for ComfyUI, including advanced GGUF offloading with DisTorch and device overrides for core nodes." -version = "1.8.0" +version = "1.8.1" license = {file = "LICENSE"} [project.urls] @@ -11,4 +11,4 @@ Repository = "https://github.com/pollockjj/ComfyUI-MultiGPU" [tool.comfy] PublisherId = "pollockjj" DisplayName = "ComfyUI-MultiGPU" -Icon = "https://raw.githubusercontent.com/pollockjj/ComfyUI-MultiGPU/main/assets/multigpu_icon.png" \ No newline at end of file +Icon = "https://raw.githubusercontent.com/pollockjj/ComfyUI-MultiGPU/main/assets/multigpu_icon.png"