| 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' |
| }, |
| { |
| node_type: 'TripoSRSampler_', |
| node_widget_name: 'image', |
| inputNodeName: 'LoadImagesToBatch', |
| inputNode_output_name: 'IMAGE' |
| }, |
| { |
| node_type: 'TripoSRSampler_', |
| node_widget_name: 'mask', |
| inputNodeName: 'RembgNode_Mix', |
| inputNode_output_name: 'masks' |
| } |
| ] |
|
|
| 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: 'VAEDecode', |
| node_output_name: 'IMAGE', |
| outputNodeName: 'AppInfo', |
| outputNode_input_name: 'IMAGE' |
| }, |
| { |
| node_type: 'VAEDecode', |
| node_output_name: 'IMAGE', |
| outputNodeName: 'SaveImageAndMetadata_', |
| outputNode_input_name: 'images' |
| }, |
| { |
| node_type: 'Moondream', |
| node_output_name: 'STRING', |
| outputNodeName: 'ShowTextForGPT', |
| outputNode_input_name: 'text' |
| } |
| ] |
|
|
| |
| |
| |
| |
| |
|
|
| 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] |
| widget.type = CONVERTED_TYPE + suffix |
| widget.serializeValue = () => { |
| |
| 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 |
| } |
|
|
| |
| 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] |
|
|
| |
| 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 |
| } |
|
|
| |
| 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 |
| ) { |
| |
|
|
| |
| 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 |
| |
| 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] |
| |
| 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 |
| |
| 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) { |
| |
| |
| |
| let node_widget_name = sc.node_widget_name |
| let widget = node.widgets.filter(w => w.name === node_widget_name)[0] |
| if (!widget) { |
| |
| widget = node.inputs.filter(w => w.name === node_widget_name)[0] |
| } |
|
|
| let isLinkNull = true |
| |
| 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, |
| widget, |
| sc.inputNodeName, |
| sc.inputNode_output_name |
| ) |
| } |
| }) |
| } |
| } |
| } |
|
|
| 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 |
| |
| 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, |
| widget, |
| sc.outputNodeName, |
| sc.outputNode_input_name |
| ) |
| } |
| }) |
| } |
| } |
| } |
|
|
| if (sopts.length > 0) options = [...sopts, null, ...options] |
|
|
| return options |
| } |
|
|