3.1 - curves, calculations, prompt building and switches.

This commit is contained in:
Morgan Johansson
2023-09-13 18:52:07 +02:00
parent 84bd74c652
commit 533386aff5
13 changed files with 761 additions and 48 deletions
+10 -3
View File
@@ -5,12 +5,15 @@ from .base import *
from .colors import *
from .curves import *
from .image_processing import *
from .inputfields import *
from .loaders import *
from .noise import *
from .output import *
from .prompting import *
from .seq_processing import *
from .switches import *
from .utility import *
from .inputfields import *
from .calculate import *
_NODE_CLASSES: List[Type] = [DreamSineWave, DreamLinear, DreamCSVCurve, DreamBeatCurve, DreamFrameDimensions,
DreamImageMotion, DreamNoiseFromPalette, DreamAnalyzePalette, DreamColorShift,
@@ -19,12 +22,16 @@ _NODE_CLASSES: List[Type] = [DreamSineWave, DreamLinear, DreamCSVCurve, DreamBea
DreamImageSequenceOutput, DreamCSVGenerator, DreamImageAreaSampler,
DreamVideoEncoder, DreamSequenceTweening, DreamSequenceBlend, DreamColorAlign,
DreamImageSampler, DreamNoiseFromAreaPalettes, DreamVideoEncoderMpegCoder,
DreamInputString, DreamInputFloat, DreamInputInt, DreamInputText]
DreamInputString, DreamInputFloat, DreamInputInt, DreamInputText, DreamBigLatentSwitch,
DreamFrameCountCalculator, DreamBigImageSwitch, DreamBigTextSwitch, DreamBigFloatSwitch,
DreamBigIntSwitch, DreamBigPaletteSwitch, DreamWeightedPromptBuilder, DreamPromptFinalizer,
DreamFrameCounterInfo, DreamBoolToFloat, DreamBoolToInt, DreamSawWave, DreamTriangleWave,
DreamTriangleEvent, DreamSmoothEvent, DreamCalculation]
_SIGNATURE_SUFFIX = " [Dream]"
MANIFEST = {
"name": "Dream Project Animation",
"version": (3, 0, 2),
"version": (3, 1, 0),
"author": "Dream Project",
"project": "https://github.com/alt-key-project/comfyui-dream-project",
"description": "Various utility nodes for creating animations with ComfyUI",
+63 -2
View File
@@ -6,6 +6,37 @@ from .shared import *
from .types import *
class DreamFrameCounterInfo:
NODE_NAME = "Frame Counter Info"
ICON = "⚋"
@classmethod
def INPUT_TYPES(cls):
return {
"required": SharedTypes.frame_counter
}
CATEGORY = NodeCategories.ANIMATION
RETURN_TYPES = ("INT", "INT", "BOOLEAN", "BOOLEAN", "FLOAT", "FLOAT", "FLOAT", "FLOAT")
RETURN_NAMES = ("frames_completed", "total_frames", "first_frame", "last_frame",
"elapsed_seconds", "remaining_seconds", "total_seconds", "completion")
FUNCTION = "result"
@classmethod
def IS_CHANGED(cls, *v):
return ALWAYS_CHANGED_FLAG
def result(self, frame_counter: FrameCounter):
return (frame_counter.current_frame,
frame_counter.total_frames,
frame_counter.is_first_frame,
frame_counter.is_final_frame,
frame_counter.current_time_in_seconds,
frame_counter.remaining_time_in_seconds,
frame_counter.total_time_in_seconds,
frame_counter.current_time_in_seconds / max(0.01, frame_counter.total_time_in_seconds))
class DreamDirectoryFileCount:
NODE_NAME = "File Count"
ICON = "📂"
@@ -35,7 +66,7 @@ class DreamDirectoryFileCount:
for pattern in patterns.split("|"):
files = list(glob.glob(pattern, root_dir=directory_path))
total += len(files)
print("total "+str(total))
print("total " + str(total))
return (total,)
@@ -105,7 +136,7 @@ class DreamDirectoryBackedFrameCounter:
"pattern": ("STRING", {"default": '*', "multiline": False}),
"indexing": (["numeric", "alphabetic order"],),
"total_frames": ("INT", {"default": 100, "min": 2, "max": 24 * 3600 * 60}),
"frames_per_second": ("INT", {"min": 1, "default": 25}),
"frames_per_second": ("INT", {"min": 1, "default": 30}),
},
}
@@ -124,3 +155,33 @@ class DreamDirectoryBackedFrameCounter:
return (FrameCounter(0, total_frames, frames_per_second),)
n = max(results.keys()) + 1
return (FrameCounter(n, total_frames, frames_per_second),)
class DreamFrameCountCalculator:
NODE_NAME = "Frame Count Calculator"
ICON = "⌛"
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"hours": ("INT", {"min": 0, "default": 0, "max": 23}),
"minutes": ("INT", {"min": 0, "default": 0, "max": 59}),
"seconds": ("INT", {"min": 0, "default": 10, "max": 59}),
"milliseconds": ("INT", {"min": 0, "default": 0, "max": 59}),
"frames_per_second": ("INT", {"min": 1, "default": 30})
},
}
CATEGORY = NodeCategories.ANIMATION
RETURN_TYPES = ("INT",)
RETURN_NAMES = ("TOTAL",)
FUNCTION = "result"
@classmethod
def IS_CHANGED(cls, *v):
return ALWAYS_CHANGED_FLAG
def result(self, hours, minutes, seconds, milliseconds, frames_per_second):
total_s = seconds + 0.001 * milliseconds + minutes * 60 + hours * 3600
return (round(total_s * frames_per_second),)
+98
View File
@@ -0,0 +1,98 @@
# -*- coding: utf-8 -*-
import math
from evalidate import Expr, EvalException, base_eval_model
from .categories import *
from .err import on_error
from .shared import hashed_as_strings
class DreamCalculation:
NODE_NAME = "Calculation"
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"expression": ("STRING", {"default": "a + b + c - (r * s * t)", "multiline": True})
},
"optional": {
"a_int": ("INT", {"default": 0, "multiline": False}),
"b_int": ("INT", {"default": 0, "multiline": False}),
"c_int": ("INT", {"default": 0, "multiline": False}),
"r_float": ("FLOAT", {"default": 0.0, "multiline": False}),
"s_float": ("FLOAT", {"default": 0.0, "multiline": False}),
"t_float": ("FLOAT", {"default": 0.0, "multiline": False})
}
}
CATEGORY = NodeCategories.ANIMATION_CURVES
RETURN_TYPES = ("FLOAT", "INT")
RETURN_NAMES = ("FLOAT", "INT")
FUNCTION = "result"
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(*values)
def _make_model(self):
funcs = self._make_functions()
m = base_eval_model.clone()
m.nodes.append('Mult')
m.nodes.append('Call')
for funname in funcs.keys():
m.allowed_functions.append(funname)
return (m, funcs)
def _make_functions(self):
return {
"round": round,
"float": float,
"int": int,
"abs": abs,
"min": min,
"max": max,
"tan": math.tan,
"tanh": math.tanh,
"sin": math.sin,
"sinh": math.sinh,
"cos": math.cos,
"cosh": math.cosh,
"pow": math.pow,
"sqrt": math.sqrt,
"ceil": math.ceil,
"floor": math.floor,
"pi": math.pi,
"log": math.log,
"log2": math.log2,
"acos": math.acos,
"asin": math.asin,
"acosh": math.acosh,
"asinh": math.asinh,
"atan": math.atan,
"atanh": math.atanh,
"exp": math.exp,
"fmod": math.fmod,
"factorial": math.factorial,
"dist": math.dist,
"atan2": math.atan2,
"log10": math.log10
}
def result(self, expression, **values):
model, funcs = self._make_model()
vars = funcs
for key in ("a_int", "b_int", "c_int", "r_float", "s_float", "t_float"):
nm = key.split("_")[0]
v = values.get(key, None)
if v is not None:
vars[nm] = v
try:
data = Expr(expression, model=model).eval(vars)
if isinstance(data, (int, float)):
return float(data), int(round(data))
else:
return 0.0, 0
except EvalException as e:
on_error(DreamCalculation, str(e))
+3 -1
View File
@@ -5,9 +5,11 @@ class NodeCategories:
ANIMATION_POSTPROCESSING = ANIMATION + "/postprocessing"
ANIMATION_TRANSFORMS = ANIMATION + "/transforms"
ANIMATION_CURVES = "animation/curves"
CONDITIONING = "conditioning"
IMAGE_POSTPROCESSING = "image/postprocessing"
IMAGE_ANIMATION = "image/animation"
IMAGE_COLORS = "image/color"
IMAGE_GENERATE = "image/generate"
IMAGE = "image"
UTILS = "utils"
UTILS = "utils"
UTILS_SWITCHES = "utils/switches"
+158 -2
View File
@@ -7,6 +7,20 @@ from .shared import hashed_as_strings
from .types import SharedTypes, FrameCounter
def _linear_value_calc(x, x_start, x_end, y_start, y_end):
if x <= x_start:
return y_start
if x >= x_end:
return y_end
dx = max(x_end - x_start, 0.0001)
n = (x - x_start) / dx
return (y_end - y_start) * n + y_start
def _curve_result(f: float):
return (f, int(round(f)))
class DreamSineWave:
NODE_NAME = "Sine Curve"
@@ -37,7 +51,149 @@ class DreamSineWave:
b = 2 * math.pi / periodicity_seconds
d = (max_value + min_value) / 2
y = a * math.sin(b * (x + c)) + d
return (y, int(round(y)))
return _curve_result(y)
class DreamSawWave:
NODE_NAME = "Saw Curve"
@classmethod
def INPUT_TYPES(cls):
return {
"required": SharedTypes.frame_counter | {
"max_value": ("FLOAT", {"default": 1.0, "multiline": False}),
"min_value": ("FLOAT", {"default": 0.0, "multiline": False}),
"periodicity_seconds": ("FLOAT", {"default": 10.0, "multiline": False, "min": 0.01}),
"phase": ("FLOAT", {"default": 0.0, "multiline": False, "min": -1, "max": 1}),
},
}
CATEGORY = NodeCategories.ANIMATION_CURVES
RETURN_TYPES = ("FLOAT", "INT")
RETURN_NAMES = ("FLOAT", "INT")
FUNCTION = "result"
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(*values)
def result(self, frame_counter: FrameCounter, max_value, min_value, periodicity_seconds, phase):
x = frame_counter.current_time_in_seconds
x = ((x + periodicity_seconds * phase) % periodicity_seconds) / periodicity_seconds
y = x * (max_value - min_value) + min_value
return _curve_result(y)
class DreamTriangleWave:
NODE_NAME = "Triangle Curve"
@classmethod
def INPUT_TYPES(cls):
return {
"required": SharedTypes.frame_counter | {
"max_value": ("FLOAT", {"default": 1.0, "multiline": False}),
"min_value": ("FLOAT", {"default": 0.0, "multiline": False}),
"periodicity_seconds": ("FLOAT", {"default": 10.0, "multiline": False, "min": 0.01}),
"phase": ("FLOAT", {"default": 0.0, "multiline": False, "min": -1, "max": 1}),
},
}
CATEGORY = NodeCategories.ANIMATION_CURVES
RETURN_TYPES = ("FLOAT", "INT")
RETURN_NAMES = ("FLOAT", "INT")
FUNCTION = "result"
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(*values)
def result(self, frame_counter: FrameCounter, max_value, min_value, periodicity_seconds, phase):
x = frame_counter.current_time_in_seconds
x = ((x + periodicity_seconds * phase) % periodicity_seconds) / periodicity_seconds
if x <= 0.5:
x *= 2
y = x * (max_value - min_value) + min_value
else:
x = (x - 0.5) * 2
y = max_value - x * (max_value - min_value)
return _curve_result(y)
class DreamTriangleEvent:
NODE_NAME = "Triangle Event Curve"
@classmethod
def INPUT_TYPES(cls):
return {
"required": SharedTypes.frame_counter | {
"max_value": ("FLOAT", {"default": 1.0, "multiline": False}),
"min_value": ("FLOAT", {"default": 0.0, "multiline": False}),
"width_seconds": ("FLOAT", {"default": 1.0, "multiline": False, "min": 0.1}),
"center_seconds": ("FLOAT", {"default": 10.0, "multiline": False, "min": 0.0}),
},
}
CATEGORY = NodeCategories.ANIMATION_CURVES
RETURN_TYPES = ("FLOAT", "INT")
RETURN_NAMES = ("FLOAT", "INT")
FUNCTION = "result"
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(*values)
def result(self, frame_counter: FrameCounter, max_value, min_value, width_seconds, center_seconds):
x = frame_counter.current_time_in_seconds
start = center_seconds - width_seconds * 0.5
end = center_seconds + width_seconds * 0.5
if start <= x <= center_seconds:
y = _linear_value_calc(x, start, center_seconds, min_value, max_value)
elif center_seconds < x <= end:
y = _linear_value_calc(x, center_seconds, end, max_value, min_value)
else:
y = min_value
return _curve_result(y)
class DreamSmoothEvent:
NODE_NAME = "Smooth Event Curve"
@classmethod
def INPUT_TYPES(cls):
return {
"required": SharedTypes.frame_counter | {
"max_value": ("FLOAT", {"default": 1.0, "multiline": False}),
"min_value": ("FLOAT", {"default": 0.0, "multiline": False}),
"width_seconds": ("FLOAT", {"default": 1.0, "multiline": False, "min": 0.1}),
"center_seconds": ("FLOAT", {"default": 10.0, "multiline": False, "min": 0.0}),
},
}
CATEGORY = NodeCategories.ANIMATION_CURVES
RETURN_TYPES = ("FLOAT", "INT")
RETURN_NAMES = ("FLOAT", "INT")
FUNCTION = "result"
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(*values)
def result(self, frame_counter: FrameCounter, max_value, min_value, width_seconds, center_seconds):
x = frame_counter.current_time_in_seconds
start = center_seconds - width_seconds * 0.5
end = center_seconds + width_seconds * 0.5
if start <= x <= center_seconds:
y = _linear_value_calc(x, start, center_seconds, 0.0, 1.0)
elif center_seconds < x <= end:
y = _linear_value_calc(x, center_seconds, end, 1.0, 0.0)
else:
y = 0.0
if y < 0.5:
y = ((y + y) * (y + y)) * 0.5
else:
a = (y - 0.5) * 2
y = math.pow(a, 0.25) * 0.5 + 0.5
return _curve_result(y * (max_value - min_value) + min_value)
class DreamBeatCurve:
@@ -96,7 +252,7 @@ class DreamBeatCurve:
v = 1.0 - v
r = low_value + v * (high_value - low_value)
return (r, int(round(r)))
return _curve_result(r)
class DreamLinear:
+41
View File
@@ -0,0 +1,41 @@
EMBEDDED_CONFIGURATION = {
"ffmpeg": {
"file_extension": "mp4",
"path": "ffmpeg",
"arguments": ["-r", "%FPS%", "-f", "concat", "-safe", "0", "-vsync",
"cfr", "-i", "%FRAMES%", "-c:v", "libx265", "-pix_fmt",
"yuv420p", "%OUTPUT%"]
},
"mpeg_coder": {
"encoding_threads": 4,
"bitrate_factor": 1.0,
"max_b_frame": 2,
"file_extension": "mp4",
"codec_name": "libx265"
},
"encoding": {
"jpeg_quality": 95
},
"debug": False,
"ui": {
"top_category": "Dream",
"prepend_icon_to_category": True,
"append_icon_to_category": False,
"prepend_icon_to_node": True,
"append_icon_to_node": False,
"category_icons": {
"animation": "🎥",
"postprocessing": "⚙",
"transforms": "🔀",
"curves": "📈",
"color": "🎨",
"generate": "⚡",
"utils": "🛠",
"image": "🌄",
"switches": "⭆",
"conditioning": "☯",
"Dream": "✨"
}
},
}
+18 -1
View File
@@ -1,14 +1,27 @@
{
"Analyze Palette [Dream]": "Output brightness, red, green and blue averages of a palette",
"Beat Curve [Dream]": "Beat pattern curve with impulses at specified beats of a measure",
"Big Float Switch [Dream]": "Switch for up to 10 inputs",
"Big Image Switch [Dream]": "Switch for up to 10 inputs",
"Big Int Switch [Dream]": "Switch for up to 10 inputs",
"Big Latent Switch [Dream]": "Switch for up to 10 inputs",
"Big Palette Switch [Dream]": "Switch for up to 10 inputs",
"Big Text Switch [Dream]": "Switch for up to 10 inputs",
"Boolean To Float [Dream]": "Converts a boolean value to two different float values",
"Boolean To Int [Dream]": "Converts a boolean value to two different int values",
"Build Prompt [Dream]": "Weighted text prompt builder utility",
"CSV Curve [Dream]": "CSV input curve where first column is frame or second and second column is value",
"CSV Generator [Dream]": "CSV output, mainly for debugging purposes",
"Calculation [Dream]": "Mathematical calculation node",
"Common Frame Dimensions [Dream]": "Utility for calculating good width/height based on common video dimensions",
"FFMPEG Video Encoder [Dream]": "Post processing for animation sequences calling FFMPEG to generate video file",
"File Count [Dream]": "Finds the number of files in a directory matching specified patterns",
"Finalize Prompt [Dream]": "Used in conjunction with 'Build Prompt'",
"Float Input [Dream]": "Float input (until primitive routing issues are solved)",
"Frame Count Calculator [Dream]": "Simple utility to calculate number of frames based on duration and framerate",
"Frame Counter (Directory) [Dream]": "Directory backed frame counter, for output directories",
"Frame Counter (Simple) [Dream]": "Integer value used as frame counter",
"Frame Counter Info [Dream]": "Extracts information from the frame counter",
"Frame Counter Offset [Dream]": "Adds an offset to a frame counter",
"Image Motion [Dream]": "Node supporting zooming in/out and translating an image",
"Image Sequence Blend [Dream]": "Post processing for animation sequences blending frame for a smoother blurred effect",
@@ -23,8 +36,12 @@
"Palette Color Shift [Dream]": "Multiplies the color values in a palette",
"Sample Image Area as Palette [Dream]": "Samples a palette from an image based on pre-defined areas",
"Sample Image as Palette [Dream]": "Randomly samples pixel values to build a palette from an image",
"Saw Curve [Dream]": "Saw wave curve",
"Sine Curve [Dream]": "Simple sine wave curve",
"Smooth Event Curve [Dream]": "Single event/peak curve with a slight bell-shape",
"String Input [Dream]": "String input (until primitive routing issues are solved)",
"Text Input [Dream]": "Multiline string input (until primitive routing issues are solved)",
"Triangle Curve [Dream]": "Triangle wave curve",
"Triangle Event Curve [Dream]": "Single event/peak curve with triangular shape",
"Video Encoder (mpegCoder) [Dream]": "Post processing for animation sequences using mpegCoder module to generate video file"
}
} and switches.
+69
View File
@@ -0,0 +1,69 @@
from .categories import NodeCategories
from .shared import hashed_as_strings
from .types import PartialPrompt
class DreamWeightedPromptBuilder:
NODE_NAME = "Build Prompt"
ICON = "⚖"
@classmethod
def INPUT_TYPES(cls):
return {
"optional": {
"partial_prompt": (PartialPrompt.ID,)
},
"required": {
"added_prompt": ("STRING", {"default": "", "multiline": True}),
"weight": ("FLOAT", {"default": 1.0}),
},
}
CATEGORY = NodeCategories.CONDITIONING
RETURN_TYPES = (PartialPrompt.ID,)
RETURN_NAMES = ("partial_prompt",)
FUNCTION = "result"
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(*values)
def result(self, added_prompt, weight, **args):
input = args.get("partial_prompt", PartialPrompt())
p = input.add(added_prompt, weight)
return (p,)
class DreamPromptFinalizer:
NODE_NAME = "Finalize Prompt"
ICON = "🗫"
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"partial_prompt": (PartialPrompt.ID,),
"adjustment": (["raw", "by_abs_max", "by_abs_sum"],),
"clamp": ("FLOAT", {"default": 2.0, "min": 0.1, "step": 0.1}),
"adjustment_reference": ("FLOAT", {"default": 1.0, "min": 0.1}),
},
}
CATEGORY = NodeCategories.CONDITIONING
RETURN_TYPES = ("STRING", "STRING")
RETURN_NAMES = ("positive", "negative")
FUNCTION = "result"
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(*values)
def result(self, partial_prompt: PartialPrompt, adjustment, adjustment_reference, clamp):
if adjustment == "raw" or partial_prompt.is_empty():
return partial_prompt.finalize(clamp)
elif adjustment == "by_abs_sum":
f = adjustment_reference / partial_prompt.abs_sum()
return partial_prompt.scaled_by(f).finalize(clamp)
else:
f = adjustment_reference / partial_prompt.abs_max()
return partial_prompt.scaled_by(f).finalize(clamp)
+32
View File
@@ -133,6 +133,20 @@ Output brightness, red, green and blue averages of a palette. Useful to control
### Beat Curve [Dream]
Beat pattern curve with impulses at specified beats of a measure.
### Big *** Switch [Dream]
Switch nodes for different type for up to ten inputs.
### Boolean To Float/Int [Dream]
Converts a boolean value to two different numeric values.
### Build Prompt [Dream] (and Finalize Prompt [Dream])
Weighted text prompt builder utility. Chain any number of these nodes and terminate with 'Finalize Prompt'.
### Calculation [Dream]
Mathematical calculation node. Exposes most of the mathematical functions in the python
[math module](https://docs.python.org/3/library/math.html), mathematical operators as well as round, abs, int,
float, max and min.
### CSV Curve [Dream]
CSV input curve where first column is frame or second and second column is value.
@@ -152,6 +166,9 @@ Post processing for animation sequences using the python module mpegCoder with f
### File Count [Dream]
Finds the number of files in a directory matching specified patterns.
### Frame Count Calculator [Dream]
Simple utility to calculate number of frames based on time and framerate.
### Frame Counter (Directory) [Dream]
Directory backed frame counter, for output directories.
@@ -159,6 +176,9 @@ Directory backed frame counter, for output directories.
Integer value used as frame counter. Useful for testing or if an auto-incrementing primitive is used as a frame
counter.
### Frame Counter Info [Dream]
Extracts information from the frame counter.
### Frame Counter Offset [Dream]
Adds an offset to a frame counter.
@@ -202,9 +222,21 @@ of equal size and each node may sample one of these.
### Sample Image as Palette [Dream]
Randomly samples pixels from a source image to build a palette from it.
### Saw Curve [Dream]
Saw wave curve.
### Sine Curve [Dream]
Simple sine wave curve.
### Smooth Event Curve [Dream]
Single event/peak curve with a slight bell-shape.
### Triangle Curve [Dream]
Triangle wave curve.
### Triangle Event Curve [Dream]
Single event/peak curve with triangular shape.
### Other custom nodes
Many of the nodes found in 'WAS Node Suite' are useful the Dream Project Animation nodes - I suggest you install those
+1
View File
@@ -4,3 +4,4 @@ scipy
numpy<1.24>=1.18
torchvision
mpegCoder
evalidate
+2 -39
View File
@@ -13,6 +13,7 @@ import torch
from PIL import Image, ImageFilter
from PIL.ImageDraw import ImageDraw
from PIL.PngImagePlugin import PngInfo
from .embedded_config import EMBEDDED_CONFIGURATION
from typing import Dict, Tuple, List
from .dreamlogger import DreamLog
@@ -43,45 +44,7 @@ _config_data = None
class DreamConfig:
FILEPATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.json")
DEFAULT_CONFIG = {
"ffmpeg": {
"file_extension": "mp4",
"path": "ffmpeg",
"arguments": ["-r", "%FPS%", "-f", "concat", "-safe", "0", "-vsync",
"cfr", "-i", "%FRAMES%", "-c:v", "libx265", "-pix_fmt",
"yuv420p", "%OUTPUT%"]
},
"mpeg_coder": {
"encoding_threads": 4,
"bitrate_factor": 1.0,
"max_b_frame": 2,
"file_extension": "mp4",
"codec_name": "libx265"
},
"encoding": {
"jpeg_quality": 95
},
"debug": False,
"ui": {
"top_category": "Dream",
"prepend_icon_to_category": True,
"append_icon_to_category": False,
"prepend_icon_to_node": True,
"append_icon_to_node": False,
"category_icons": {
"animation": "🎥",
"postprocessing": "⚙",
"transforms": "🔀",
"curves": "📈",
"color": "🎨",
"generate": "⚡",
"utils": "🛠",
"image": "🌄",
"Dream": "✨"
}
},
}
DEFAULT_CONFIG = EMBEDDED_CONFIGURATION
def __init__(self):
global _config_data
+212
View File
@@ -0,0 +1,212 @@
from .categories import NodeCategories
from .err import *
from .shared import ALWAYS_CHANGED_FLAG, hashed_as_strings
from .types import RGBPalette
def _generate_switch_input(type: str):
d = dict()
for i in range(10):
d["input_" + str(i)] = (type,)
return {
"required": {
"select": ("INT", {"defualt": 0, "min": 0, "max": 9}),
"on_missing": (["previous", "next"],)
},
"optional": d
}
def _do_pick(cls, select, on_missing, **args):
direction = 1
if on_missing == "previous":
direction = -1
if len(args) == 0:
on_error(cls, "No inputs provided!")
while args.get("input_" + str(select), None) is None:
select = (select + direction) % 10
return args["input_" + str(select)],
class DreamBigImageSwitch:
_switch_type = "IMAGE"
NODE_NAME = "Big Image Switch"
ICON = "⭆"
CATEGORY = NodeCategories.UTILS_SWITCHES
RETURN_TYPES = (_switch_type,)
RETURN_NAMES = ("selected",)
FUNCTION = "pick"
@classmethod
def INPUT_TYPES(cls):
return _generate_switch_input(cls._switch_type)
@classmethod
def IS_CHANGED(cls, *values):
return ALWAYS_CHANGED_FLAG
def pick(self, select, on_missing, **args):
return _do_pick(self.__class__, select, on_missing, **args)
class DreamBigLatentSwitch:
_switch_type = "LATENT"
NODE_NAME = "Big Latent Switch"
ICON = "⭆"
CATEGORY = NodeCategories.UTILS_SWITCHES
RETURN_TYPES = (_switch_type,)
RETURN_NAMES = ("selected",)
FUNCTION = "pick"
@classmethod
def INPUT_TYPES(cls):
return _generate_switch_input(cls._switch_type)
@classmethod
def IS_CHANGED(cls, *values):
return ALWAYS_CHANGED_FLAG
def pick(self, select, on_missing, **args):
return _do_pick(self.__class__, select, on_missing, **args)
class DreamBigTextSwitch:
_switch_type = "STRING"
NODE_NAME = "Big Text Switch"
ICON = "⭆"
CATEGORY = NodeCategories.UTILS_SWITCHES
RETURN_TYPES = (_switch_type,)
RETURN_NAMES = ("selected",)
FUNCTION = "pick"
@classmethod
def INPUT_TYPES(cls):
return _generate_switch_input(cls._switch_type)
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(values)
def pick(self, select, on_missing, **args):
return _do_pick(self.__class__, select, on_missing, **args)
class DreamBigPaletteSwitch:
_switch_type = RGBPalette.ID
NODE_NAME = "Big Palette Switch"
ICON = "⭆"
CATEGORY = NodeCategories.UTILS_SWITCHES
RETURN_TYPES = (_switch_type,)
RETURN_NAMES = ("selected",)
FUNCTION = "pick"
@classmethod
def INPUT_TYPES(cls):
return _generate_switch_input(cls._switch_type)
@classmethod
def IS_CHANGED(cls, *values):
return ALWAYS_CHANGED_FLAG
def pick(self, select, on_missing, **args):
return _do_pick(self.__class__, select, on_missing, **args)
class DreamBigFloatSwitch:
_switch_type = "FLOAT"
NODE_NAME = "Big Float Switch"
ICON = "⭆"
CATEGORY = NodeCategories.UTILS_SWITCHES
RETURN_TYPES = (_switch_type,)
RETURN_NAMES = ("selected",)
FUNCTION = "pick"
@classmethod
def INPUT_TYPES(cls):
return _generate_switch_input(cls._switch_type)
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(values)
def pick(self, select, on_missing, **args):
return _do_pick(self.__class__, select, on_missing, **args)
class DreamBigIntSwitch:
_switch_type = "INT"
NODE_NAME = "Big Int Switch"
ICON = "⭆"
CATEGORY = NodeCategories.UTILS_SWITCHES
RETURN_TYPES = (_switch_type,)
RETURN_NAMES = ("selected",)
FUNCTION = "pick"
@classmethod
def INPUT_TYPES(cls):
return _generate_switch_input(cls._switch_type)
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(values)
def pick(self, select, on_missing, **args):
return _do_pick(self.__class__, select, on_missing, **args)
class DreamBoolToFloat:
NODE_NAME = "Boolean To Float"
ICON = "⬖"
CATEGORY = NodeCategories.UTILS_SWITCHES
RETURN_TYPES = ("FLOAT",)
RETURN_NAMES = ("result",)
FUNCTION = "pick"
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"boolean": ("BOOLEAN", {"default": False}),
"on_true": ("FLOAT", {"default": 1.0}),
"on_false": ("FLOAT", {"default": 0.0})
}
}
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(values)
def pick(self, boolean, on_true, on_false):
if boolean:
return (on_true,)
else:
return (on_false,)
class DreamBoolToInt:
NODE_NAME = "Boolean To Int"
ICON = "⬖"
CATEGORY = NodeCategories.UTILS_SWITCHES
RETURN_TYPES = ("INT",)
RETURN_NAMES = ("result",)
FUNCTION = "pick"
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"boolean": ("BOOLEAN", {"default": False}),
"on_true": ("INT", {"default": 1}),
"on_false": ("INT", {"default": 0})
}
}
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(values)
def pick(self, boolean, on_true, on_false):
if boolean:
return (on_true,)
else:
return (on_false,)
+54
View File
@@ -64,6 +64,52 @@ class RGBPalette:
return _ColorIterator()
class PartialPrompt:
ID = "PARTIAL_PROMPT"
def __init__(self):
self._data = {}
def add(self, text: str, weight: float):
output = PartialPrompt()
output._data = dict(self._data)
output._data[text.strip()] = weight
return output
def is_empty(self):
return not self._data
def abs_sum(self):
if not self._data:
return 0.0
return sum(map(abs, self._data.values()))
def abs_max(self):
if not self._data:
return 0.0
return max(map(abs, self._data.values()))
def scaled_by(self, f: float):
new_data = PartialPrompt()
new_data._data = dict(self._data)
for text, weight in new_data._data.items():
new_data._data[text] = weight * f
return new_data
def finalize(self, clamp: float):
items = self._data.items()
items = sorted(items, key=lambda pair: (pair[1], pair[0]))
pos = list()
neg = list()
for text, w in sorted(items, key=lambda pair: (-pair[1], pair[0])):
if w >= 0.0001:
pos.append("({}:{:.3f})".format(text, min(clamp, w)))
for text, w in sorted(items, key=lambda pair: (pair[1], pair[0])):
if w <= -0.0001:
neg.append("({}:{:.3f})".format(text, min(clamp, -w)))
return ", ".join(pos), ", ".join(neg)
class FrameCounter:
ID = "FRAME_COUNTER"
@@ -91,6 +137,14 @@ class FrameCounter:
def current_time_in_seconds(self):
return float(self.current_frame) / self.frames_per_second
@property
def total_time_in_seconds(self):
return float(self.total_frames) / self.frames_per_second
@property
def remaining_time_in_seconds(self):
return self.total_time_in_seconds - self.current_time_in_seconds
@property
def progress(self):
return float(self.current_frame) / (max(2, self.total_frames) - 1)