Spaces:
Running
on
L40S
Running
on
L40S
import base64 | |
import io | |
import json | |
from pathlib import Path | |
from typing import Optional | |
import folder_paths | |
import torch | |
from ..log import log | |
from ..utils import tensor2pil | |
# region processors | |
def process_tensor(tensor): | |
log.debug(f"Tensor: {tensor.shape}") | |
image = tensor2pil(tensor) | |
b64_imgs = [] | |
for im in image: | |
buffered = io.BytesIO() | |
im.save(buffered, format="PNG") | |
b64_imgs.append( | |
"data:image/png;base64," | |
+ base64.b64encode(buffered.getvalue()).decode("utf-8") | |
) | |
return {"b64_images": b64_imgs} | |
def process_list(anything): | |
text = [] | |
if not anything: | |
return {"text": []} | |
first_element = anything[0] | |
if ( | |
isinstance(first_element, list) | |
and first_element | |
and isinstance(first_element[0], torch.Tensor) | |
): | |
text.append( | |
"List of List of Tensors: " | |
f"{first_element[0].shape} (x{len(anything)})" | |
) | |
elif isinstance(first_element, torch.Tensor): | |
text.append( | |
f"List of Tensors: {first_element.shape} (x{len(anything)})" | |
) | |
else: | |
text.append(f"Array ({len(anything)}): {anything}") | |
return {"text": text} | |
def process_dict(anything): | |
text = [] | |
if "samples" in anything: | |
is_empty = ( | |
"(empty)" if torch.count_nonzero(anything["samples"]) == 0 else "" | |
) | |
text.append(f"Latent Samples: {anything['samples'].shape} {is_empty}") | |
else: | |
text.append(json.dumps(anything, indent=2)) | |
return {"text": text} | |
def process_bool(anything): | |
return {"text": ["True" if anything else "False"]} | |
def process_text(anything): | |
return {"text": [str(anything)]} | |
# endregion | |
class MTB_Debug: | |
"""Experimental node to debug any Comfy values. | |
support for more types and widgets is planned. | |
""" | |
def INPUT_TYPES(cls): | |
return { | |
"required": {"output_to_console": ("BOOLEAN", {"default": False})}, | |
} | |
RETURN_TYPES = () | |
FUNCTION = "do_debug" | |
CATEGORY = "mtb/debug" | |
OUTPUT_NODE = True | |
def do_debug(self, output_to_console: bool, **kwargs): | |
output = { | |
"ui": {"b64_images": [], "text": []}, | |
# "result": ("A"), | |
} | |
processors = { | |
torch.Tensor: process_tensor, | |
list: process_list, | |
dict: process_dict, | |
bool: process_bool, | |
} | |
if output_to_console: | |
for k, v in kwargs.items(): | |
log.info(f"{k}: {v}") | |
for anything in kwargs.values(): | |
processor = processors.get(type(anything), process_text) | |
processed_data = processor(anything) | |
for ui_key, ui_value in processed_data.items(): | |
output["ui"][ui_key].extend(ui_value) | |
return output | |
class MTB_SaveTensors: | |
"""Save torch tensors (image, mask or latent) to disk. | |
useful to debug things outside comfy. | |
""" | |
def __init__(self): | |
self.output_dir = folder_paths.get_output_directory() | |
self.type = "mtb/debug" | |
def INPUT_TYPES(cls): | |
return { | |
"required": { | |
"filename_prefix": ("STRING", {"default": "ComfyPickle"}), | |
}, | |
"optional": { | |
"image": ("IMAGE",), | |
"mask": ("MASK",), | |
"latent": ("LATENT",), | |
}, | |
} | |
FUNCTION = "save" | |
OUTPUT_NODE = True | |
RETURN_TYPES = () | |
CATEGORY = "mtb/debug" | |
def save( | |
self, | |
filename_prefix, | |
image: Optional[torch.Tensor] = None, | |
mask: Optional[torch.Tensor] = None, | |
latent: Optional[torch.Tensor] = None, | |
): | |
( | |
full_output_folder, | |
filename, | |
counter, | |
subfolder, | |
filename_prefix, | |
) = folder_paths.get_save_image_path(filename_prefix, self.output_dir) | |
full_output_folder = Path(full_output_folder) | |
if image is not None: | |
image_file = f"{filename}_image_{counter:05}.pt" | |
torch.save(image, full_output_folder / image_file) | |
# np.save(full_output_folder/ image_file, image.cpu().numpy()) | |
if mask is not None: | |
mask_file = f"{filename}_mask_{counter:05}.pt" | |
torch.save(mask, full_output_folder / mask_file) | |
# np.save(full_output_folder/ mask_file, mask.cpu().numpy()) | |
if latent is not None: | |
# for latent we must use pickle | |
latent_file = f"{filename}_latent_{counter:05}.pt" | |
torch.save(latent, full_output_folder / latent_file) | |
# pickle.dump(latent, open(full_output_folder/ latent_file, "wb")) | |
# np.save(full_output_folder / latent_file, | |
# latent[""].cpu().numpy()) | |
return f"{filename_prefix}_{counter:05}" | |
__nodes__ = [MTB_Debug, MTB_SaveTensors] | |