create range and cast nodes

This commit is contained in:
godmt
2024-09-24 18:34:56 +09:00
parent 294d80eed1
commit 2f8a36f025
3 changed files with 463 additions and 210 deletions
+177 -25
View File
@@ -1,20 +1,20 @@
// https://gist.github.com/Amorano/9871fb3be1aa75defdfad013e1f95e0e
import { app } from "../../scripts/app.js";
// import { api } from "../../scripts/api.js";
import { ComfyWidgets } from "../../scripts/widgets.js";
// import { addConnectionLayoutSupport } from "./utils.js";
import { app } from "../../scripts/app.js"
// import { api } from "../../scripts/api.js"
import { ComfyWidgets } from "../../scripts/widgets.js"
// import { addConnectionLayoutSupport } from "./utils.js"
const _prefix = 'value';
const _prefix = 'value'
const TypeSlot = {
Input: 1,
Output: 2,
};
}
const TypeSlotEvent = {
Connect: true,
Disconnect: false,
};
}
const dynamic_connection = (node, index, event, prefix = 'in_', type = '*', names = []
) => {
@@ -51,11 +51,29 @@ const dynamic_connection = (node, index, event, prefix = 'in_', type = '*', name
}
}
/**
* Get all unique types in the workflow.
* @returns {Set} Unique set of all types used in the workflow
*/
function getWorkflowTypes(app) {
// 実装
const types = new Set(["*", "STRING", "INT", "FLOAT", "IMAGE", "LATENT", "MASK", "NOISE", "SAMPLER", "SIGMAS", "GUIDER", "MODEL", "CLIP", "VAE", "CONDITIONING"])
app.graph._nodes.forEach(node => {
node.inputs.forEach(slot => {
types.add(slot.type)
})
node.outputs.forEach(slot => {
types.add(slot.type)
})
})
return Array.from(types)
}
app.registerExtension({
name: "godmt.ListUtils",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "GODMT_Pack" || nodeData.name === "GODMT_CreateList" || nodeData.name == "GODMT_CreateBatch") {
if (nodeData.name === "GODMT_Pack" || nodeData.name == "GODMT_CreateBatch") {
const onNodeCreated = nodeType.prototype.onNodeCreated
nodeType.prototype.onNodeCreated = function () {
const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined
@@ -93,13 +111,80 @@ app.registerExtension({
this.inputs[slot].label = `${_prefix}_${slot + 1}`
}
}
return me;
return me
}
} else if (nodeData.name === "GODMT_CreateStringList") {
} else if (nodeData.name === "GODMT_CreateList" || nodeData.name === "GODMT_MergeList") {
const onNodeCreated = nodeType.prototype.onNodeCreated
nodeType.prototype.onNodeCreated = function () {
const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined
this.addInput(`${_prefix}_1`, 'STRING')
this.addInput(`${_prefix}_1`, '*')
return r
}
// TODO might be buggy on load
// on copy, paste, load
const onConfigure = nodeType.prototype.onConfigure
nodeType.prototype.onConfigure = function () {
const r = onConfigure ? onConfigure.apply(this, arguments) : undefined
if (!app.configuringGraph && this.inputs) {
const length = this.inputs.length
for (let i = length - 1; i >= 0; i--) {
this.removeInput(i)
}
this.addInput(`${_prefix}_1`, '*')
}
return r
}
const onConnectionsChange = nodeType.prototype.onConnectionsChange
nodeType.prototype.onConnectionsChange = function (slotType, slot, event, link_info, data) {
const me = onConnectionsChange ? onConnectionsChange.apply(this, arguments) : undefined
if (slotType === TypeSlot.Input) {
if (!this.inputs[slot].name.startsWith(_prefix)) {
return
}
if (event == TypeSlotEvent.Connect && link_info) {
if (slot == 0) {
const node = app.graph.getNodeById(link_info.origin_id)
const origin_type = node.outputs[link_info.origin_slot].type
this.inputs[0].type = origin_type
this.outputs[0].type = origin_type
this.outputs[0].label = origin_type
this.outputs[0].name = origin_type
}
}
// remove all non connected inputs
if (event == TypeSlotEvent.Disconnect && this.inputs.length > 0) {
if (this.widgets) {
const widget = this.widgets.find((w) => w.name === this.inputs[slot].name)
if (widget) {
widget.onRemoved?.()
this.widgets.length = this.widgets.length - 1
}
}
this.removeInput(slot)
// make inputs sequential again
for (let i = 0; i < this.inputs.length; i++) {
this.inputs[i].label = `${_prefix}_${i + 1}`
this.inputs[i].name = `${_prefix}_${i + 1}`
}
}
// add an extra input
if (this.inputs[this.inputs.length - 1].link != undefined) {
const nextIndex = this.inputs.length
this.addInput(`${_prefix}_${nextIndex + 1}`, this.inputs[0].type)
}
}
return me
}
} else if (nodeData.name == "GODMT_MergeBatch") {
const onNodeCreated = nodeType.prototype.onNodeCreated
nodeType.prototype.onNodeCreated = function () {
const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined
this.addInput(`${_prefix}_1`, 'LIST')
return r
}
@@ -112,7 +197,7 @@ app.registerExtension({
for (let i = length - 1; i >= 0; i--) {
this.removeInput(i)
}
this.addInput(`${_prefix}_1`, 'STRING')
this.addInput(`${_prefix}_1`, 'LIST')
}
return r
}
@@ -121,7 +206,7 @@ app.registerExtension({
nodeType.prototype.onConnectionsChange = function (slotType, slot, event, link_info, data) {
const me = onConnectionsChange ? onConnectionsChange.apply(this, arguments) : undefined
if (slotType === TypeSlot.Input) {
dynamic_connection(this, slot, event, `${_prefix}_`, 'STRING')
dynamic_connection(this, slot, event, `${_prefix}_`, 'LIST')
if (event === TypeSlotEvent.Connect && link_info) {
const fromNode = this.graph._nodes.find(
(otherNode) => otherNode.id == link_info.origin_id
@@ -129,11 +214,11 @@ app.registerExtension({
const type = fromNode.outputs[link_info.origin_slot].type
this.inputs[slot].type = type
} else if (event === TypeSlotEvent.Disconnect) {
this.inputs[slot].type = 'STRING'
this.inputs[slot].type = 'LIST'
this.inputs[slot].label = `${_prefix}_${slot + 1}`
}
}
return me;
return me
}
} else if (nodeData.name === "GODMT_Unpack") {
const onNodeCreated = nodeType.prototype.onNodeCreated
@@ -159,7 +244,7 @@ app.registerExtension({
this.addOutput(`${_prefix}_1`, "*")
}
this.outputs[0].type = "*"
const output_len = this.outputs.length;
const output_len = this.outputs.length
for (let i = output_len - 1; i > 0; i--) {
this.removeOutput(i)
}
@@ -198,19 +283,86 @@ app.registerExtension({
}
}
return me;
return me
}
} else if (nodeData.name == "GODMT_AnyCast") {
const onNodeCreated = nodeType.prototype.onNodeCreated
nodeType.prototype.onNodeCreated = function () {
const me = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined
const onWidgetChanged = this.widgets[0].callback
const thisNode = this
this.widgets[0].callback = function () {
const me = onWidgetChanged ? onWidgetChanged.apply(this, arguments) : undefined
const output_type = thisNode.widgets[0].value
thisNode.outputs[0].type = output_type
thisNode.outputs[0].label = output_type
thisNode.outputs[0].name = output_type
return me
}
return me
}
// on copy, paste, load
const onConfigure = nodeType.prototype.onConfigure
nodeType.prototype.onConfigure = function () {
const me = onConfigure ? onConfigure.apply(this, arguments) : undefined
const output_type = this.widgets[0].value
this.outputs[0].type = output_type
this.outputs[0].label = output_type
this.outputs[0].name = output_type
return me
}
const onConnectionsChange = nodeType.prototype.onConnectionsChange
nodeType.prototype.onConnectionsChange = function (slotType, slot, event, link_info, data) {
const me = onConnectionsChange ? onConnectionsChange.apply(this, arguments) : undefined
if (slotType === TypeSlot.Input) {
if (event === TypeSlotEvent.Connect && link_info) {
const origin_node = app.graph.getNodeById(link_info.origin_id)
const origin_slot = origin_node.outputs[link_info.origin_slot]
const origin_type = origin_slot.type
const types = getWorkflowTypes(app)
this.widgets[0].options.values = types
const output_type = this.widgets[0].value
this.outputs[0].type = output_type
this.outputs[0].label = output_type
this.outputs[0].name = origin_type
} else if (event === TypeSlotEvent.Disconnect) {
this.outputs[0].type = "*"
this.outputs[0].label = "*"
this.outputs[0].name = "*"
}
}
return me
}
} else if (nodeData.name === "GODMT_GetShape") {
const onNodeCreated = nodeType.prototype.onNodeCreated;
const onNodeCreated = nodeType.prototype.onNodeCreated
nodeType.prototype.onNodeCreated = function () {
onNodeCreated ? onNodeCreated.apply(this, []) : undefined;
this.showValueWidget = ComfyWidgets["STRING"](this, "WHBC", ["STRING", { multiline: false }], app).widget;
};
const onExecuted = nodeType.prototype.onExecuted;
onNodeCreated ? onNodeCreated.apply(this, []) : undefined
this.showValueWidget = ComfyWidgets["STRING"](this, "WHBC", ["STRING", { multiline: false }], app).widget
}
const onExecuted = nodeType.prototype.onExecuted
nodeType.prototype.onExecuted = function (message) {
onExecuted === null || onExecuted === void 0 ? void 0 : onExecuted.apply(this, [message]);
this.showValueWidget.value = message.text[0];
};
onExecuted === null || onExecuted === void 0 ? void 0 : onExecuted.apply(this, [message])
this.showValueWidget.value = message.text[0]
}
} else if (nodeData.name === "GODMT_ListGetByIndex" || nodeData.name === "GODMT_ListSlice") {
const onConnectionsChange = nodeType.prototype.onConnectionsChange
nodeType.prototype.onConnectionsChange = function (slotType, slot, event, link_info, data) {
const me = onConnectionsChange ? onConnectionsChange.apply(this, arguments) : undefined
if (slotType === TypeSlot.Input) {
if (event === TypeSlotEvent.Connect && link_info) {
const node = app.graph.getNodeById(link_info.origin_id)
let origin_type = node.outputs[link_info.origin_slot].type
this.outputs[0].type = origin_type
this.outputs[0].label = origin_type
this.outputs[0].name = origin_type
} else if (event === TypeSlotEvent.Disconnect) {
this.outputs[0].type = "*"
this.outputs[0].label = "*"
this.outputs[0].name = "*"
}
}
return me
}
}
}
})
+285 -184
View File
@@ -1,3 +1,4 @@
import numpy as np
import itertools
@@ -91,35 +92,7 @@ class SplitString:
return (result, result, length)
class StringListSelectByIndex:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"STRING": ("STRING", {"forceInput": True}),
"index": ("INT", {"forceInput": False, "default": 0}),
}
}
TITLE = "String List: Select By Index"
RETURN_TYPES = ("STRING", )
RETURN_NAMES = ("STRING", )
INPUT_IS_LIST = True
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, STRING: list[str], index: list[int]):
index = index[0]
if index >= len(STRING):
print("Error: index out of range")
return ("", )
return (STRING[index], )
class ListSelectByIndex:
class ListGetByIndex:
def __init__(self):
pass
@@ -132,7 +105,7 @@ class ListSelectByIndex:
}
}
TITLE = "List: Select By Index"
TITLE = "List: Get By Index"
RETURN_TYPES = (ANY_TYPE, )
INPUT_IS_LIST = True
FUNCTION = "run"
@@ -146,7 +119,7 @@ class ListSelectByIndex:
return (ANY[index], )
class BatchSelectByIndex:
class BatchGetByIndex:
def __init__(self):
pass
@@ -159,7 +132,7 @@ class BatchSelectByIndex:
}
}
TITLE = "Batch: Select By Index"
TITLE = "Batch: Get By Index"
RETURN_TYPES = (ANY_TYPE, )
FUNCTION = "run"
CATEGORY = "list_utils"
@@ -171,36 +144,6 @@ class BatchSelectByIndex:
return (LIST[index], )
class StringListSlice:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"STRING": ("STRING", {"forceInput": True}),
"start": ("INT", {"default": 0}),
"end": ("INT", {"default": 0, "min": -9007199254740991}),
}
}
TITLE = "String List: Slice"
RETURN_TYPES = ("STRING", )
RETURN_NAMES = ("STRING", )
INPUT_IS_LIST = True
OUTPUT_IS_LIST = (True, )
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, STRING: list[str], start: list[int], end: list[int]):
start = start[0]
end = end[0]
if end == 0:
return (STRING[start:], )
return (STRING[start:end], )
class ListSlice:
def __init__(self):
pass
@@ -209,8 +152,8 @@ class ListSlice:
def INPUT_TYPES(s):
return {
"required": {
"ANY": ("ANY_TYPE", {"forceInput": True}),
"start": ("INT", {"default": 0}),
"ANY": (ANY_TYPE, {"forceInput": True}),
"start": ("INT", {"default": 0, "min": -9007199254740991}),
"end": ("INT", {"default": 0, "min": -9007199254740991}),
}
}
@@ -239,7 +182,7 @@ class BatchSlice:
return {
"required": {
"LIST": ("LIST", {"forceInput": True}),
"start": ("INT", {"default": 0}),
"start": ("INT", {"default": 0, "min": -9007199254740991}),
"end": ("INT", {"default": 0, "min": -9007199254740991}),
}
}
@@ -255,53 +198,6 @@ class BatchSlice:
return (LIST[start:end], )
class BatchToStringList:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"LIST": ("LIST", ),
}
}
TITLE = "Batch To String List"
RETURN_TYPES = ("STRING", )
RETURN_NAMES = ("STRING", )
OUTPUT_IS_LIST = (True,)
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, LIST: list):
str_list = [str(i) for i in LIST]
return (str_list, )
class StringListToBatch:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"STRING": ("STRING", {"forceInput": True}),
}
}
TITLE = "String List To Batch"
RETURN_TYPES = ("LIST", )
RETURN_NAMES = ("LIST", )
INPUT_IS_LIST = True
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, STRING: list[str]):
return (STRING, )
class BatchToList:
def __init__(self):
pass
@@ -443,6 +339,151 @@ class CreateBatch:
return (output_list, )
class MergeList:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {},
"optional": {},
"hidden": {
"unique_id": "UNIQUE_ID",
"prompt": "PROMPT",
"extra_pnginfo": "EXTRA_PNGINFO",
},
}
TITLE = "Merge List"
INPUT_IS_LIST = True
RETURN_TYPES = (ANY_TYPE, )
OUTPUT_IS_LIST = (True, )
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, unique_id, prompt, extra_pnginfo, **kwargs):
unique_id = unique_id[0]
prompt = prompt[0]
extra_pnginfo = extra_pnginfo[0]
node_list = extra_pnginfo["workflow"]["nodes"] # list of dict including id, type
cur_node = next(n for n in node_list if str(n["id"]) == unique_id)
output_list = []
for k, v in kwargs.items():
if k.startswith(PACK_PREFIX):
output_list += v
return (output_list, )
class MergeBatch:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {},
"optional": {},
"hidden": {
"unique_id": "UNIQUE_ID",
"prompt": "PROMPT",
"extra_pnginfo": "EXTRA_PNGINFO",
},
}
TITLE = "Merge Batch"
RETURN_TYPES = ("LIST", )
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, unique_id, prompt, extra_pnginfo, **kwargs):
node_list = extra_pnginfo["workflow"]["nodes"] # list of dict including id, type
cur_node = next(n for n in node_list if str(n["id"]) == unique_id)
output_list = []
for k, v in kwargs.items():
if k.startswith(PACK_PREFIX):
output_list += v
return (output_list, )
class CreateRange:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"start": ("INT", {"default": 0, "min": -9007199254740991}),
"stop": ("INT", {"default": 1, "min": -9007199254740991}),
"step": ("INT", {"default": 1, "min": -9007199254740991}),
},
}
TITLE = "Create Range"
RETURN_TYPES = ("INT", "LIST", "INT")
RETURN_NAMES = ("INT", "LIST", "length")
OUTPUT_IS_LIST = (True, False, False, )
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, start: int, stop: int, step: int):
range_list = list(range(start, stop, step))
return (range_list, range_list, len(range_list))
class CreateArange:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"start": ("FLOAT", {"default": 0}),
"stop": ("FLOAT", {"default": 1}),
"step": ("FLOAT", {"default": 1}),
},
}
TITLE = "Create Arange"
RETURN_TYPES = ("FLOAT", "LIST", "INT")
RETURN_NAMES = ("FLOAT", "LIST", "length")
OUTPUT_IS_LIST = (True, False, False, )
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, start: float, stop: float, step: float):
range_list = list(np.arange(start, stop, step))
return (range_list, range_list, len(range_list))
class CreateLinspace:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"start": ("FLOAT", {"default": 0}),
"stop": ("FLOAT", {"default": 1}),
"num": ("INT", {"default": 10, "min": 2}),
},
}
TITLE = "Create Linspace"
RETURN_TYPES = ("FLOAT", "LIST", "INT")
RETURN_NAMES = ("FLOAT", "LIST", "length")
OUTPUT_IS_LIST = (True, False, False, )
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, start: float, stop: float, num: int):
range_list = list(np.linspace(start, stop, num))
return (range_list, range_list, len(range_list))
PACK_PREFIX = 'value'
class Pack:
def __init__(self):
@@ -522,69 +563,6 @@ class Unpack:
return tuple(outputs)
class AnyToDict:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"ANY" : (ANY_TYPE, {}),
},
}
TITLE = "Any To Dict"
RETURN_TYPES = ("DICT", "STRING")
RETURN_NAMES = ("DICT", "str()")
OUTPUT_NODE = True
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, ANY):
if type(ANY) is dict:
return (ANY, str(ANY))
elif not hasattr(ANY, '__dict__'):
print(f"Object of type {type(ANY).__name__} doesn't have a __dict__ attribute")
return ({}, str(ANY))
else:
return (vars(ANY), str(ANY))
class GetWidgetsValues:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"ANY" : (ANY_TYPE, {}),
},
"hidden": {
"unique_id": "UNIQUE_ID",
"prompt": "PROMPT",
"extra_pnginfo": "EXTRA_PNGINFO",
},
}
TITLE = "Get Widgets Values"
RETURN_TYPES = ("LIST", )
RETURN_NAMES = ("LIST", )
OUTPUT_NODE = True
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, ANY, unique_id, prompt, extra_pnginfo):
node_list = extra_pnginfo["workflow"]["nodes"] # list of dict including id, type
cur_node = next(n for n in node_list if str(n["id"]) == unique_id)
link_id = cur_node["inputs"][0]["link"]
link = next(l for l in extra_pnginfo["workflow"]["links"] if l[0] == link_id)
in_node_id, in_socket_id = link[1], link[2]
in_node = next(n for n in node_list if n["id"] == in_node_id)
return (in_node["widgets_values"], )
class GetLength:
def __init__(self):
pass
@@ -670,25 +648,148 @@ class GetShape:
return { "ui": {"text": (f"{W}, {H}, {B}, {C}",)}, "result": (W, H, B, C) }
class AnyToDict:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"ANY" : (ANY_TYPE, {}),
},
}
TITLE = "Any To Dict"
RETURN_TYPES = ("DICT", "STRING")
RETURN_NAMES = ("DICT", "str()")
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, ANY):
if type(ANY) is dict:
return (ANY, str(ANY))
elif not hasattr(ANY, '__dict__'):
print(f"Object of type {type(ANY).__name__} doesn't have a __dict__ attribute")
return ({}, str(ANY))
else:
return (vars(ANY), str(ANY))
class GetWidgetsValues:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"ANY" : (ANY_TYPE, {}),
},
"hidden": {
"unique_id": "UNIQUE_ID",
"prompt": "PROMPT",
"extra_pnginfo": "EXTRA_PNGINFO",
},
}
TITLE = "Get Widgets Values"
RETURN_TYPES = ("LIST", )
RETURN_NAMES = ("LIST", )
OUTPUT_NODE = True
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, ANY, unique_id, prompt, extra_pnginfo):
node_list = extra_pnginfo["workflow"]["nodes"] # list of dict including id, type
cur_node = next(n for n in node_list if str(n["id"]) == unique_id)
link_id = cur_node["inputs"][0]["link"]
link = next(l for l in extra_pnginfo["workflow"]["links"] if l[0] == link_id)
in_node_id, in_socket_id = link[1], link[2]
in_node = next(n for n in node_list if n["id"] == in_node_id)
return (in_node["widgets_values"], )
class AnyCast:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"ANY" : (ANY_TYPE, {}),
"TYPE": (["*", "STRING", "INT", "FLOAT", "IMAGE", "LATENT", "MASK", "NOISE", "SAMPLER", "SIGMAS", "GUIDER", "MODEL", "CLIP", "VAE", "CONDITIONING"], {}),
},
}
TITLE = "Any Cast"
RETURN_TYPES = (ANY_TYPE,)
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, ANY, TYPE):
result = ANY
if TYPE == "STRING":
result = str(ANY)
elif TYPE == "INT":
result = int(ANY)
elif TYPE == "FLOAT" or TYPE == "NUMBER":
result = float(ANY)
return (result, )
class BatchItemCast:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"LIST": ("LIST", {"forceInput": True}),
"TYPE": (["STRING", "INT", "FLOAT", "NUMBER"], {}),
},
}
TITLE = "Batch Item Cast"
RETURN_TYPES = ("LIST", )
RETURN_NAMES = ("LIST", )
FUNCTION = "run"
CATEGORY = "list_utils"
def run(self, LIST: list, TYPE: str):
converted_list = []
if TYPE == "STRING":
converted_list = [str(v) for v in LIST]
elif TYPE == "INT":
converted_list = [int(v) for v in LIST]
elif TYPE == "FLOAT" or TYPE == "NUMBER":
converted_list = [float(v) for v in LIST]
return (converted_list, )
NODE_CLASS_MAPPINGS = {
"GODMT_SplitString": SplitString,
"GODMT_StringListSelectByIndex": StringListSelectByIndex,
"GODMT_ListSelectByIndex": ListSelectByIndex,
"GODMT_BatchSelectByIndex": BatchSelectByIndex,
"GODMT_StringListSlice": StringListSlice,
"GODMT_ListGetByIndex": ListGetByIndex,
"GODMT_BatchGetByIndex": BatchGetByIndex,
"GODMT_ListSlice": ListSlice,
"GODMT_BatchSlice": BatchSlice,
"GODMT_BatchToStringList": BatchToStringList,
"GODMT_StringListToBatch": StringListToBatch,
"GODMT_BatchToList": BatchToList,
"GODMT_ListToBatch": ListToBatch,
"GODMT_CreateStringList": CreateStringList,
"GODMT_BatchToList": BatchToList,
"GODMT_CreateList": CreateList,
"GODMT_CreateBatch": CreateBatch,
"GODMT_MergeList": MergeList,
"GODMT_MergeBatch": MergeBatch,
"GODMT_CreateRange": CreateRange,
"GODMT_CreateArange": CreateArange,
"GODMT_CreateLinspace": CreateLinspace,
"GODMT_Pack": Pack,
"GODMT_Unpack": Unpack,
"GODMT_AnyToDict": AnyToDict,
"GODMT_GetLength": GetLength,
"GODMT_GetShape": GetShape,
"GODMT_AnyToDict": AnyToDict,
"GODMT_GetWidgetsValues": GetWidgetsValues,
"GODMT_AnyCast": AnyCast,
"GODMT_BatchItemCast": BatchItemCast,
}
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui-list-utils"
description = "LIST and BATCH utilities which support: create, convert, get or slice items"
version = "1.0.1"
version = "1.1.0"
license = { file = "LICENSE" }
[project.urls]