Properly implement ComfyNodeDef interface (#1821)

* nit

* Properly implement ComfyNodeDef interface

* nit

* Mark readonly
This commit is contained in:
Chenlei Hu
2024-12-06 09:00:15 -08:00
committed by GitHub
parent aa68422e0f
commit ae26390776
6 changed files with 67 additions and 37 deletions

View File

@@ -69,7 +69,7 @@ const onIdle = () => {
) )
if (inputSlot !== -1) { if (inputSlot !== -1) {
const inputName = node.inputs[inputSlot].name const inputName = node.inputs[inputSlot].name
return showTooltip(nodeDef.input.getInput(inputName)?.tooltip) return showTooltip(nodeDef.inputs.getInput(inputName)?.tooltip)
} }
const outputSlot = canvas.isOverNodeOutput( const outputSlot = canvas.isOverNodeOutput(
@@ -79,14 +79,14 @@ const onIdle = () => {
[0, 0] [0, 0]
) )
if (outputSlot !== -1) { if (outputSlot !== -1) {
return showTooltip(nodeDef.output.all?.[outputSlot]?.tooltip) return showTooltip(nodeDef.outputs.all?.[outputSlot]?.tooltip)
} }
const widget = comfyApp.canvas.getWidgetAtCursor() const widget = comfyApp.canvas.getWidgetAtCursor()
// Dont show for DOM widgets, these use native browser tooltips as we dont get proper mouse events on these // Dont show for DOM widgets, these use native browser tooltips as we dont get proper mouse events on these
if (widget && !widget.element) { if (widget && !widget.element) {
return showTooltip( return showTooltip(
widget.tooltip ?? nodeDef.input.getInput(widget.name)?.tooltip widget.tooltip ?? nodeDef.inputs.getInput(widget.name)?.tooltip
) )
} }
} }

View File

@@ -105,8 +105,8 @@ const litegraphColors = colors ?? defaultColorPalette.colors.litegraph_base
const widgetStore = useWidgetStore() const widgetStore = useWidgetStore()
const nodeDef = props.nodeDef const nodeDef = props.nodeDef
const allInputDefs = nodeDef.input.all const allInputDefs = nodeDef.inputs.all
const allOutputDefs = nodeDef.output.all const allOutputDefs = nodeDef.outputs.all
const slotInputDefs = allInputDefs.filter( const slotInputDefs = allInputDefs.filter(
(input) => !widgetStore.inputIsWidget(input) (input) => !widgetStore.inputIsWidget(input)
) )

View File

@@ -1600,7 +1600,7 @@ export class ComfyApp {
app.canvas.getWidgetLinkType = function (widget, node) { app.canvas.getWidgetLinkType = function (widget, node) {
const nodeDefStore = useNodeDefStore() const nodeDefStore = useNodeDefStore()
const nodeDef = nodeDefStore.nodeDefsByName[node.type] const nodeDef = nodeDefStore.nodeDefsByName[node.type]
const input = nodeDef.input.getInput(widget.name) const input = nodeDef.inputs.getInput(widget.name)
return input?.type return input?.type
} }

View File

@@ -209,7 +209,7 @@ export class NodeSearchService {
/* name */ 'Input Type', /* name */ 'Input Type',
/* invokeSequence */ 'i', /* invokeSequence */ 'i',
/* longInvokeSequence */ 'input', /* longInvokeSequence */ 'input',
(node) => node.input.all.map((input) => input.type), (node) => node.inputs.all.map((input) => input.type),
data, data,
filterSearchOptions filterSearchOptions
) )
@@ -219,7 +219,7 @@ export class NodeSearchService {
/* name */ 'Output Type', /* name */ 'Output Type',
/* invokeSequence */ 'o', /* invokeSequence */ 'o',
/* longInvokeSequence */ 'output', /* longInvokeSequence */ 'output',
(node) => node.output.all.map((output) => output.type), (node) => node.outputs.all.map((output) => output.type),
data, data,
filterSearchOptions filterSearchOptions
) )

View File

@@ -5,10 +5,10 @@ import {
import { import {
type ComfyNodeDef, type ComfyNodeDef,
type ComfyInputsSpec as ComfyInputsSpecSchema, type ComfyInputsSpec as ComfyInputsSpecSchema,
type ComfyOutputTypesSpec as ComfyOutputTypesSpecSchema,
type InputSpec type InputSpec
} from '@/types/apiTypes' } from '@/types/apiTypes'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ComfyWidgetConstructor } from '@/scripts/widgets'
import { TreeNode } from 'primevue/treenode' import { TreeNode } from 'primevue/treenode'
import { buildTree } from '@/utils/treeUtil' import { buildTree } from '@/utils/treeUtil'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
@@ -149,21 +149,45 @@ export class ComfyOutputsSpec {
} }
} }
/** export class ComfyNodeDefImpl implements ComfyNodeDef {
* Note: This class does not implement the ComfyNodeDef interface, as we are // ComfyNodeDef fields
* using a custom output spec for output definitions. readonly name: string
*/ readonly display_name: string
export class ComfyNodeDefImpl { /**
name: string * Category is not marked as readonly as the bookmark system
display_name: string * needs to write to it to assign a node to a custom folder.
*/
category: string category: string
python_module: string readonly python_module: string
description: string readonly description: string
deprecated: boolean readonly deprecated: boolean
experimental: boolean readonly experimental: boolean
input: ComfyInputsSpec readonly output_node: boolean
output: ComfyOutputsSpec /**
nodeSource: NodeSource * @deprecated Use `inputs` instead
*/
readonly input: ComfyInputsSpecSchema
/**
* @deprecated Use `outputs` instead
*/
readonly output: ComfyOutputTypesSpecSchema
/**
* @deprecated Use `outputs[n].is_list` instead
*/
readonly output_is_list?: boolean[]
/**
* @deprecated Use `outputs[n].name` instead
*/
readonly output_name?: string[]
/**
* @deprecated Use `outputs[n].tooltip` instead
*/
readonly output_tooltips?: string[]
// ComfyNodeDefImpl fields
readonly inputs: ComfyInputsSpec
readonly outputs: ComfyOutputsSpec
readonly nodeSource: NodeSource
constructor(obj: ComfyNodeDef) { constructor(obj: ComfyNodeDef) {
this.name = obj.name this.name = obj.name
@@ -174,8 +198,15 @@ export class ComfyNodeDefImpl {
this.deprecated = obj.deprecated ?? obj.category === '' this.deprecated = obj.deprecated ?? obj.category === ''
this.experimental = this.experimental =
obj.experimental ?? obj.category.startsWith('_for_testing') obj.experimental ?? obj.category.startsWith('_for_testing')
this.input = new ComfyInputsSpec(obj.input ?? {}) this.output_node = obj.output_node
this.output = ComfyNodeDefImpl.transformOutputSpec(obj) this.input = obj.input ?? {}
this.output = obj.output ?? []
this.output_is_list = obj.output_is_list
this.output_name = obj.output_name
this.output_tooltips = obj.output_tooltips
this.inputs = new ComfyInputsSpec(obj.input ?? {})
this.outputs = ComfyNodeDefImpl.transformOutputSpec(obj)
this.nodeSource = getNodeSource(obj.python_module) this.nodeSource = getNodeSource(obj.python_module)
} }
@@ -284,7 +315,6 @@ export function createDummyFolderNodeDef(folderPath: string): ComfyNodeDefImpl {
export const useNodeDefStore = defineStore('nodeDef', () => { export const useNodeDefStore = defineStore('nodeDef', () => {
const nodeDefsByName = ref<Record<string, ComfyNodeDefImpl>>({}) const nodeDefsByName = ref<Record<string, ComfyNodeDefImpl>>({})
const nodeDefsByDisplayName = ref<Record<string, ComfyNodeDefImpl>>({}) const nodeDefsByDisplayName = ref<Record<string, ComfyNodeDefImpl>>({})
const widgets = ref<Record<string, ComfyWidgetConstructor>>({})
const showDeprecated = ref(false) const showDeprecated = ref(false)
const showExperimental = ref(false) const showExperimental = ref(false)

View File

@@ -171,8 +171,8 @@ describe('ComfyNodeDefImpl', () => {
expect(result.category).toBe('Testing') expect(result.category).toBe('Testing')
expect(result.python_module).toBe('test_module') expect(result.python_module).toBe('test_module')
expect(result.description).toBe('A test node') expect(result.description).toBe('A test node')
expect(result.input).toBeInstanceOf(ComfyInputsSpec) expect(result.inputs).toBeInstanceOf(ComfyInputsSpec)
expect(result.output.all).toEqual([ expect(result.outputs.all).toEqual([
{ {
index: 0, index: 0,
name: 'intOutput', name: 'intOutput',
@@ -243,7 +243,7 @@ describe('ComfyNodeDefImpl', () => {
const result = new ComfyNodeDefImpl(plainObject) const result = new ComfyNodeDefImpl(plainObject)
expect(result.output.all).toEqual([ expect(result.outputs.all).toEqual([
{ {
index: 0, index: 0,
name: 'stringOutput', name: 'stringOutput',
@@ -281,7 +281,7 @@ describe('ComfyNodeDefImpl', () => {
const result = new ComfyNodeDefImpl(plainObject) const result = new ComfyNodeDefImpl(plainObject)
expect(result.output.all).toEqual([ expect(result.outputs.all).toEqual([
{ {
index: 0, index: 0,
name: 'INT', name: 'INT',
@@ -317,7 +317,7 @@ describe('ComfyNodeDefImpl', () => {
} }
const result = new ComfyNodeDefImpl(plainObject) const result = new ComfyNodeDefImpl(plainObject)
expect(result.output.all).toEqual([ expect(result.outputs.all).toEqual([
{ {
index: 0, index: 0,
name: 'output', name: 'output',
@@ -354,7 +354,7 @@ describe('ComfyNodeDefImpl', () => {
const result = new ComfyNodeDefImpl(plainObject) const result = new ComfyNodeDefImpl(plainObject)
expect(result.output.all).toEqual([]) expect(result.outputs.all).toEqual([])
}) })
it('should handle undefined fields', () => { it('should handle undefined fields', () => {
@@ -367,8 +367,8 @@ describe('ComfyNodeDefImpl', () => {
} }
const result = new ComfyNodeDefImpl(plainObject) const result = new ComfyNodeDefImpl(plainObject)
expect(result.output.all).toEqual([]) expect(result.outputs.all).toEqual([])
expect(result.input.all).toEqual([]) expect(result.inputs.all).toEqual([])
}) })
it('should handle complex input specifications', () => { it('should handle complex input specifications', () => {
@@ -395,8 +395,8 @@ describe('ComfyNodeDefImpl', () => {
const result = new ComfyNodeDefImpl(plainObject) const result = new ComfyNodeDefImpl(plainObject)
expect(result.input).toBeInstanceOf(ComfyInputsSpec) expect(result.inputs).toBeInstanceOf(ComfyInputsSpec)
expect(result.input.required).toBeDefined() expect(result.inputs.required).toBeDefined()
expect(result.input.optional).toBeDefined() expect(result.inputs.optional).toBeDefined()
}) })
}) })