Initial code commit - v1.0

This commit is contained in:
webfiltered
2024-07-29 19:02:51 +10:00
parent bfeb99f98f
commit 19a3c1504b
3 changed files with 204 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
from .debugnode import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
WEB_DIRECTORY = "js"
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
+82
View File
@@ -0,0 +1,82 @@
"""A simple debug node used to quickly check output of nodes in ComfyUI"""
# AnyType was ruthlessly pilfered from https://github.com/pythongosssss/ComfyUI-Custom-Scripts
class AnyType(str):
def __ne__(self, __value: object) -> bool:
return False
ANY = AnyType("*")
class WTFDebugNode:
"""What's That Field? Displays string representation of node output to ease debugging
Displays some common attributes, if available:
- len()
- .shape
- if the input was an iterable, the type of the first child item
Displays str(Exception) on for unhandled exceptions"""
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"anything": (ANY,),
}
}
OUTPUT_NODE = True
INPUT_IS_LIST = True
# OUTPUT_IS_LIST = (False,)
RETURN_TYPES = ()
FUNCTION = "execute"
CATEGORY = "debug"
def execute(self, anything=None):
out = []
for item in anything:
info = {
"type": str(type(item)),
}
try:
info["len"] = len(item)
except TypeError:
pass
except Exception as e:
info["len"] = str(e)
if not isinstance(item, str):
try:
first_iter_item = next(iter(item))
info["firstIterItem"] = str(type(first_iter_item))
except TypeError:
pass
# info["firstIterItem"] = ["Wasn't a list"]
except StopIteration:
info["firstIterItem"] = "List had no items"
except Exception as e:
info["firstIterItem"] = f"Exception [firstIterItem]: {str(e)}"
try:
info["shape"] = str(item.shape)
except AttributeError:
pass
except Exception as e:
info["shape"] = str(e)
info["value"] = str(item) if item != None else None
out.append(info)
return { "ui": { "items": out, "length": len(anything) } }
NODE_CLASS_MAPPINGS = {
"WTFDebugNode": WTFDebugNode,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"WTFDebugNode": "🐜 WTF?",
}
+117
View File
@@ -0,0 +1,117 @@
import { app } from "../../scripts/app.js";
import { ComfyWidgets } from "../../scripts/widgets.js";
const hardLimit = 100
// Does most of the regular textarea cleanup, but leaks a ref in domWidget.js -> elementWidgets until the node is removed
function removeWidget(node, widget) {
widget.onRemove?.()
const index = node.widgets.indexOf(widget)
if (index !== -1)
node.widgets.splice(index, 1)
}
function removeAllWidgets(node) {
for (const widget of node.widgets) {
widget.onRemove?.()
}
node.widgets.length = 0
}
// Main logic
app.registerExtension({
name: "WTFDebugNode",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "WTFDebugNode") {
const origOnExecuted = nodeType.prototype.onExecuted;
nodeType.prototype.onExecuted = function (message) {
const r = origOnExecuted
? origOnExecuted?.apply(this, arguments)
: undefined
// Because debug
console.log(message)
// Sanity init
this.widgets ??= []
this.serialize_widgets = false
const baseOpacity = app.canvas.editor_alpha
// Clear if invalid
const itemsLength = parseInt(message?.items?.length)
if (isNaN(itemsLength)) {
removeAllWidgets(this)
return r
}
const isMultiItem = itemsLength > 1
const wasMultiItem = this.debugNodeLength !== 1
// Clean up existing widgets if required
if (isMultiItem !== wasMultiItem) {
removeAllWidgets(this)
}
// Remove only widgets we can't reuse
else if (this.debugNodeLength > itemsLength) {
for (let i = itemsLength; i <= this.debugNodeLength; i++) {
for (const widget of this.widgets.filter(x => x.name.endsWith(` ${i}`))) {
removeWidget(this, widget)
}
}
}
this.debugNodeLength = itemsLength
const maxItems = Math.min(itemsLength, hardLimit)
// Create / update widget values for each item
for (let i = 0; i < maxItems; i++) {
const item = message.items[i]
const type = item.type
const len = item.len
const shape = item.shape
const firstIterItem = item.firstIterItem
const value = item.value
function processWidget(node, name, value, isMultiline = false) {
const numberedName = isMultiItem
? `${name} ${i}`
: name
const comfyType = isMultiline
? ["STRING", { multiline: true }]
: "STRING"
const current = node.widgets.find(x => x.name === numberedName)
const widget = current ?? ComfyWidgets.STRING(node, numberedName, comfyType, app).widget
if (!widget.options)
widget.options = {}
widget.options.serialize = false
widget.value = value
widget.disabled = value === null || value === undefined
if (isMultiline) {
widget.element.style.opacity = widget.disabled
? baseOpacity * 0.5
: baseOpacity
}
}
processWidget(this, "type", type)
processWidget(this, "len()", len)
processWidget(this, "shape", shape)
processWidget(this, "type of first iter() item", firstIterItem)
processWidget(this, "value", value, true)
}
requestAnimationFrame(() => {
const size = this.computeSize();
for (const widget of this.widgets.filter(x => x.element)) {
widget.onResize?.(size)
}
})
return r
}
}
},
});