Use ComfyNodeDefImpl on NodePreview component (#228)

* store widgets

* Use node def impl
This commit is contained in:
Chenlei Hu
2024-07-25 23:15:03 -04:00
committed by GitHub
parent dc13ed102b
commit 8e1d3f3baa
4 changed files with 45 additions and 58 deletions

View File

@@ -22,7 +22,7 @@ https://github.com/Nuked88/ComfyUI-N-Sidebar/blob/7ae7da4a9761009fb6629bc04c6830
<div class="_sb_col">{{ slotInput ? slotInput.name : '' }}</div> <div class="_sb_col">{{ slotInput ? slotInput.name : '' }}</div>
<div class="_sb_col middle-column"></div> <div class="_sb_col middle-column"></div>
<div class="_sb_col _sb_inherit"> <div class="_sb_col _sb_inherit">
{{ slotOutput ? slotOutput.name : '' }} {{ slotOutput ? slotOutput.display_name : '' }}
</div> </div>
<div class="_sb_col"> <div class="_sb_col">
<div v-if="slotOutput" :class="['_sb_dot', slotOutput.type]"></div> <div v-if="slotOutput" :class="['_sb_dot', slotOutput.type]"></div>
@@ -34,7 +34,7 @@ https://github.com/Nuked88/ComfyUI-N-Sidebar/blob/7ae7da4a9761009fb6629bc04c6830
<div class="_sb_col _sb_arrow">&#x25C0;</div> <div class="_sb_col _sb_arrow">&#x25C0;</div>
<div class="_sb_col">{{ widgetInput.name }}</div> <div class="_sb_col">{{ widgetInput.name }}</div>
<div class="_sb_col middle-column"></div> <div class="_sb_col middle-column"></div>
<div class="_sb_col _sb_inherit">{{ widgetInput.defaultValue }}</div> <div class="_sb_col _sb_inherit">{{ widgetInput.default }}</div>
<div class="_sb_col _sb_arrow">&#x25B6;</div> <div class="_sb_col _sb_arrow">&#x25B6;</div>
</div> </div>
</div> </div>
@@ -45,67 +45,27 @@ https://github.com/Nuked88/ComfyUI-N-Sidebar/blob/7ae7da4a9761009fb6629bc04c6830
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { app } from '@/scripts/app' import { ComfyNodeDefImpl, useNodeDefStore } from '@/stores/nodeDefStore'
import { type ComfyNodeDef } from '@/types/apiTypes'
import _ from 'lodash' import _ from 'lodash'
import { PropType } from 'vue'
const props = defineProps({ const props = defineProps({
nodeDef: { nodeDef: {
type: Object as PropType<ComfyNodeDef>, type: ComfyNodeDefImpl,
required: true required: true
} }
}) })
const nodeDef = props.nodeDef as ComfyNodeDef const nodeDefStore = useNodeDefStore()
// -------------------------------------------------- const nodeDef = props.nodeDef
// TODO: Move out to separate file const allInputDefs = nodeDef.input.all
interface IComfyNodeInputDef { const allOutputDefs = Object.values(nodeDef.output)
name: string const slotInputDefs = allInputDefs.filter(
type: string (input) => !nodeDefStore.inputIsWidget(input)
widgetType: string | null
defaultValue: any
}
interface IComfyNodeOutputDef {
name: string | null
type: string
isList: boolean
}
const allInputs = Object.assign(
{},
nodeDef.input.required || {},
nodeDef.input.optional || {}
) )
const allInputDefs: IComfyNodeInputDef[] = Object.entries(allInputs).map( const widgetInputDefs = allInputDefs.filter((input) =>
([inputName, inputData]) => { nodeDefStore.inputIsWidget(input)
return {
name: inputName,
type: inputData[0],
widgetType: app.getWidgetType(inputData, inputName),
defaultValue:
inputData[1]?.default ||
(inputData[0] instanceof Array ? inputData[0][0] : '')
}
}
) )
const allOutputDefs: IComfyNodeOutputDef[] = _.zip(
nodeDef.output,
nodeDef.output_name || [],
nodeDef.output_is_list || []
).map(([outputType, outputName, isList]) => {
return {
name: outputName,
type: outputType instanceof Array ? 'COMBO' : outputType,
isList: isList
}
})
const slotInputDefs = allInputDefs.filter((input) => !input.widgetType)
const widgetInputDefs = allInputDefs.filter((input) => !!input.widgetType)
</script> </script>
<style scoped> <style scoped>

View File

@@ -2,7 +2,7 @@
<div class="comfy-vue-node-search-container"> <div class="comfy-vue-node-search-container">
<div class="comfy-vue-node-preview-container"> <div class="comfy-vue-node-preview-container">
<NodePreview <NodePreview
:nodeDef="hoveredSuggestion" :nodeDef="plainToClass(ComfyNodeDefImpl, hoveredSuggestion)"
:key="hoveredSuggestion?.name || ''" :key="hoveredSuggestion?.name || ''"
v-if="hoveredSuggestion" v-if="hoveredSuggestion"
/> />
@@ -62,7 +62,8 @@ import NodeSourceChip from '@/components/NodeSourceChip.vue'
import { ComfyNodeDef } from '@/types/apiTypes' import { ComfyNodeDef } from '@/types/apiTypes'
import { type FilterAndValue } from '@/services/nodeSearchService' import { type FilterAndValue } from '@/services/nodeSearchService'
import NodePreview from './NodePreview.vue' import NodePreview from './NodePreview.vue'
import { useNodeDefStore } from '@/stores/nodeDefStore' import { ComfyNodeDefImpl, useNodeDefStore } from '@/stores/nodeDefStore'
import { plainToClass } from 'class-transformer'
const props = defineProps({ const props = defineProps({
filters: { filters: {

View File

@@ -1965,10 +1965,12 @@ export class ComfyApp {
async registerNodes() { async registerNodes() {
// Load node definitions from the backend // Load node definitions from the backend
const defs = await api.getNodeDefs() const defs = await api.getNodeDefs()
if (this.vueAppReady) {
useNodeDefStore().addNodeDefs(Object.values(defs))
}
await this.registerNodesFromDefs(defs) await this.registerNodesFromDefs(defs)
if (this.vueAppReady) {
const nodeDefStore = useNodeDefStore()
nodeDefStore.addNodeDefs(Object.values(defs))
nodeDefStore.updateWidgets(this.widgets)
}
await this.#invokeExtensionsAsync('registerCustomNodes') await this.#invokeExtensionsAsync('registerCustomNodes')
} }

View File

@@ -2,6 +2,7 @@ import { NodeSearchService } from '@/services/nodeSearchService'
import { ComfyNodeDef } from '@/types/apiTypes' import { ComfyNodeDef } from '@/types/apiTypes'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { Type, Transform, plainToClass } from 'class-transformer' import { Type, Transform, plainToClass } from 'class-transformer'
import { ComfyWidgetConstructor } from '@/scripts/widgets'
export class BaseInputSpec<T = any> { export class BaseInputSpec<T = any> {
name: string name: string
@@ -124,6 +125,10 @@ export class ComfyInputsSpec {
return plainToClass(CustomInputSpec, { name, type, ...spec }) return plainToClass(CustomInputSpec, { name, type, ...spec })
} }
} }
get all() {
return [...Object.values(this.required), ...Object.values(this.optional)]
}
} }
export class ComfyOutputSpec { export class ComfyOutputSpec {
@@ -224,11 +229,13 @@ const SYSTEM_NODE_DEFS_BY_NAME = SYSTEM_NODE_DEFS.reduce((acc, nodeDef) => {
interface State { interface State {
nodeDefsByName: Record<string, ComfyNodeDef> nodeDefsByName: Record<string, ComfyNodeDef>
widgets: Record<string, ComfyWidgetConstructor>
} }
export const useNodeDefStore = defineStore('nodeDef', { export const useNodeDefStore = defineStore('nodeDef', {
state: (): State => ({ state: (): State => ({
nodeDefsByName: SYSTEM_NODE_DEFS_BY_NAME nodeDefsByName: SYSTEM_NODE_DEFS_BY_NAME,
widgets: {}
}), }),
getters: { getters: {
nodeDefs(state) { nodeDefs(state) {
@@ -246,6 +253,23 @@ export const useNodeDefStore = defineStore('nodeDef', {
for (const nodeDef of nodeDefs) { for (const nodeDef of nodeDefs) {
this.nodeDefsByName[nodeDef.name] = nodeDef this.nodeDefsByName[nodeDef.name] = nodeDef
} }
},
updateWidgets(widgets: Record<string, ComfyWidgetConstructor>) {
this.widgets = widgets
},
getWidgetType(type: string, inputName: string) {
if (type === 'COMBO') {
return 'COMBO'
} else if (`${type}:${inputName}` in this.widgets) {
return `${type}:${inputName}`
} else if (type in this.widgets) {
return type
} else {
return null
}
},
inputIsWidget(spec: BaseInputSpec) {
return this.getWidgetType(spec.type, spec.name) !== null
} }
} }
}) })