Instructions to use bbbboiwow/cocccck with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use bbbboiwow/cocccck with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("bbbboiwow/cocccck", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
| import folder_paths | |
| import os | |
| import json | |
| import re | |
| from PIL import Image, ImageOps | |
| import numpy as np | |
| import torch | |
| import hashlib | |
| class LoadImageExtended: | |
| def __init__(self): | |
| pass | |
| def INPUT_TYPES(s): | |
| input_dir = folder_paths.get_input_directory() | |
| files = [ | |
| f | |
| for f in os.listdir(input_dir) | |
| if os.path.isfile(os.path.join(input_dir, f)) | |
| ] | |
| return { | |
| "required": { | |
| "image": (sorted(files), {"image_upload": True}), | |
| }, | |
| "optional": {"vae": ("VAE",)}, | |
| } | |
| CATEGORY = "Chibi-Nodes/Image" | |
| # changes here | |
| RETURN_TYPES = ( | |
| "IMAGE", | |
| "MASK", | |
| "LATENT", | |
| "STRING", | |
| "STRING", | |
| "INT", | |
| "INT", | |
| ) | |
| RETURN_NAMES = ( | |
| "IMAGE", | |
| "MASK", | |
| "LATENT", | |
| "filename", | |
| "image Info", | |
| "width", | |
| "height", | |
| ) | |
| # | |
| FUNCTION = "load_image" | |
| def load_image(self, image, vae=None): | |
| image_path = folder_paths.get_annotated_filepath(image) | |
| # Check if os is windows for backwards paths. | |
| if os.name == "nt": | |
| filename = image_path.rsplit("\\", 1)[-1] | |
| else: | |
| filename = image_path.rsplit("/", 1)[-1] | |
| im = Image.open(image_path) | |
| # Start ai-info.py section, with no exif | |
| def type_changer(value): | |
| if value.isnumeric(): | |
| return int(value) | |
| else: | |
| return value | |
| im.load() | |
| prompt = {} | |
| if "prompt" in im.info.keys(): | |
| # comfyui, workflow is also available but we aren't getting that today | |
| # prompt = {} | |
| prompt.update({"prompt": json.loads(im.info["prompt"])}) | |
| else: | |
| # automatic111, gosh this is a mess. | |
| if "parameters" in im.info.keys(): | |
| parameters = im.info["parameters"] | |
| prompt = {"parameters": {}} | |
| parameters = re.split( | |
| "(Negative prompt): |(Negative Template): |(Template): |(ControlNet): |\n", | |
| parameters, | |
| ) | |
| # removes None and new lines | |
| parameters_clean_none = [] | |
| for i in range(0, len(parameters)): | |
| if parameters[i] is None: | |
| pass | |
| elif parameters[i] == "": | |
| pass | |
| else: | |
| parameters_clean_none.append(parameters[i]) | |
| parameters = parameters_clean_none | |
| # settings field | |
| parameters_settings = {} | |
| for i in range(0, len(parameters)): | |
| if parameters[i].split(":", 1)[0] == "Steps": | |
| parameters[i] = re.split(", ", parameters[i]) | |
| for k in parameters[i]: | |
| k = k.split(": ", 1) | |
| if len(k) == 2: | |
| k[1] = type_changer(k[1]) | |
| # makes "Size" : "(widthxheight)" into two keys | |
| if k[0] == "Size": | |
| k[1] = k[1].split("x") | |
| for s in range(0, len(k[1])): | |
| k[1][s] = type_changer(k[1][s]) | |
| parameters_settings.update( | |
| {"width": k[1][0]}) | |
| parameters_settings.update( | |
| {"height": k[1][1]}) | |
| else: | |
| parameters_settings.update({k[0]: k[1]}) | |
| parameters[i] = parameters_settings | |
| # builder | |
| parameters_built = {} | |
| for i in range(0, len(parameters)): | |
| match parameters[i]: | |
| case "Negative prompt": | |
| parameters_built.update( | |
| {parameters[i]: parameters[i + 1]}) | |
| case "Negative Template": | |
| parameters_built.update( | |
| {parameters[i]: parameters[i + 1]}) | |
| case "Template": | |
| parameters_built.update( | |
| {parameters[i]: parameters[i + 1]}) | |
| case "ControlNet": | |
| parameters_built.update( | |
| {parameters[i]: parameters[i + 1]}) | |
| case dict(): | |
| parameters_built.update(parameters[i]) | |
| case _: | |
| if i == 0: | |
| parameters_built.update( | |
| {"Positive prompt": parameters[i]} | |
| ) | |
| pass | |
| prompt["parameters"] = parameters_built | |
| if type(prompt) is dict: | |
| prompt = json.dumps(prompt, indent=2) | |
| elif type(prompt) is str: | |
| prompt = json.dumps(json.loads(prompt), indent=2) | |
| # end section | |
| im = ImageOps.exif_transpose(im) | |
| image = im.convert("RGB") | |
| image = np.array(image).astype(np.float32) / 255.0 | |
| image = torch.from_numpy(image)[None,] | |
| shape = image.shape | |
| width = shape[2] | |
| height = shape[1] | |
| if "A" in im.getbands(): | |
| mask = np.array(im.getchannel("A")).astype(np.float32) / 255.0 | |
| mask = 1.0 - torch.from_numpy(mask) | |
| else: | |
| mask = torch.zeros((64, 64), dtype=torch.float32, device="cpu") | |
| if vae is not None: | |
| latent = image | |
| x = (latent.shape[1] // 8) * 8 | |
| y = (latent.shape[2] // 8) * 8 | |
| if latent.shape[1] is not x or latent.shape[2] is not y: | |
| x_offset = (latent.shape[1] % 8) // 2 | |
| y_offset = (latent.shape[2] % 8) // 2 | |
| latent = latent[:, x_offset: x + | |
| x_offset, y_offset: y + y_offset, :] | |
| latent = vae.encode(latent[:, :, :, :3]) | |
| return ( | |
| image, | |
| mask.unsqueeze(0), | |
| {"samples": latent}, | |
| filename, | |
| str(prompt), | |
| width, | |
| height, | |
| ) | |
| else: | |
| return ( | |
| image, | |
| mask.unsqueeze(0), | |
| None, | |
| filename, | |
| str(prompt), | |
| width, | |
| height, | |
| ) | |
| def IS_CHANGED(s, image, vae=None): | |
| image_path = folder_paths.get_annotated_filepath(image) | |
| m = hashlib.sha256() | |
| with open(image_path, "rb") as f: | |
| m.update(f.read()) | |
| return m.digest().hex() | |
| def VALIDATE_INPUTS(s, image, vae=None): | |
| if not folder_paths.exists_annotated_filepath(image): | |
| return "Invalid image file: {}".format(image) | |
| return True | |