202 lines
7.2 KiB
Python
202 lines
7.2 KiB
Python
import torch
|
|
import os
|
|
import folder_paths
|
|
from transformers import CLIPTextModelWithProjection, CLIPTokenizer, T5EncoderModel, T5TokenizerFast
|
|
from diffusers import StableDiffusion3InstructPix2PixPipeline, AutoencoderKL, FlowMatchEulerDiscreteScheduler, SD3Transformer2DModel
|
|
import numpy as np
|
|
from PIL import Image
|
|
|
|
device = "cuda" if torch.cuda.is_available() else "cpu"
|
|
|
|
folder_paths.folder_names_and_paths["ultraedit"] = ([os.path.join(folder_paths.models_dir, "ultraedit")], folder_paths.supported_pt_extensions)
|
|
|
|
|
|
def tensor2pil(image):
|
|
return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))
|
|
|
|
def pil2tensor(image):
|
|
return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0)
|
|
|
|
def resize_to_closest_area(image, target_area=512*512):
|
|
original_width, original_height = image.size
|
|
original_area = original_width * original_height
|
|
|
|
# 计算缩放比例
|
|
scale = (target_area / original_area) ** 0.5
|
|
|
|
# 根据比例计算新的尺寸
|
|
new_width = int(original_width * scale)
|
|
new_height = int(original_height * scale)
|
|
|
|
return image.resize((new_width, new_height), Image.LANCZOS)
|
|
|
|
|
|
class UltraEdit_ModelLoader_Zho:
|
|
def __init__(self):
|
|
pass
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"base_model": ("STRING", {"default": "BleachNick/SD3_UltraEdit_w_mask"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("UEMODEL",)
|
|
RETURN_NAMES = ("pipe",)
|
|
FUNCTION = "load_model"
|
|
CATEGORY = "🏕️UltraEdit"
|
|
|
|
def load_model(self, base_model):
|
|
pipe = StableDiffusion3InstructPix2PixPipeline.from_pretrained(
|
|
base_model,
|
|
torch_dtype=torch.float16,
|
|
).to(device)
|
|
return [pipe]
|
|
|
|
|
|
class UltraEdit_ModelLoader_local_Zho:
|
|
def __init__(self):
|
|
pass
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"base_model": (folder_paths.get_filename_list("ultraedit"), ),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("UEMODEL",)
|
|
RETURN_NAMES = ("pipe",)
|
|
FUNCTION = "load_model"
|
|
CATEGORY = "🏕️UltraEdit"
|
|
|
|
def load_model(self, base_model):
|
|
if not base_model:
|
|
raise ValueError("Please provide the aurasr_model parameter with the name of the model file.")
|
|
|
|
ultraedit_path = folder_paths.get_full_path("ultraedit", base_model)
|
|
print(ultraedit_path)
|
|
|
|
# 获取当前工作目录
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
# 绝对路径加载 text_encoder
|
|
text_encoder_path = os.path.join(current_dir, "../../models/ultraedit/text_encoder")
|
|
text_encoder_2_path = os.path.join(current_dir, "../../models/ultraedit/text_encoder_2")
|
|
text_encoder_3_path = os.path.join(current_dir, "../../models/ultraedit/text_encoder_3")
|
|
|
|
text_encoder = CLIPTextModelWithProjection.from_pretrained(text_encoder_path)
|
|
text_encoder_2 = CLIPTextModelWithProjection.from_pretrained(text_encoder_2_path)
|
|
text_encoder_3 = T5EncoderModel.from_pretrained(text_encoder_3_path)
|
|
|
|
# 绝对路径加载 vae
|
|
vae_path = os.path.join(current_dir, "../../models/ultraedit/vae")
|
|
vae = AutoencoderKL.from_pretrained(vae_path)
|
|
|
|
# 绝对路径加载 transformer
|
|
transformer_path = os.path.join(current_dir, "../../models/ultraedit/transformer")
|
|
transformer = SD3Transformer2DModel.from_pretrained(transformer_path)
|
|
|
|
# 绝对路径加载 tokenizer
|
|
tokenizer_path = os.path.join(current_dir, "../../models/ultraedit/tokenizer")
|
|
tokenizer_2_path = os.path.join(current_dir, "../../models/ultraedit/tokenizer_2")
|
|
tokenizer_3_path = os.path.join(current_dir, "../../models/ultraedit/tokenizer_3")
|
|
|
|
tokenizer = CLIPTokenizer.from_pretrained(tokenizer_path)
|
|
tokenizer_2 = CLIPTokenizer.from_pretrained(tokenizer_2_path)
|
|
tokenizer_3 = T5TokenizerFast.from_pretrained(tokenizer_3_path)
|
|
|
|
# 绝对路径加载 scheduler
|
|
scheduler_path = os.path.join(current_dir, "../../models/ultraedit/scheduler")
|
|
scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(scheduler_path)
|
|
|
|
|
|
pipe = StableDiffusion3InstructPix2PixPipeline.from_single_file(
|
|
ultraedit_path,
|
|
transformer=transformer,
|
|
text_encoder=text_encoder,
|
|
text_encoder_2=text_encoder_2,
|
|
text_encoder_3=text_encoder_3,
|
|
vae=vae,
|
|
tokenizer=tokenizer,
|
|
tokenizer_2=tokenizer_2,
|
|
tokenizer_3=tokenizer_3,
|
|
scheduler=scheduler,
|
|
torch_dtype=torch.float16,
|
|
).to(device)
|
|
return [pipe]
|
|
|
|
|
|
class UltraEdit_Generation_Zho:
|
|
def __init__(self):
|
|
pass
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"pipe": ("UEMODEL",),
|
|
"image": ("IMAGE",),
|
|
"positive": ("STRING", {"default": "cat", "multiline": True}),
|
|
"negative": ("STRING", {"default": "worst quality, low quality", "multiline": True}),
|
|
"steps": ("INT", {"default": 50, "min": 1, "max": 100, "step": 1}),
|
|
"image_guidance_scale": ("FLOAT", {"default": 1.5, "min": 0, "max": 2.5}),
|
|
"text_guidance_scale": ("FLOAT", {"default": 7.5, "min": 0, "max": 12.5}),
|
|
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
|
},
|
|
"optional": {
|
|
"mask": ("IMAGE",),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
FUNCTION = "generate_image"
|
|
CATEGORY = "🏕️UltraEdit"
|
|
|
|
def generate_image(self, pipe, image, positive, negative, steps, seed, image_guidance_scale, text_guidance_scale, mask=None):
|
|
|
|
generator = torch.Generator(device=device).manual_seed(seed)
|
|
|
|
image_t=tensor2pil(image)
|
|
image_resized = resize_to_closest_area(image_t, 512*512)
|
|
|
|
if mask is None:
|
|
mask_t = Image.new("RGB", image_t.size, (255, 255, 255))
|
|
mask_resized = resize_to_closest_area(mask_t, 512*512)
|
|
else:
|
|
mask_t = tensor2pil(mask)
|
|
mask_resized = resize_to_closest_area(mask_t, 512*512)
|
|
|
|
output = pipe(
|
|
prompt=positive,
|
|
negative_prompt=negative,
|
|
image=image_resized,
|
|
mask_img=mask_resized,
|
|
num_inference_steps=steps,
|
|
image_guidance_scale=image_guidance_scale,
|
|
guidance_scale=text_guidance_scale,
|
|
generator=generator,
|
|
)[0]
|
|
|
|
output_t = pil2tensor(output)
|
|
output_t = output_t.squeeze(0)
|
|
print(output_t.shape)
|
|
|
|
return (output_t,)
|
|
|
|
|
|
NODE_CLASS_MAPPINGS = {
|
|
"UltraEdit_ModelLoader_Zho": UltraEdit_ModelLoader_Zho,
|
|
"UltraEdit_ModelLoader_local_Zho": UltraEdit_ModelLoader_local_Zho,
|
|
"UltraEdit_Generation_Zho": UltraEdit_Generation_Zho
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"UltraEdit_ModelLoader_Zho": "🏕️UltraEdit Model(auto) Zho",
|
|
"UltraEdit_ModelLoader_local_Zho": "🏕️UltraEdit Model(local) Zho",
|
|
"UltraEdit_Generation_Zho": "🏕️UltraEdit Generation Zho"
|
|
}
|