Eji-Sensei14's picture
Upload folder using huggingface_hub
c6535db verified
import {app} from "@/composable/comfyAPI";
import {LoraInfoDialog, CheckpointInfoDialog} from "@/composable/model"
import {$t} from '@/composable/i18n.js'
import swap from "@/constants/swap.js";
// Replace node
function replaceNode(oldNode, newNodeName, type) {
const newNode = LiteGraph.createNode(newNodeName);
if (!newNode) {
return;
}
app.graph.add(newNode);
newNode.pos = oldNode.pos.slice();
newNode.size = oldNode.size.slice();
if(oldNode.widgets?.length>0){
oldNode.widgets.forEach(widget => {
if(swap[type]?.['widget']?.[widget.name]){
const newName = swap[type]['widget'][widget.name];
if (newName && newNode.widgets) {
const newWidget = findWidgetByName(newNode, newName);
if (newWidget) {
newWidget.value = widget.value;
if(widget.name == 'seed_num'){
newWidget.linkedWidgets[0].value = widget.linkedWidgets[0].value
}
if(widget.type == 'converted-widget'){
convertToInput(newNode, newWidget, widget);
}
}
}
}
});
}
if(oldNode.inputs){
oldNode.inputs.forEach((input, index) => {
if (input && input.link && swap[type]?.['input']?.[input.name]) {
const newInputName = swap[type]?.['input'][input.name];
// If the new node does not have this output, skip
if (newInputName === null) {
return;
}
const newInputIndex = newNode.findInputSlot(newInputName);
if (newInputIndex !== -1) {
const originLinkInfo = oldNode.graph.links[input.link];
if (originLinkInfo) {
const originNode = oldNode.graph.getNodeById(originLinkInfo.origin_id);
if (originNode) {
originNode.connect(originLinkInfo.origin_slot, newNode, newInputIndex);
}
}
}
}
});
}
if(oldNode.outputs){
oldNode.outputs.forEach((output, index) => {
if (output && output.links && swap[type]?.['output']?.[output.name]) {
const newOutputName = swap[type]['output'][output.name];
// If the new node does not have this output, skip
if (newOutputName === null) {
return;
}
const newOutputIndex = newNode.findOutputSlot(newOutputName);
if (newOutputIndex !== -1) {
output.links.forEach(link => {
const targetLinkInfo = oldNode.graph.links[link];
if (targetLinkInfo) {
const targetNode = oldNode.graph.getNodeById(targetLinkInfo.target_id);
if (targetNode) {
newNode.connect(newOutputIndex, targetNode, targetLinkInfo.target_slot);
}
}
});
}
}
});
}
// Remove old node
app.graph.remove(oldNode);
// Remove others
if(newNode.type == 'easy fullkSampler'){
const link_output_id = newNode.outputs[0].links
if(link_output_id && link_output_id[0]){
const nodes = app.graph._nodes
const node = nodes.find(cate=> cate.inputs && cate.inputs[0] && cate.inputs[0]['link'] == link_output_id[0])
if(node){
app.graph.remove(node);
}
}
}else if(swap.preSampling.nodes.includes(newNode.type)){
const link_output_id = newNode.outputs[0].links
if(!link_output_id || !link_output_id[0]){
const ksampler = LiteGraph.createNode('easy kSampler');
app.graph.add(ksampler);
ksampler.pos = newNode.pos.slice();
ksampler.pos[0] = ksampler.pos[0] + newNode.size[0] + 20;
const newInputIndex = newNode.findInputSlot('pipe');
if (newInputIndex !== -1) {
if (newNode) {
newNode.connect(0, ksampler, newInputIndex);
}
}
}
}
// autoHeight
newNode.setSize([newNode.size[0], newNode.computeSize()[1]]);
}
export function findWidgetByName(node, widgetName) {
return node.widgets.find(widget => typeof widgetName == 'object' ? widgetName.includes(widget.name) : widget.name === widgetName);
}
function replaceNodeMenuCallback(currentNode, targetNodeName, type) {
return function() {
replaceNode(currentNode, targetNodeName, type);
};
}
const addMenuHandler = (nodeType, cb)=> {
const getOpts = nodeType.prototype.getExtraMenuOptions;
nodeType.prototype.getExtraMenuOptions = function () {
const r = getOpts.apply(this, arguments);
cb.apply(this, arguments);
return r;
};
}
const addMenu = (content, type, nodes_include, nodeType, has_submenu=true) => {
addMenuHandler(nodeType, function (_, options) {
options.unshift({
content: content,
has_submenu: has_submenu,
callback: (value, options, e, menu, node) => showSwapMenu(value, options, e, menu, node, type, nodes_include)
})
if(type == 'loaders') {
options.unshift({
content: $t("💎 View Lora Info..."),
callback: (value, options, e, menu, node) => {
const widget = node.widgets.find(cate => cate.name == 'lora_name')
let name = widget.value;
if (!name || name == 'None') return
// todo: lora info
new LoraInfoDialog(name).show('loras', name);
}
})
options.unshift({
content: $t("💎 View Checkpoint Info..."),
callback: (value, options, e, menu, node) => {
let name = node.widgets[0].value;
if (!name || name == 'None') return
// todo: checkpoint info
new CheckpointInfoDialog(name).show('checkpoints', name);
}
})
}
})
}
const showSwapMenu = (value, options, e, menu, node, type, nodes_include) => {
const swapOptions = [];
nodes_include.map(cate=>{
if (node.type !== cate) {
swapOptions.push({
content: `${cate}`,
callback: replaceNodeMenuCallback(node, cate, type)
});
}
})
new LiteGraph.ContextMenu(swapOptions, {
event: e,
callback: null,
parentMenu: menu,
node: node
});
return false;
}
// 重载节点
const CONVERTED_TYPE = "converted-widget";
const GET_CONFIG = Symbol();
function hideWidget(node, widget, suffix = "") {
widget.origType = widget.type;
widget.origComputeSize = widget.computeSize;
widget.origSerializeValue = widget.serializeValue;
widget.computeSize = () => [0, -4]; // -4 is due to the gap litegraph adds between widgets automatically
widget.type = CONVERTED_TYPE + suffix;
widget.serializeValue = () => {
// Prevent serializing the widget if we have no input linked
if (!node.inputs) {
return undefined;
}
let node_input = node.inputs.find((i) => i.widget?.name === widget.name);
if (!node_input || !node_input.link) {
return undefined;
}
return widget.origSerializeValue ? widget.origSerializeValue() : widget.value;
};
// Hide any linked widgets, e.g. seed+seedControl
if (widget.linkedWidgets) {
for (const w of widget.linkedWidgets) {
hideWidget(node, w, ":" + widget.name);
}
}
}
function convertToInput(node, widget, config) {
console.log('config:', config)
hideWidget(node, widget);
const { type } = getWidgetType(config);
// Add input and store widget config for creating on primitive node
const sz = node.size;
if(!widget.options || !widget.options.forceInput){
node.addInput(widget.name, type, {
widget: { name: widget.name, [GET_CONFIG]: () => config },
});
}
for (const widget of node.widgets) {
widget.last_y += LiteGraph.NODE_SLOT_HEIGHT;
}
// Restore original size but grow if needed
node.setSize([Math.max(sz[0], node.size[0]), Math.max(sz[1], node.size[1])]);
}
function getWidgetType(config) {
// Special handling for COMBO so we restrict links based on the entries
let type = config[0];
if (type instanceof Array) {
type = "COMBO";
}
return { type };
}
const reloadNode = function (node) {
const nodeType = node.constructor.type;
const origVals = node.properties.origVals || {};
const nodeTitle = origVals.title || node.title;
const nodeColor = origVals.color || node.color;
const bgColor = origVals.bgcolor || node.bgcolor;
const oldNode = node
const options = {
'size': [...node.size],
'color': nodeColor,
'bgcolor': bgColor,
'pos': [...node.pos]
}
let inputLinks = []
let outputLinks = []
if(node.inputs){
for (const input of node.inputs) {
if (input.link) {
const input_name = input.name
const input_slot = node.findInputSlot(input_name)
const input_node = node.getInputNode(input_slot)
const input_link = node.getInputLink(input_slot)
inputLinks.push([input_link.origin_slot, input_node, input_name])
}
}
}
if(node.outputs) {
for (const output of node.outputs) {
if (output.links) {
const output_name = output.name
for (const linkID of output.links) {
const output_link = graph.links[linkID]
const output_node = graph._nodes_by_id[output_link.target_id]
outputLinks.push([output_name, output_node, output_link.target_slot])
}
}
}
}
app.graph.remove(node)
let newNode = app.graph.add(LiteGraph.createNode(nodeType, nodeTitle, options));
newNode.inputs.map((cate,index) => {
newNode.inputs[index]['label'] = node.inputs[index]['label']
})
newNode.outputs.map((cate,index) => {
newNode.outputs[index]['label'] = node.outputs[index]['label']
})
function handleLinks() {
// re-convert inputs
if(oldNode.widgets) {
for (let w of oldNode.widgets) {
if (w.type === 'converted-widget') {
const WidgetToConvert = newNode.widgets.find((nw) => nw.name === w.name);
for (let i of oldNode.inputs) {
if (i.name === w.name) {
convertToInput(newNode, WidgetToConvert, i.widget);
}
}
}
}
}
// replace input and output links
for (let input of inputLinks) {
const [output_slot, output_node, input_name] = input;
output_node.connect(output_slot, newNode.id, input_name)
}
for (let output of outputLinks) {
const [output_name, input_node, input_slot] = output;
newNode.connect(output_name, input_node, input_slot)
}
}
// fix widget values
let values = oldNode.widgets_values;
if (!values && newNode.widgets?.length>0) {
newNode.widgets.forEach((newWidget, index) => {
const oldWidget = oldNode.widgets[index];
if (newWidget.name === oldWidget.name && newWidget.type === oldWidget.type) {
newWidget.value = oldWidget.value;
}
});
handleLinks();
return;
}
if(values){
let pass = false
const isIterateForwards = values?.length <= newNode.widgets?.length;
let vi = isIterateForwards ? 0 : values.length - 1 ;
function evalWidgetValues(testValue, newWidg) {
if (testValue === true || testValue === false) {
if (newWidg.options?.on && newWidg.options?.off) {
return { value: testValue, pass: true };
}
} else if (typeof testValue === "number") {
if (newWidg.options?.min <= testValue && testValue <= newWidg.options?.max) {
return { value: testValue, pass: true };
}
} else if (newWidg.options?.values?.includes(testValue)) {
return { value: testValue, pass: true };
} else if (newWidg.inputEl && typeof testValue === "string") {
return { value: testValue, pass: true };
}
return { value: newWidg.value, pass: false };
}
const updateValue = (wi) => {
const oldWidget = oldNode.widgets[wi];
let newWidget = newNode.widgets[wi];
if (newWidget.name === oldWidget.name && newWidget.type === oldWidget.type) {
while ((isIterateForwards ? vi < values.length : vi >= 0) && !pass) {
let { value, pass } = evalWidgetValues(values[vi], newWidget);
if (pass && value !== null) {
newWidget.value = value;
break;
}
vi += isIterateForwards ? 1 : -1;
}
vi++
if (!isIterateForwards) {
vi = values.length - (newNode.widgets?.length - 1 - wi);
}
}
};
if (isIterateForwards && newNode.widgets?.length>0) {
for (let wi = 0; wi < newNode.widgets.length; wi++) {
updateValue(wi);
}
} else if(newNode.widgets?.length>0){
for (let wi = newNode.widgets.length - 1; wi >= 0; wi--) {
updateValue(wi);
}
}
}
handleLinks();
};
app.registerExtension({
name: "Comfy.EasyUse.ExtraMenu",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
// 刷新节点
addMenuHandler(nodeType, function (_, options) {
options.unshift({
content: $t("🔃 Reload Node"),
callback: (value, options, e, menu, node) => {
let graphcanvas = LGraphCanvas.active_canvas;
if (!graphcanvas.selected_nodes || Object.keys(graphcanvas.selected_nodes).length <= 1) {
reloadNode(node);
} else {
for (let i in graphcanvas.selected_nodes) {
reloadNode(graphcanvas.selected_nodes[i]);
}
}
}
})
// ckptNames
if(nodeData.name == 'easy ckptNames'){
options.unshift({
content: $t("💎 View Checkpoint Info..."),
callback: (value, options, e, menu, node) => {
let name = node.widgets[0].value;
if (!name || name == 'None') return
}
})
}
})
for (const key in swap) {
if (swap[key].nodes.includes(nodeData.name)) {
addMenu(`↪️ Swap ${swap[key].category}`, key, swap[key].nodes, nodeType)
}
}
}
});