New SDXL Power Prompt, Image Inset, Config, and more.
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
"""Display any data node."""
|
||||
import json
|
||||
from .constants import get_category, get_name
|
||||
|
||||
|
||||
class RgthreeDisplayAny:
|
||||
"""Display any data node."""
|
||||
|
||||
NAME = get_name('Display Any')
|
||||
CATEGORY = get_category()
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls): # pylint: disable = invalid-name, missing-function-docstring
|
||||
return {
|
||||
"required": {
|
||||
"source": ("*", {}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ()
|
||||
FUNCTION = "main"
|
||||
OUTPUT_NODE = True
|
||||
|
||||
def main(self, source=None):
|
||||
"""Main."""
|
||||
value = 'None'
|
||||
if source is not None:
|
||||
try:
|
||||
value = json.dumps(source)
|
||||
except Exception:
|
||||
try:
|
||||
value = str(source)
|
||||
except Exception:
|
||||
value = 'source exists, but could not be serialized.'
|
||||
|
||||
return {"ui": {"text": (value,)}}
|
||||
+75
-46
@@ -1,64 +1,93 @@
|
||||
"""Image Inset Crop, with percentages."""
|
||||
from .log import log_node_info
|
||||
from .constants import get_category, get_name
|
||||
from nodes import MAX_RESOLUTION
|
||||
|
||||
|
||||
def getNewBounds(width, height, left, right, top, bottom):
|
||||
left = 0 + left
|
||||
right = width - right
|
||||
top = 0 + top
|
||||
bottom = height - bottom
|
||||
return (left, right, top, bottom)
|
||||
def get_new_bounds(width, height, left, right, top, bottom):
|
||||
"""Returns the new bounds for an image with inset crop data."""
|
||||
left = 0 + left
|
||||
right = width - right
|
||||
top = 0 + top
|
||||
bottom = height - bottom
|
||||
return (left, right, top, bottom)
|
||||
|
||||
|
||||
class RgthreeImageInsetCrop:
|
||||
"""Image Inset Crop, with percentages."""
|
||||
|
||||
NAME = get_name('Image Inset Crop')
|
||||
CATEGORY = get_category()
|
||||
NAME = get_name('Image Inset Crop')
|
||||
CATEGORY = get_category()
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"measurement": (['Pixels', 'Percentage'],),
|
||||
"left": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 8}),
|
||||
"right": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 8}),
|
||||
"top": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 8}),
|
||||
"bottom": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 8}),
|
||||
},
|
||||
}
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls): # pylint: disable = invalid-name, missing-function-docstring
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"measurement": (['Pixels', 'Percentage'],),
|
||||
"left": ("INT", {
|
||||
"default": 0,
|
||||
"min": 0,
|
||||
"max": MAX_RESOLUTION,
|
||||
"step": 8
|
||||
}),
|
||||
"right": ("INT", {
|
||||
"default": 0,
|
||||
"min": 0,
|
||||
"max": MAX_RESOLUTION,
|
||||
"step": 8
|
||||
}),
|
||||
"top": ("INT", {
|
||||
"default": 0,
|
||||
"min": 0,
|
||||
"max": MAX_RESOLUTION,
|
||||
"step": 8
|
||||
}),
|
||||
"bottom": ("INT", {
|
||||
"default": 0,
|
||||
"min": 0,
|
||||
"max": MAX_RESOLUTION,
|
||||
"step": 8
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "crop"
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "crop"
|
||||
|
||||
def crop(self, measurement, left, right, top, bottom, image=None):
|
||||
# pylint: disable = too-many-arguments
|
||||
def crop(self, measurement, left, right, top, bottom, image=None):
|
||||
"""Does the crop."""
|
||||
|
||||
_, height, width, _ = image.shape
|
||||
_, height, width, _ = image.shape
|
||||
|
||||
if measurement == 'Percentage':
|
||||
left = int(width - (width * (100-left) / 100))
|
||||
right = int(width - (width * (100-right) / 100))
|
||||
top = int(height - (height * (100-top) / 100))
|
||||
bottom = int(height - (height * (100-bottom) / 100))
|
||||
if measurement == 'Percentage':
|
||||
left = int(width - (width * (100 - left) / 100))
|
||||
right = int(width - (width * (100 - right) / 100))
|
||||
top = int(height - (height * (100 - top) / 100))
|
||||
bottom = int(height - (height * (100 - bottom) / 100))
|
||||
|
||||
# Snap to 8 pixels
|
||||
left = left // 8 * 8
|
||||
right = right // 8 * 8
|
||||
top = top // 8 * 8
|
||||
bottom = bottom // 8 * 8
|
||||
# Snap to 8 pixels
|
||||
left = left // 8 * 8
|
||||
right = right // 8 * 8
|
||||
top = top // 8 * 8
|
||||
bottom = bottom // 8 * 8
|
||||
|
||||
if left == 0 and right == 0 and bottom == 0 and top == 0:
|
||||
return (image,)
|
||||
if left == 0 and right == 0 and bottom == 0 and top == 0:
|
||||
return (image,)
|
||||
|
||||
inset_left, inset_right, inset_top, inset_bottom = getNewBounds(width, height, left, right, top, bottom)
|
||||
if (inset_top > inset_bottom):
|
||||
raise ValueError(f"Invalid cropping dimensions top ({inset_top}) exceeds bottom ({inset_bottom})")
|
||||
if (inset_left > inset_right):
|
||||
raise ValueError(f"Invalid cropping dimensions left ({inset_left}) exceeds right ({inset_right})")
|
||||
|
||||
log_node_info(self.NAME, f'Cropping image {width}x{height} width inset by {inset_left},{inset_right}, and height inset by {inset_top}, {inset_bottom}')
|
||||
image = image[:, inset_top:inset_bottom, inset_left:inset_right, :]
|
||||
|
||||
return (image,)
|
||||
inset_left, inset_right, inset_top, inset_bottom = get_new_bounds(width, height, left, right,
|
||||
top, bottom)
|
||||
if inset_top > inset_bottom:
|
||||
raise ValueError(
|
||||
f"Invalid cropping dimensions top ({inset_top}) exceeds bottom ({inset_bottom})")
|
||||
if inset_left > inset_right:
|
||||
raise ValueError(
|
||||
f"Invalid cropping dimensions left ({inset_left}) exceeds right ({inset_right})")
|
||||
|
||||
log_node_info(
|
||||
self.NAME, f'Cropping image {width}x{height} width inset by {inset_left},{inset_right}, ' +
|
||||
f'and height inset by {inset_top}, {inset_bottom}')
|
||||
image = image[:, inset_top:inset_bottom, inset_left:inset_right, :]
|
||||
|
||||
return (image,)
|
||||
|
||||
+77
-88
@@ -1,105 +1,94 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
from .log import log_node_warn, log_node_info, log_node_success
|
||||
|
||||
from .constants import get_category, get_name
|
||||
from .power_prompt_utils import get_and_strip_loras
|
||||
from nodes import LoraLoader, CLIPTextEncode
|
||||
import folder_paths
|
||||
|
||||
NODE_NAME=get_name('Power Prompt')
|
||||
|
||||
def get_and_strip_loras(prompt, silent=False):
|
||||
pattern='<lora:([^:>]*?)(?::(-?\d*(?:\.\d*)?))?>'
|
||||
lora_paths=folder_paths.get_filename_list('loras')
|
||||
lora_filenames_no_ext=[os.path.splitext(os.path.basename(x))[0] for x in lora_paths]
|
||||
|
||||
matches = re.findall(pattern, prompt)
|
||||
|
||||
loras=[]
|
||||
for match in matches:
|
||||
tag_filename=match[0]
|
||||
strength=float(match[1] if len(match) > 1 and len(match[1]) else 1.0)
|
||||
if strength == 0 and not silent:
|
||||
log_node_info(NODE_NAME, f'Skipping "{tag_filename}" with strength of zero')
|
||||
continue
|
||||
|
||||
# Let's be flexible. If the lora filename in the tag doesn't have the extension or
|
||||
# path prefix, let's still find and load it.
|
||||
if tag_filename not in lora_paths:
|
||||
found_tag_filename=None
|
||||
for index, value in enumerate(lora_filenames_no_ext):
|
||||
if value in tag_filename:
|
||||
found_tag_filename=lora_paths[index]
|
||||
break
|
||||
if found_tag_filename:
|
||||
# if not silent:
|
||||
# log_node_info(NODE_NAME, f'Found "{found_tag_filename}" for "{tag_filename}" in prompt')
|
||||
tag_filename=found_tag_filename
|
||||
else:
|
||||
if not silent:
|
||||
log_node_warn(NODE_NAME, f'Lora "{tag_filename}" not found, skipping.')
|
||||
continue
|
||||
|
||||
loras.append({'lora':tag_filename, 'strength':strength})
|
||||
|
||||
return (re.sub(pattern, '', prompt), loras)
|
||||
|
||||
NODE_NAME = get_name('Power Prompt')
|
||||
|
||||
|
||||
class RgthreePowerPrompt:
|
||||
|
||||
NAME = NODE_NAME
|
||||
CATEGORY = get_category()
|
||||
NAME = NODE_NAME
|
||||
CATEGORY = get_category()
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls): # pylint: disable = invalid-name, missing-function-docstring
|
||||
SAVED_PROMPTS_FILES=folder_paths.get_filename_list('saved_prompts')
|
||||
SAVED_PROMPTS_CONTENT=[]
|
||||
for filename in SAVED_PROMPTS_FILES:
|
||||
with open(folder_paths.get_full_path('saved_prompts', filename), 'r') as f:
|
||||
SAVED_PROMPTS_CONTENT.append(f.read())
|
||||
return {
|
||||
'required': {
|
||||
'prompt': ('STRING', {'multiline': True}),
|
||||
},
|
||||
'optional': {
|
||||
"opt_model": ("MODEL",),
|
||||
"opt_clip": ("CLIP", ),
|
||||
'insert_lora': (['CHOOSE', 'DISABLE LORAS'] + [os.path.splitext(x)[0] for x in folder_paths.get_filename_list('loras')],),
|
||||
'insert_embedding': (['CHOOSE',] + [os.path.splitext(x)[0] for x in folder_paths.get_filename_list('embeddings')],),
|
||||
'insert_saved': (['CHOOSE',] + SAVED_PROMPTS_FILES,),
|
||||
},
|
||||
'hidden': {
|
||||
'values_insert_saved': (['CHOOSE'] + SAVED_PROMPTS_CONTENT,),
|
||||
}
|
||||
}
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls): # pylint: disable = invalid-name, missing-function-docstring
|
||||
SAVED_PROMPTS_FILES = folder_paths.get_filename_list('saved_prompts')
|
||||
SAVED_PROMPTS_CONTENT = []
|
||||
for filename in SAVED_PROMPTS_FILES:
|
||||
with open(folder_paths.get_full_path('saved_prompts', filename), 'r') as f:
|
||||
SAVED_PROMPTS_CONTENT.append(f.read())
|
||||
return {
|
||||
'required': {
|
||||
'prompt': ('STRING', {
|
||||
'multiline': True
|
||||
}),
|
||||
},
|
||||
'optional': {
|
||||
"opt_model": ("MODEL",),
|
||||
"opt_clip": ("CLIP",),
|
||||
'insert_lora': (['CHOOSE', 'DISABLE LORAS'] +
|
||||
[os.path.splitext(x)[0] for x in folder_paths.get_filename_list('loras')],),
|
||||
'insert_embedding': ([
|
||||
'CHOOSE',
|
||||
] + [os.path.splitext(x)[0] for x in folder_paths.get_filename_list('embeddings')],),
|
||||
'insert_saved': ([
|
||||
'CHOOSE',
|
||||
] + SAVED_PROMPTS_FILES,),
|
||||
},
|
||||
'hidden': {
|
||||
'values_insert_saved': (['CHOOSE'] + SAVED_PROMPTS_CONTENT,),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ('CONDITIONING', 'MODEL', 'CLIP', 'STRING',)
|
||||
RETURN_NAMES = ('CONDITIONING', 'MODEL', 'CLIP', 'TEXT',)
|
||||
FUNCTION = 'main'
|
||||
RETURN_TYPES = (
|
||||
'CONDITIONING',
|
||||
'MODEL',
|
||||
'CLIP',
|
||||
'STRING',
|
||||
)
|
||||
RETURN_NAMES = (
|
||||
'CONDITIONING',
|
||||
'MODEL',
|
||||
'CLIP',
|
||||
'TEXT',
|
||||
)
|
||||
FUNCTION = 'main'
|
||||
|
||||
def main(self, prompt, opt_model=None, opt_clip=None, insert_lora=None, insert_embedding=None, insert_saved=None, values_insert_saved=None):
|
||||
if insert_lora == 'DISABLE LORAS':
|
||||
prompt, loras = get_and_strip_loras(prompt, True)
|
||||
log_node_info(NODE_NAME, f'Disabling all found loras ({len(loras)}) and stripping lora tags for TEXT output.')
|
||||
elif opt_model != None and opt_clip != None:
|
||||
prompt, loras = get_and_strip_loras(prompt)
|
||||
if len(loras):
|
||||
for lora in loras:
|
||||
opt_model, opt_clip = LoraLoader().load_lora(opt_model, opt_clip, lora['lora'], lora['strength'], lora['strength'])
|
||||
log_node_success(NODE_NAME, f'Loaded "{lora["lora"]}" from prompt')
|
||||
log_node_info(NODE_NAME, f'{len(loras)} Loras processed; stripping tags for TEXT output.')
|
||||
elif '<lora:' in prompt:
|
||||
_prompt_stripped, loras = get_and_strip_loras(prompt, True)
|
||||
if len(loras):
|
||||
log_node_warn(NODE_NAME, f'Found {len(loras)} lora tags in prompt but model & clip were not supplied!')
|
||||
log_node_info(NODE_NAME, f'Loras not processed, keeping for TEXT output.')
|
||||
def main(self,
|
||||
prompt,
|
||||
opt_model=None,
|
||||
opt_clip=None,
|
||||
insert_lora=None,
|
||||
insert_embedding=None,
|
||||
insert_saved=None,
|
||||
values_insert_saved=None):
|
||||
if insert_lora == 'DISABLE LORAS':
|
||||
prompt, loras = get_and_strip_loras(prompt, log_node=NODE_NAME, silent=True)
|
||||
log_node_info(
|
||||
NODE_NAME,
|
||||
f'Disabling all found loras ({len(loras)}) and stripping lora tags for TEXT output.')
|
||||
elif opt_model != None and opt_clip != None:
|
||||
prompt, loras = get_and_strip_loras(prompt, log_node=NODE_NAME)
|
||||
if len(loras):
|
||||
for lora in loras:
|
||||
opt_model, opt_clip = LoraLoader().load_lora(opt_model, opt_clip, lora['lora'],
|
||||
lora['strength'], lora['strength'])
|
||||
log_node_success(NODE_NAME, f'Loaded "{lora["lora"]}" from prompt')
|
||||
log_node_info(NODE_NAME, f'{len(loras)} Loras processed; stripping tags for TEXT output.')
|
||||
elif '<lora:' in prompt:
|
||||
_prompt_stripped, loras = get_and_strip_loras(prompt, log_node=NODE_NAME, silent=True)
|
||||
if len(loras):
|
||||
log_node_warn(
|
||||
NODE_NAME, f'Found {len(loras)} lora tags in prompt but model & clip were not supplied!')
|
||||
log_node_info(NODE_NAME, 'Loras not processed, keeping for TEXT output.')
|
||||
|
||||
conditioning=None
|
||||
if opt_clip != None:
|
||||
conditioning = CLIPTextEncode().encode(opt_clip, prompt)[0]
|
||||
|
||||
|
||||
return (conditioning, opt_model, opt_clip, prompt)
|
||||
conditioning = None
|
||||
if opt_clip != None:
|
||||
conditioning = CLIPTextEncode().encode(opt_clip, prompt)[0]
|
||||
|
||||
return (conditioning, opt_model, opt_clip, prompt)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
"""Utilities for Power Prompt nodes."""
|
||||
import re
|
||||
import os
|
||||
import folder_paths
|
||||
|
||||
from .log import log_node_warn, log_node_info
|
||||
|
||||
|
||||
def get_and_strip_loras(prompt, silent=False, log_node="Power Prompt"):
|
||||
"""Collects and strips lora tags from a prompt."""
|
||||
pattern = '<lora:([^:>]*?)(?::(-?\d*(?:\.\d*)?))?>'
|
||||
lora_paths = folder_paths.get_filename_list('loras')
|
||||
lora_filenames_no_ext = [os.path.splitext(os.path.basename(x))[0] for x in lora_paths]
|
||||
|
||||
matches = re.findall(pattern, prompt)
|
||||
|
||||
loras = []
|
||||
for match in matches:
|
||||
tag_filename = match[0]
|
||||
strength = float(match[1] if len(match) > 1 and len(match[1]) else 1.0)
|
||||
if strength == 0 and not silent:
|
||||
log_node_info(log_node, f'Skipping "{tag_filename}" with strength of zero')
|
||||
continue
|
||||
|
||||
# Let's be flexible. If the lora filename in the tag doesn't have the extension or
|
||||
# path prefix, let's still find and load it.
|
||||
if tag_filename not in lora_paths:
|
||||
found_tag_filename = None
|
||||
for index, value in enumerate(lora_filenames_no_ext):
|
||||
if value in tag_filename:
|
||||
found_tag_filename = lora_paths[index]
|
||||
break
|
||||
if found_tag_filename:
|
||||
if not silent:
|
||||
log_node_info(log_node, f'Found "{found_tag_filename}" for "{tag_filename}" in prompt')
|
||||
tag_filename = found_tag_filename
|
||||
else:
|
||||
if not silent:
|
||||
log_node_warn(log_node, f'Lora "{tag_filename}" not found, skipping.')
|
||||
continue
|
||||
|
||||
loras.append({'lora': tag_filename, 'strength': strength})
|
||||
|
||||
return (re.sub(pattern, '', prompt), loras)
|
||||
@@ -0,0 +1,47 @@
|
||||
"""Some basic config stuff I use for SDXL."""
|
||||
|
||||
from .constants import get_category, get_name
|
||||
from nodes import MAX_RESOLUTION
|
||||
import comfy.samplers
|
||||
|
||||
|
||||
class RgthreeSDXLConfig:
|
||||
"""Some basic config stuff I use for SDXL."""
|
||||
|
||||
NAME = get_name('SDXL Config')
|
||||
CATEGORY = get_category()
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls): # pylint: disable = invalid-name, missing-function-docstring
|
||||
return {
|
||||
"required": {
|
||||
"steps_total": ("INT", {
|
||||
"default": 30,
|
||||
"min": 1,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
"refiner_step": ("INT", {
|
||||
"default": 24,
|
||||
"min": 1,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS,),
|
||||
"scheduler": (comfy.samplers.KSampler.SCHEDULERS,),
|
||||
#"refiner_ascore_pos": ("FLOAT", {"default": 6.0, "min": 0.0, "max": 1000.0, "step": 0.01}),
|
||||
#"refiner_ascore_neg": ("FLOAT", {"default": 6.0, "min": 0.0, "max": 1000.0, "step": 0.01}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("INT", "INT", comfy.samplers.KSampler.SAMPLERS,
|
||||
comfy.samplers.KSampler.SCHEDULERS)
|
||||
RETURN_NAMES = ("STEPS", "REFINER_STEP", "SAMPLER", "SCHEDULER")
|
||||
FUNCTION = "main"
|
||||
|
||||
def main(self, steps_total, refiner_step, sampler_name, scheduler):
|
||||
"""main"""
|
||||
return (
|
||||
steps_total,
|
||||
refiner_step,
|
||||
sampler_name,
|
||||
scheduler,
|
||||
)
|
||||
@@ -1,49 +1,63 @@
|
||||
from nodes import EmptyLatentImage
|
||||
from .constants import get_category, get_name
|
||||
|
||||
|
||||
class RgthreeSDXLEmptyLatentImage:
|
||||
|
||||
NAME = get_name('SDXL Empty Latent Image')
|
||||
CATEGORY = get_category()
|
||||
NAME = get_name('SDXL Empty Latent Image')
|
||||
CATEGORY = get_category()
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"dimensions" : ([
|
||||
# 'Custom',
|
||||
'1536 x 640 (landscape)',
|
||||
'1344 x 768 (landscape)',
|
||||
'1216 x 832 (landscape)',
|
||||
'1152 x 896 (landscape)',
|
||||
'1024 x 1024 (square)',
|
||||
' 896 x 1152 (portrait)',
|
||||
' 832 x 1216 (portrait)',
|
||||
' 768 x 1344 (portrait)',
|
||||
' 640 x 1536 (portrait)',
|
||||
], {"default": '1024 x 1024 (square)'}),
|
||||
"clip_scale": ("FLOAT", {"default": 2.0, "min": 1.0, "max": 10.0, "step": .5}),
|
||||
"batch_size": ("INT", {"default": 1, "min": 1, "max": 64}),
|
||||
},
|
||||
"optional": {
|
||||
# "custom_width": ("INT", {"min": 1, "max": MAX_RESOLUTION, "step": 64}),
|
||||
# "custom_height": ("INT", {"min": 1, "max": MAX_RESOLUTION, "step": 64}),
|
||||
}
|
||||
}
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls): # pylint: disable = invalid-name, missing-function-docstring
|
||||
return {
|
||||
"required": {
|
||||
"dimensions": (
|
||||
[
|
||||
# 'Custom',
|
||||
'1536 x 640 (landscape)',
|
||||
'1344 x 768 (landscape)',
|
||||
'1216 x 832 (landscape)',
|
||||
'1152 x 896 (landscape)',
|
||||
'1024 x 1024 (square)',
|
||||
' 896 x 1152 (portrait)',
|
||||
' 832 x 1216 (portrait)',
|
||||
' 768 x 1344 (portrait)',
|
||||
' 640 x 1536 (portrait)',
|
||||
],
|
||||
{
|
||||
"default": '1024 x 1024 (square)'
|
||||
}),
|
||||
"clip_scale": ("FLOAT", {
|
||||
"default": 2.0,
|
||||
"min": 1.0,
|
||||
"max": 10.0,
|
||||
"step": .5
|
||||
}),
|
||||
"batch_size": ("INT", {
|
||||
"default": 1,
|
||||
"min": 1,
|
||||
"max": 64
|
||||
}),
|
||||
},
|
||||
# "optional": {
|
||||
# "custom_width": ("INT", {"min": 1, "max": MAX_RESOLUTION, "step": 64}),
|
||||
# "custom_height": ("INT", {"min": 1, "max": MAX_RESOLUTION, "step": 64}),
|
||||
# }
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("LATENT", "INT", "INT")
|
||||
RETURN_NAMES = ("LATENT", "CLIP_WIDTH", "CLIP_HEIGHT")
|
||||
FUNCTION = "generate"
|
||||
RETURN_TYPES = ("LATENT", "INT", "INT")
|
||||
RETURN_NAMES = ("LATENT", "CLIP_WIDTH", "CLIP_HEIGHT")
|
||||
FUNCTION = "generate"
|
||||
|
||||
# def generate(self, dimensions, clip_scale, batch_size, custom_width=1024, custom_height=1024):
|
||||
def generate(self, dimensions, clip_scale, batch_size):
|
||||
# if dimensions == 'Custom':
|
||||
# width = custom_width
|
||||
# height = custom_height
|
||||
# else:
|
||||
if True:
|
||||
result = [x.strip() for x in dimensions.split('x')]
|
||||
width = int(result[0])
|
||||
height = int(result[1].split(' ')[0])
|
||||
latent = EmptyLatentImage().generate(width, height, batch_size)[0]
|
||||
return (latent, int(width * clip_scale), int(height * clip_scale),)
|
||||
def generate(self, dimensions, clip_scale, batch_size):
|
||||
"""Generates the latent and exposes the clip_width and clip_height"""
|
||||
if True:
|
||||
result = [x.strip() for x in dimensions.split('x')]
|
||||
width = int(result[0])
|
||||
height = int(result[1].split(' ')[0])
|
||||
latent = EmptyLatentImage().generate(width, height, batch_size)[0]
|
||||
return (
|
||||
latent,
|
||||
int(width * clip_scale),
|
||||
int(height * clip_scale),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
import os
|
||||
import re
|
||||
from nodes import MAX_RESOLUTION
|
||||
from comfy_extras.nodes_clip_sdxl import CLIPTextEncodeSDXL, CLIPTextEncodeSDXLRefiner
|
||||
|
||||
from .log import log_node_warn, log_node_info, log_node_success
|
||||
from .constants import get_category, get_name
|
||||
from .power_prompt_utils import get_and_strip_loras
|
||||
from nodes import LoraLoader, CLIPTextEncode
|
||||
import folder_paths
|
||||
|
||||
NODE_NAME = get_name('SDXL Power Prompt - Positive')
|
||||
|
||||
|
||||
class RgthreeSDXLPowerPromptPositive:
|
||||
"""The Power Prompt for positive conditioning."""
|
||||
|
||||
NAME = NODE_NAME
|
||||
CATEGORY = get_category()
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls): # pylint: disable = invalid-name, missing-function-docstring
|
||||
SAVED_PROMPTS_FILES = folder_paths.get_filename_list('saved_prompts')
|
||||
SAVED_PROMPTS_CONTENT = []
|
||||
for filename in SAVED_PROMPTS_FILES:
|
||||
with open(folder_paths.get_full_path('saved_prompts', filename), 'r') as f:
|
||||
SAVED_PROMPTS_CONTENT.append(f.read())
|
||||
return {
|
||||
'required': {
|
||||
'prompt_g': ('STRING', {
|
||||
'multiline': True
|
||||
}),
|
||||
'prompt_l': ('STRING', {
|
||||
'multiline': True
|
||||
}),
|
||||
},
|
||||
'optional': {
|
||||
"opt_model": ("MODEL",),
|
||||
"opt_clip": ("CLIP",),
|
||||
"opt_clip_width": ("INT", {
|
||||
"forceInput": True,
|
||||
"default": 1024.0,
|
||||
"min": 0,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
"opt_clip_height": ("INT", {
|
||||
"forceInput": True,
|
||||
"default": 1024.0,
|
||||
"min": 0,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
'insert_lora': (['CHOOSE', 'DISABLE LORAS'] +
|
||||
[os.path.splitext(x)[0] for x in folder_paths.get_filename_list('loras')],),
|
||||
'insert_embedding': ([
|
||||
'CHOOSE',
|
||||
] + [os.path.splitext(x)[0] for x in folder_paths.get_filename_list('embeddings')],),
|
||||
'insert_saved': ([
|
||||
'CHOOSE',
|
||||
] + SAVED_PROMPTS_FILES,),
|
||||
# We'll hide these in the UI for now.
|
||||
"target_width": ("INT", {
|
||||
"default": -1,
|
||||
"min": -1,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
"target_height": ("INT", {
|
||||
"default": -1,
|
||||
"min": -1,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
"crop_width": ("INT", {
|
||||
"default": -1,
|
||||
"min": -1,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
"crop_height": ("INT", {
|
||||
"default": -1,
|
||||
"min": -1,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
},
|
||||
'hidden': {
|
||||
'values_insert_saved': (['CHOOSE'] + SAVED_PROMPTS_CONTENT,),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ('CONDITIONING', 'MODEL', 'CLIP', 'STRING', 'STRING')
|
||||
RETURN_NAMES = ('CONDITIONING', 'MODEL', 'CLIP', 'TEXT_G', 'TEXT_L')
|
||||
FUNCTION = 'main'
|
||||
|
||||
def main(self,
|
||||
prompt_g,
|
||||
prompt_l,
|
||||
opt_model=None,
|
||||
opt_clip=None,
|
||||
opt_clip_width=None,
|
||||
opt_clip_height=None,
|
||||
insert_lora=None,
|
||||
insert_embedding=None,
|
||||
insert_saved=None,
|
||||
target_width=-1,
|
||||
target_height=-1,
|
||||
crop_width=-1,
|
||||
crop_height=-1,
|
||||
values_insert_saved=None):
|
||||
if insert_lora == 'DISABLE LORAS':
|
||||
prompt_g, loras_g = get_and_strip_loras(prompt_g, True)
|
||||
prompt_l, loras_l = get_and_strip_loras(prompt_l, True)
|
||||
loras = loras_g + loras_l
|
||||
log_node_info(
|
||||
NODE_NAME,
|
||||
f'Disabling all found loras ({len(loras)}) and stripping lora tags for TEXT output.')
|
||||
elif opt_model != None and opt_clip != None:
|
||||
prompt_g, loras_g = get_and_strip_loras(prompt_g)
|
||||
prompt_l, loras_l = get_and_strip_loras(prompt_l)
|
||||
loras = loras_g + loras_l
|
||||
if len(loras):
|
||||
for lora in loras:
|
||||
opt_model, opt_clip = LoraLoader().load_lora(opt_model, opt_clip, lora['lora'],
|
||||
lora['strength'], lora['strength'])
|
||||
log_node_success(NODE_NAME, f'Loaded "{lora["lora"]}" from prompt')
|
||||
log_node_info(NODE_NAME, f'{len(loras)} Loras processed; stripping tags for TEXT output.')
|
||||
elif '<lora:' in prompt_g or '<lora:' in prompt_l:
|
||||
_prompt_stripped_g, loras_g = get_and_strip_loras(prompt_g, True)
|
||||
_prompt_stripped_l, loras_l = get_and_strip_loras(prompt_l, True)
|
||||
loras = loras_g + loras_l
|
||||
if len(loras):
|
||||
log_node_warn(
|
||||
NODE_NAME, f'Found {len(loras)} lora tags in prompt but model & clip were not supplied!')
|
||||
log_node_info(NODE_NAME, 'Loras not processed, keeping for TEXT output.')
|
||||
|
||||
conditioning_base = None
|
||||
if opt_clip_width and opt_clip_height:
|
||||
target_width = target_width if target_width and target_width > 0 else opt_clip_width
|
||||
target_height = target_height if target_height and target_height > 0 else opt_clip_height
|
||||
crop_width = crop_width if crop_width and crop_width > 0 else 0
|
||||
crop_height = crop_height if crop_height and crop_height > 0 else 0
|
||||
if opt_clip:
|
||||
conditioning_base = CLIPTextEncodeSDXL().encode(opt_clip, opt_clip_width, opt_clip_height,
|
||||
crop_width, crop_height, target_width,
|
||||
target_height, prompt_g, prompt_l)[0]
|
||||
|
||||
return (conditioning_base, opt_model, opt_clip, prompt_g, prompt_l)
|
||||
@@ -0,0 +1,113 @@
|
||||
"""A simpler SDXL Power Prompt that doesn't load Loras, like for negative."""
|
||||
import os
|
||||
import re
|
||||
import folder_paths
|
||||
from nodes import MAX_RESOLUTION, LoraLoader
|
||||
from comfy_extras.nodes_clip_sdxl import CLIPTextEncodeSDXL
|
||||
|
||||
from .log import log_node_warn, log_node_info, log_node_success
|
||||
|
||||
from .constants import get_category, get_name
|
||||
|
||||
NODE_NAME = get_name('SDXL Power Prompt - Simple / Negative')
|
||||
|
||||
|
||||
class RgthreeSDXLPowerPromptSimple:
|
||||
"""A simpler SDXL Power Prompt that doesn't handle Loras."""
|
||||
|
||||
NAME = NODE_NAME
|
||||
CATEGORY = get_category()
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls): # pylint: disable = invalid-name, missing-function-docstring
|
||||
saved_prompts_files = folder_paths.get_filename_list('saved_prompts')
|
||||
saved_promptes_content = []
|
||||
for fname in saved_prompts_files:
|
||||
with open(folder_paths.get_full_path('saved_prompts', fname), 'r', encoding="utf-8") as file:
|
||||
saved_promptes_content.append(file.read())
|
||||
|
||||
return {
|
||||
'required': {
|
||||
'prompt_g': ('STRING', {
|
||||
'multiline': True
|
||||
}),
|
||||
'prompt_l': ('STRING', {
|
||||
'multiline': True
|
||||
}),
|
||||
},
|
||||
'optional': {
|
||||
"opt_clip": ("CLIP",),
|
||||
"opt_clip_width": ("INT", {
|
||||
"forceInput": True,
|
||||
"default": 1024.0,
|
||||
"min": 0,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
"opt_clip_height": ("INT", {
|
||||
"forceInput": True,
|
||||
"default": 1024.0,
|
||||
"min": 0,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
'insert_embedding': ([
|
||||
'CHOOSE',
|
||||
] + [os.path.splitext(x)[0] for x in folder_paths.get_filename_list('embeddings')],),
|
||||
'insert_saved': ([
|
||||
'CHOOSE',
|
||||
] + saved_prompts_files,),
|
||||
# We'll hide these in the UI for now.
|
||||
"target_width": ("INT", {
|
||||
"default": -1,
|
||||
"min": -1,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
"target_height": ("INT", {
|
||||
"default": -1,
|
||||
"min": -1,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
"crop_width": ("INT", {
|
||||
"default": -1,
|
||||
"min": -1,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
"crop_height": ("INT", {
|
||||
"default": -1,
|
||||
"min": -1,
|
||||
"max": MAX_RESOLUTION
|
||||
}),
|
||||
},
|
||||
'hidden': {
|
||||
'values_insert_saved': (['CHOOSE'] + saved_promptes_content,),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ('CONDITIONING', 'STRING', 'STRING')
|
||||
RETURN_NAMES = ('CONDITIONING', 'TEXT_G', 'TEXT_L')
|
||||
FUNCTION = 'main'
|
||||
|
||||
def main(self,
|
||||
prompt_g,
|
||||
prompt_l,
|
||||
opt_clip=None,
|
||||
opt_clip_width=None,
|
||||
opt_clip_height=None,
|
||||
insert_embedding=None,
|
||||
insert_saved=None,
|
||||
target_width=-1,
|
||||
target_height=-1,
|
||||
crop_width=-1,
|
||||
crop_height=-1,
|
||||
values_insert_saved=None):
|
||||
conditioning_base = None
|
||||
if opt_clip_width and opt_clip_height:
|
||||
target_width = target_width if target_width and target_width > 0 else opt_clip_width
|
||||
target_height = target_height if target_height and target_height > 0 else opt_clip_height
|
||||
crop_width = crop_width if crop_width and crop_width > 0 else 0
|
||||
crop_height = crop_height if crop_height and crop_height > 0 else 0
|
||||
if opt_clip:
|
||||
conditioning_base = CLIPTextEncodeSDXL().encode(opt_clip, opt_clip_width, opt_clip_height,
|
||||
crop_width, crop_height, target_width,
|
||||
target_height, prompt_g, prompt_l)[0]
|
||||
|
||||
return (conditioning_base, prompt_g, prompt_l)
|
||||
Reference in New Issue
Block a user