303 lines
8.7 KiB
JavaScript
303 lines
8.7 KiB
JavaScript
const smart_connect_config_input = [
|
||
{
|
||
node_type: 'CLIPTextEncode',
|
||
node_widget_name: 'text',
|
||
inputNodeName: 'RandomPrompt',
|
||
inputNode_output_name: 'STRING'
|
||
},
|
||
{
|
||
node_type: 'CLIPTextEncode',
|
||
node_widget_name: 'text',
|
||
inputNodeName: 'EmbeddingPrompt',
|
||
inputNode_output_name: 'STRING'
|
||
},
|
||
{
|
||
node_type: 'CLIPTextEncode',
|
||
node_widget_name: 'text',
|
||
inputNodeName: 'ChinesePrompt_Mix',
|
||
inputNode_output_name: 'prompt'
|
||
},
|
||
{
|
||
node_type: 'CheckpointLoaderSimple',
|
||
node_widget_name: 'ckpt_name',
|
||
inputNodeName: 'CkptNames_',
|
||
inputNode_output_name: 'ckpt_names'
|
||
},
|
||
{
|
||
node_type: 'KSampler',
|
||
node_widget_name: 'sampler_name',
|
||
inputNodeName: 'SamplerNames_',
|
||
inputNode_output_name: 'sampler_names'
|
||
},
|
||
{
|
||
node_type: 'LoraLoaderModelOnly',
|
||
node_widget_name: 'lora_name',
|
||
inputNodeName: 'LoraNames_',
|
||
inputNode_output_name: 'lora_names'
|
||
},
|
||
{
|
||
node_type: 'LoadLoRA',
|
||
node_widget_name: 'lora_name',
|
||
inputNodeName: 'LoraNames_',
|
||
inputNode_output_name: 'lora_names'
|
||
},
|
||
{
|
||
node_type: 'Moondream',
|
||
node_widget_name: 'image',
|
||
inputNodeName: 'LoadImage',
|
||
inputNode_output_name: 'IMAGE'
|
||
}
|
||
]
|
||
|
||
const smart_connect_config_output = [
|
||
{
|
||
node_type: 'LoadImage',
|
||
node_output_name: 'IMAGE',
|
||
outputNodeName: 'ClipInterrogator',
|
||
outputNode_input_name: 'image'
|
||
},
|
||
{
|
||
node_type: 'VAEDecode',
|
||
node_output_name: 'IMAGE',
|
||
outputNodeName: 'PromptImage',
|
||
outputNode_input_name: 'images'
|
||
},
|
||
{
|
||
node_type: 'VAEDecode',
|
||
node_output_name: 'IMAGE',
|
||
outputNodeName: 'PreviewImage',
|
||
outputNode_input_name: 'images'
|
||
},
|
||
{
|
||
node_type: 'VAEDecode',
|
||
node_output_name: 'IMAGE',
|
||
outputNodeName: 'SaveImage',
|
||
outputNode_input_name: 'images'
|
||
},
|
||
{
|
||
node_type: 'Moondream',
|
||
node_output_name: 'STRING',
|
||
outputNodeName: 'ShowTextForGPT',
|
||
outputNode_input_name: 'text'
|
||
}
|
||
]
|
||
|
||
// import {
|
||
// convertToInput,
|
||
// getConfig,
|
||
// isConvertableWidget
|
||
// } from '../../../extensions/core/widgetInputs.js'
|
||
|
||
const CONVERTED_TYPE = 'converted-widget'
|
||
const GET_CONFIG = Symbol()
|
||
|
||
function getConfig (widgetName) {
|
||
const { nodeData } = this.constructor
|
||
return (
|
||
nodeData?.input?.required[widgetName] ??
|
||
nodeData?.input?.optional?.[widgetName]
|
||
)
|
||
}
|
||
|
||
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) {
|
||
hideWidget(node, widget)
|
||
|
||
const type = config[0]
|
||
|
||
// Add input and store widget config for creating on primitive node
|
||
const sz = node.size
|
||
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])])
|
||
}
|
||
|
||
export function smart_init () {
|
||
LGraphCanvas.prototype._createNodeForInput = function (
|
||
node,
|
||
widget,
|
||
inputNodeName,
|
||
inputNode_slot
|
||
) {
|
||
// console.log(node.pos)
|
||
|
||
// var widget = node.widgets.filter(w => w.name === node_widget_name)[0]
|
||
if (widget) {
|
||
// 如果有存在的,没有连线输出的,自动连,不新建
|
||
let input_node = null
|
||
|
||
Array.from(app.graph.findNodesByType(inputNodeName), n => {
|
||
var links = n.outputs.filter(o => o.name === inputNode_slot)[0].links
|
||
// console.log(links)
|
||
if (!links || links?.length === 0) input_node = n
|
||
})
|
||
// 新建
|
||
if (!input_node) {
|
||
input_node = LiteGraph.createNode(inputNodeName)
|
||
input_node.pos = [node.pos[0] - node.size[0] - 24, node.pos[1] - 48]
|
||
app.canvas.graph.add(input_node, false)
|
||
} else {
|
||
input_node.pos = [node.pos[0] - node.size[0] - 24, node.pos[1] - 48]
|
||
}
|
||
|
||
const config = getConfig.call(node, widget.name) ?? [
|
||
widget.type,
|
||
widget.options || {}
|
||
]
|
||
let node_slotType = config[0]
|
||
// 如果input没有,则创建
|
||
if (!node.inputs?.filter(inp => inp.name === widget.name)[0]||!node.inputs)
|
||
convertToInput(node, widget, config)
|
||
input_node.connectByType(inputNode_slot, node, node_slotType)
|
||
}
|
||
}
|
||
|
||
LGraphCanvas.prototype._createNodeForOutput = function (
|
||
node,
|
||
widget,
|
||
outputNodeName,
|
||
outputNode_slot
|
||
) {
|
||
if (widget) {
|
||
let output_node
|
||
Array.from(app.graph.findNodesByType(outputNodeName), n => {
|
||
var links = n.inputs.filter(o => o.name === outputNode_slot)[0].links
|
||
// console.log(links)
|
||
if (!links || links?.length === 0) output_node = n
|
||
})
|
||
console.log('output_node', output_node, widget.name)
|
||
|
||
if (!output_node) {
|
||
// 新建
|
||
output_node = LiteGraph.createNode(outputNodeName)
|
||
output_node.pos = [node.pos[0] + node.size[0] + 24, node.pos[1] - 48]
|
||
app.canvas.graph.add(output_node, false)
|
||
} else {
|
||
output_node.pos = [node.pos[0] + node.size[0] + 24, node.pos[1] - 48]
|
||
}
|
||
|
||
const config = getConfig.call(node, widget.name) ?? [
|
||
widget.type,
|
||
widget.options || {}
|
||
]
|
||
let node_slotType = config[0]
|
||
console.log(node_slotType, output_node, outputNode_slot)
|
||
let type = output_node.inputs.filter(
|
||
inp => inp.name == outputNode_slot
|
||
)[0].type
|
||
node.connectByType(node_slotType, output_node, type)
|
||
}
|
||
}
|
||
}
|
||
|
||
export function addSmartMenu (options, node) {
|
||
let sopts = []
|
||
|
||
for (const sc of smart_connect_config_input) {
|
||
// 有智能推荐,则出现
|
||
if (node.type === sc.node_type) {
|
||
// console.log('smart',node)
|
||
// 则出现 randomPrompt
|
||
// CLIPTextEncode 的widget ,name== 'text'
|
||
let node_widget_name = sc.node_widget_name
|
||
let widget = node.widgets.filter(w => w.name === node_widget_name)[0]
|
||
if (!widget) {
|
||
// 控件没有,则查找inputs
|
||
widget = node.inputs.filter(w => w.name === node_widget_name)[0]
|
||
}
|
||
|
||
let isLinkNull = true
|
||
// 如果input里已经有,但是link为空
|
||
if (node.inputs?.filter(inp => inp.name === node_widget_name)[0]) {
|
||
isLinkNull =
|
||
node.inputs.filter(inp => inp.name === node_widget_name)[0].link ===
|
||
null
|
||
}
|
||
|
||
if (widget && isLinkNull) {
|
||
sopts.push({
|
||
content: sc.inputNodeName.split('_')[0] + '➡️',
|
||
callback: () => {
|
||
LGraphCanvas.prototype._createNodeForInput(
|
||
node, //当前node
|
||
widget, //当前node里需要自动连线的widget
|
||
sc.inputNodeName, //作为input的node type
|
||
sc.inputNode_output_name // 作为input的node的outputs的name. the input slot type of the target node
|
||
)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
for (const sc of smart_connect_config_output) {
|
||
if (node.type === sc.node_type) {
|
||
let node_output_name = sc.node_output_name
|
||
const widget = node.outputs.filter(w => w.name === node_output_name)[0]
|
||
|
||
let isLinkNull = true
|
||
// 如果output里 link为空
|
||
if (node.outputs?.filter(inp => inp.name === node_output_name)[0]) {
|
||
isLinkNull =
|
||
node.outputs.filter(inp => inp.name === node_output_name)[0].links
|
||
?.length === 0
|
||
if (!node.outputs.filter(inp => inp.name === node_output_name)[0].links)
|
||
isLinkNull = true
|
||
}
|
||
|
||
if (widget && isLinkNull) {
|
||
sopts.push({
|
||
content: '➡️' + sc.outputNodeName.split('_')[0],
|
||
callback: () => {
|
||
LGraphCanvas.prototype._createNodeForOutput(
|
||
node, //当前node
|
||
widget, //当前node里需要自动连线的widget
|
||
sc.outputNodeName, //作为input的node type
|
||
sc.outputNode_input_name // 作为input的node的outputs的name. the input slot type of the target node
|
||
)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
if (sopts.length > 0) options = [...sopts, null, ...options]
|
||
|
||
return options
|
||
}
|