fixed factorial
added fill array mode for op unary
This commit is contained in:
Alexander G. Morano
2025-05-04 03:32:02 -04:00
parent 558693fc8f
commit d8badc5320
16 changed files with 115 additions and 52 deletions
+37 -37
View File
@@ -160,7 +160,7 @@ OP_UNARY = {
EnumUnaryOperation.TAN: lambda x: math.tan(x),
EnumUnaryOperation.NEGATE: lambda x: -x,
EnumUnaryOperation.RECIPROCAL: lambda x: 1 / x if x != 0 else 0,
EnumUnaryOperation.FACTORIAL: lambda x: math.factorial(math.abs(int(x))),
EnumUnaryOperation.FACTORIAL: lambda x: math.factorial(abs(int(x))),
EnumUnaryOperation.EXP: lambda x: math.exp(x),
EnumUnaryOperation.NOT: lambda x: not x,
EnumUnaryOperation.BIT_NOT: lambda x: ~int(x),
@@ -216,6 +216,7 @@ class BitSplitNode(CozyBaseNode):
CATEGORY = JOV_CATEGORY
RETURN_TYPES = (COZY_TYPE_ANY, "BOOLEAN",)
RETURN_NAMES = ("BIT", "BOOL",)
OUTPUT_IS_LIST = (True, True,)
OUTPUT_TOOLTIPS = (
"Bits as Numerical output (0 or 1)",
"Bits as Boolean output (True or False)"
@@ -272,6 +273,7 @@ class ComparisonNode(CozyBaseNode):
CATEGORY = JOV_CATEGORY
RETURN_TYPES = (COZY_TYPE_ANY, COZY_TYPE_ANY,)
RETURN_NAMES = ("OUT", "VAL",)
OUTPUT_IS_LIST = (True, True,)
OUTPUT_TOOLTIPS = (
"Outputs the input at PASS or FAIL depending the evaluation",
"The comparison result value"
@@ -405,6 +407,7 @@ class LerpNode(CozyBaseNode):
CATEGORY = JOV_CATEGORY
RETURN_TYPES = (COZY_TYPE_ANY,)
RETURN_NAMES = ("🦄",)
OUTPUT_IS_LIST = (True,)
OUTPUT_TOOLTIPS = (
f"Output can vary depending on the type chosen in the {"TYPE"} parameter"
)
@@ -510,6 +513,7 @@ class OPUnaryNode(CozyBaseNode):
CATEGORY = JOV_CATEGORY
RETURN_TYPES = (COZY_TYPE_ANY,)
RETURN_NAMES = ("❔",)
OUTPUT_IS_LIST = (True,)
OUTPUT_TOOLTIPS = (
"Output type will match the input type"
)
@@ -521,12 +525,19 @@ Perform single function operations like absolute value, mean, median, mode, magn
@classmethod
def INPUT_TYPES(cls) -> InputType:
d = super().INPUT_TYPES()
typ = EnumConvertType._member_names_[:6]
d = deep_merge(d, {
"optional": {
"A": (COZY_TYPE_NUMERICAL, {
"default": None}),
"FUNCTION": (EnumUnaryOperation._member_names_, {
"default": EnumUnaryOperation.ABS.name})
"default": EnumUnaryOperation.ABS.name}),
"TYPE": (typ, {
"default": EnumConvertType.FLOAT.name,
"tooltip":"Take the input and convert it into the selected type"}),
"FILL": ("BOOLEAN", {
"default": False,
"tooltip":"If the value should fill the output type (VEC*)"}),
}
})
return d
@@ -535,24 +546,16 @@ Perform single function operations like absolute value, mean, median, mode, magn
results = []
A = parse_param(kw, "A", EnumConvertType.ANY, 0)
op = parse_param(kw, "FUNCTION", EnumUnaryOperation, EnumUnaryOperation.ABS.name)
params = list(zip_longest_fill(A, op))
out = parse_param(kw, "TYPE", EnumConvertType, EnumConvertType.FLOAT.name)
fill = parse_param(kw, "FILL", EnumConvertType.BOOLEAN, False)
params = list(zip_longest_fill(A, op, out, fill))
pbar = ProgressBar(len(params))
for idx, (A, op) in enumerate(params):
typ = EnumConvertType.ANY
if isinstance(A, (str, )):
typ = EnumConvertType.STRING
elif isinstance(A, (bool, )):
for idx, (A, op, out, fill) in enumerate(params):
typ = EnumConvertType.FLOAT
if isinstance(A, (bool, )):
typ = EnumConvertType.BOOLEAN
elif isinstance(A, (int, )):
typ = EnumConvertType.INT
elif isinstance(A, (float, )):
typ = EnumConvertType.FLOAT
elif isinstance(A, (list, set, tuple,)):
typ = EnumConvertType(len(A) * 10)
elif isinstance(A, (dict,)):
typ = EnumConvertType.DICT
elif isinstance(A, (TensorType,)):
typ = EnumConvertType.IMAGE
val = parse_value(A, typ, 0)
if not isinstance(val, (list, tuple, )):
@@ -593,17 +596,11 @@ Perform single function operations like absolute value, mean, median, mode, magn
ret.append(v)
val = ret
convert = int if isinstance(A, (bool, int, np.uint8, np.uint16, np.uint32, np.uint64)) else float
ret = []
for v in val:
try:
ret.append(convert(v))
except OverflowError:
ret.append(0)
except Exception as e:
logger.error(f"{e} :: {op}")
ret.append(0)
val = parse_value(val, typ, 0)
if fill:
while len(val) < 4:
val.append(val[-1])
val = parse_value(val, out, 0)
results.append(val)
pbar.update_absolute(idx)
return (results,)
@@ -613,6 +610,7 @@ class OPBinaryNode(CozyBaseNode):
CATEGORY = JOV_CATEGORY
RETURN_TYPES = (COZY_TYPE_ANY,)
RETURN_NAMES = ("❔",)
OUTPUT_IS_LIST = (True,)
OUTPUT_TOOLTIPS = (
"Output type will match the input type"
)
@@ -768,6 +766,7 @@ class StringerNode(CozyBaseNode):
CATEGORY = JOV_CATEGORY
RETURN_TYPES = ("STRING", "INT",)
RETURN_NAMES = ("STRING", "COUNT",)
OUTPUT_IS_LIST = (True, False,)
SORT = 44
DESCRIPTION = """
Manipulate strings through filtering
@@ -788,7 +787,7 @@ Manipulate strings through filtering
"REPLACE": ("STRING", {
"default":"", "dynamicPrompt":False}),
"RANGE": ("VEC3", {
"default":(0, -1, 1),
"default":(0, -1, 1), "int": True,
"tooltip":"Start, End and Step. Values will clip to the actual list size(s)."}),
}
})
@@ -796,23 +795,25 @@ Manipulate strings through filtering
def run(self, **kw) -> tuple[TensorType, ...]:
# turn any all inputs into the
data_list = parse_dynamic(kw, "❔", EnumConvertType.ANY, "")
data_list = parse_dynamic(kw, "STRING", EnumConvertType.ANY, "")
if data_list is None:
logger.warn("no data for list")
return ([],)
# flat list of ALL the dynamic inputs...
#data_list = flatten(data_list)
# single operation mode -- like array node
return ([], 0)
op = parse_param(kw, "FUNCTION", EnumConvertString, EnumConvertString.SPLIT.name)[0]
key = parse_param(kw, "KEY", EnumConvertType.STRING, "")[0]
replace = parse_param(kw, "REPLACE", EnumConvertType.STRING, "")[0]
stenst = parse_param(kw, "RANGE", EnumConvertType.VEC3INT, (0, -1, 1))[0]
results = []
print(data_list)
match op:
case EnumConvertString.SPLIT:
results = data_list
if key != "":
results = [r.split(key) for r in data_list]
results = []
for d in data_list:
d = [key if len(r) == 0 else r for r in d.split(key)]
results.extend(d)
case EnumConvertString.JOIN:
results = [key.join(data_list)]
case EnumConvertString.FIND:
@@ -830,15 +831,14 @@ Manipulate strings through filtering
results.append(x[start:end:step])
else:
results.append(x)
if len(results) == 0:
results = [""]
return (results, [len(r) for r in results],) if len(results) > 1 else (results[0], len(results[0]),)
return (results, len(results),)
class SwizzleNode(CozyBaseNode):
NAME = "SWIZZLE (JOV) 😵"
CATEGORY = JOV_CATEGORY
RETURN_TYPES = (COZY_TYPE_ANY,)
RETURN_NAMES = ("🦄",)
OUTPUT_IS_LIST = (True,)
SORT = 40
DESCRIPTION = """
Swap components between two vectors based on specified swizzle patterns and values. It provides flexibility in rearranging vector elements dynamically.
-2
View File
@@ -33,9 +33,7 @@ Supplies raw or default values for various data types, supporting vector input w
@classmethod
def INPUT_TYPES(cls) -> InputType:
d = super().INPUT_TYPES()
typ = EnumConvertType._member_names_[:6]
d = deep_merge(d, {
"optional": {
"A": (COZY_TYPE_ANY, {
+1 -1
View File
@@ -2,7 +2,7 @@
import { app } from "../../../scripts/app.js"
import { ComfyWidgets } from '../../../scripts/widgets.js';
import { nodeAddDynamic } from '../util.js'
import { nodeAddDynamic } from "../util.js"
const _prefix = '📥'
const _id = "AKASHIC (JOV) 📓"
+1 -1
View File
@@ -5,7 +5,7 @@
*/
import { app } from "../../../scripts/app.js"
import { nodeAddDynamic } from '../util.js'
import { nodeAddDynamic } from "../util.js"
const _id = "ARRAY (JOV) 📚"
const _prefix = '❔'
+1 -1
View File
@@ -1,7 +1,7 @@
/**/
import { app } from "../../../scripts/app.js"
import { widgetHookAB } from '../util.js'
import { widgetHookAB } from "../util.js"
const _id = "OP BINARY (JOV) 🌟"
+1 -1
View File
@@ -2,7 +2,7 @@
import { api } from "../../../scripts/api.js";
import { app } from "../../../scripts/app.js";
import { apiJovimetrix } from '../util.js'
import { apiJovimetrix } from "../util.js"
import { bubbles } from '../fun.js'
const _id = "DELAY (JOV) ✋🏽"
+1 -2
View File
@@ -1,7 +1,7 @@
/**/
import { app } from "../../../scripts/app.js"
import { nodeAddDynamic } from '../util.js'
import { nodeAddDynamic } from "../util.js"
const _id = "FLATTEN (JOV) ⬇️"
const _prefix = 'IMAGE'
@@ -14,6 +14,5 @@ app.registerExtension({
}
nodeAddDynamic(nodeType, _prefix);
}
})
+1 -1
View File
@@ -1,7 +1,7 @@
/**/
import { app } from "../../../scripts/app.js"
import { apiJovimetrix, nodeAddDynamic } from '../util.js'
import { apiJovimetrix, nodeAddDynamic } from "../util.js"
const _id = "GRAPH (JOV) 📈"
const _prefix = '❔'
+1 -1
View File
@@ -1,7 +1,7 @@
/**/
import { app } from "../../../scripts/app.js"
import { widgetHookControl, widgetHookAB } from '../util.js'
import { widgetHookControl, widgetHookAB } from "../util.js"
const _id = "LERP (JOV) 🔰"
+48
View File
@@ -0,0 +1,48 @@
/**/
import { app } from "../../../scripts/app.js"
import { TypeSlotEvent, TypeSlot, nodeFitHeight } from "../util.js"
const _id = "OP UNARY (JOV) 🎲"
app.registerExtension({
name: 'jovimetrix.node.' + _id,
async beforeRegisterNodeDef(nodeType, nodeData) {
if (nodeData.name !== _id) {
return;
}
const onConnectionsChange = nodeType.prototype.onConnectionsChange
nodeType.prototype.onConnectionsChange = function (slotType, slot_idx, event, link_info, node_slot) {
const me = onConnectionsChange?.apply(this, arguments);
let connected = false;
const output = this.outputs[0];
if (slotType == TypeSlot.Input && link_info && event == TypeSlotEvent.Connect) {
const fromNode = this.graph._nodes.find(
(otherNode) => otherNode.id == link_info.origin_id
)
if (fromNode) {
const parent_link = fromNode.outputs[link_info.origin_slot];
if (parent_link) {
output.type = parent_link.type;
//output.name = parent_link.name;
//output.localized_name = parent_link.localized_name;
connected = true;
}
}
}
if (connected == false) {
output.type = "*";
//output.name = "❔";
//output.localized_name = "❔";
}
nodeFitHeight(this);
return me;
}
return nodeType;
}
})
+1 -1
View File
@@ -3,7 +3,7 @@
import { api } from "../../../scripts/api.js";
import { app } from "../../../scripts/app.js";
import { ComfyWidgets } from '../../../scripts/widgets.js';
import { apiJovimetrix, TypeSlotEvent, TypeSlot } from '../util.js'
import { apiJovimetrix, TypeSlotEvent, TypeSlot } from "../util.js"
import { flashBackgroundColor } from '../fun.js'
const _id1 = "QUEUE (JOV) 🗃";
+1 -1
View File
@@ -4,7 +4,7 @@ import { app } from "../../../scripts/app.js"
import {
TypeSlot, TypeSlotEvent, nodeFitHeight,
nodeVirtualLinkRoot, nodeInputsClear, nodeOutputsClear
} from '../util.js'
} from "../util.js"
const _id = "ROUTE (JOV) 🚌";
const _prefix = '🔮';
+1 -1
View File
@@ -1,7 +1,7 @@
/**/
import { app } from "../../../scripts/app.js"
import { nodeAddDynamic} from '../util.js'
import { nodeAddDynamic} from "../util.js"
const _id = "STACK (JOV) ➕"
const _prefix = 'IMAGE'
+18
View File
@@ -0,0 +1,18 @@
/**/
import { app } from "../../../scripts/app.js"
import { nodeAddDynamic } from "../util.js"
const _id = "STRINGER (JOV) 🪀"
const _prefix = 'STRING'
app.registerExtension({
name: 'jovimetrix.node.' + _id,
async beforeRegisterNodeDef(nodeType, nodeData) {
if (nodeData.name !== _id) {
return;
}
nodeAddDynamic(nodeType, _prefix);
}
})
+1 -1
View File
@@ -2,7 +2,7 @@
import { api } from "../../../scripts/api.js";
import { app } from "../../../scripts/app.js"
import { apiJovimetrix } from '../util.js'
import { apiJovimetrix } from "../util.js"
const _id = "TICK (JOV) ⏱";
const EVENT_JOVI_TICK = "jovi-tick";
+1 -1
View File
@@ -1,7 +1,7 @@
/**/
import { app } from "../../../scripts/app.js"
import { widgetHookAB, nodeFitHeight} from '../util.js'
import { widgetHookAB, nodeFitHeight} from "../util.js"
const _id = "VALUE (JOV) 🧬"