Critical fixes: - AnyAspectRatio: remove dead duplicate calculation that was overwriting itself with a wrong formula (correct formula kept on lines 55-56) - LoadImageResizer: fix trailing comma that made resized_mask a tuple instead of a value; properly convert alpha channel to float32 tensor - openAI_PoP: replace deprecated openai v0 API (openai.Image.create, openai.error.*) with modern openai>=1.0 client; fix hardcoded Windows backslash path with os.path.dirname(__file__); fix log/image dirs to be relative to module file instead of CWD - LoraStackLoaders: add missing `import comfy.sd` (was NameError at runtime); fix filter from l[0] (switch, never 'None') to l[1] (lora_name); fix `lora_name is None` to `== 'None'` for string comparison; fix display name mapping key LoraStackLoader10 -> LoraStackLoader10_PoP High severity fixes: - Conditioning: guard std() divisions with `if std > 0` to prevent NaN/Inf crash when tensor has zero variance - EfficientAttention: move dim_head calculation after dimension truncation so reshape is always valid; add divisibility check; fix output reshape to use min_dim not dim_q - VAEEncodeDecodeLoader: remove 5 debug print statements from decode() - CNutil: remove 3 debug print statements from resize_to_resolution() Minor fixes: - AdaptiveCannyDetector: fix `Category` -> `CATEGORY` (case-sensitive, ComfyUI was ignoring the node category) - LoadImageResizer: remove duplicate CATEGORY = "image" definition - requirements.txt: remove unused matplotlib/seaborn; add missing Pillow https://claude.ai/code/session_01QPLKoy7P41H3QPB6tMrpPh
79 lines
2.2 KiB
Python
79 lines
2.2 KiB
Python
# VAE Encode Decode Loader
|
|
import numpy as np
|
|
import os
|
|
import sys
|
|
import folder_paths
|
|
import comfy.sd
|
|
#we need proper documentation for this class
|
|
# singleton VAE model loader
|
|
class VAEModel:
|
|
_instances = {}
|
|
|
|
@classmethod
|
|
def get_instance(cls, vae_path):
|
|
if vae_path not in cls._instances:
|
|
cls._instances[vae_path] = comfy.sd.VAE(ckpt_path=vae_path)
|
|
return cls._instances[vae_path]
|
|
|
|
# VAE Encoder node
|
|
class VAEEncoderPoP:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"pixels": ("IMAGE", ),
|
|
"vae_name": (folder_paths.get_filename_list("vae"), )
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("LATENT",)
|
|
RETURN_NAMES = ("samples",)
|
|
FUNCTION = "encode"
|
|
|
|
def vae_encode_crop_pixels(self, pixels):
|
|
height, width, _ = pixels.shape[1:]
|
|
new_dim = min(height, width)
|
|
height_start = (height - new_dim) // 2
|
|
width_start = (width - new_dim) // 2
|
|
cropped_pixels = pixels[:, height_start:height_start + new_dim, width_start:width_start + new_dim, :]
|
|
return cropped_pixels
|
|
|
|
def encode(self, vae_name, pixels):
|
|
vae_path = folder_paths.get_full_path('vae', vae_name)
|
|
vae = VAEModel.get_instance(vae_path)
|
|
pixels = self.vae_encode_crop_pixels(pixels)
|
|
encoded = vae.encode(pixels[:,:,:,:3])
|
|
return ({"samples": encoded}, )
|
|
|
|
# VAE Decoder node
|
|
class VAEDecoderPoP:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"samples": ("LATENT", ),
|
|
"vae_name": (folder_paths.get_filename_list("vae"), )
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
|
|
FUNCTION = "decode"
|
|
|
|
def decode(self, vae_name, samples):
|
|
vae_path = folder_paths.get_full_path('vae', vae_name)
|
|
vae = VAEModel.get_instance(vae_path)
|
|
decoded = (vae.decode(samples["samples"]),)
|
|
return decoded
|
|
|
|
NODE_CLASS_MAPPINGS = {
|
|
"VAEEncoderPoP": VAEEncoderPoP,
|
|
"VAEDecoderPoP": VAEDecoderPoP
|
|
}
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"VAEEncoderPoP": "VAE Encoder PoP",
|
|
"VAEDecoderPoP": "VAE Decoder PoP"
|
|
}
|
|
|
|
|