Image and radio widgets

This commit is contained in:
space-nuko
2023-05-08 01:25:10 -05:00
parent b53d04286b
commit 584119433d
17 changed files with 332 additions and 94 deletions

View File

@@ -1,21 +1,13 @@
import { LiteGraph, type ContextMenuItem, type LGraphNode, type Vector2, LConnectionKind, LLink, LGraphCanvas, type SlotType, TitleMode, type SlotLayout, BuiltInSlotType, type ITextWidget, type SerializedLGraphNode, NodeMode, type IToggleWidget } from "@litegraph-ts/core";
import ComfyGraphNode from "./ComfyGraphNode";
import { Watch } from "@litegraph-ts/nodes-basic";
import type { SerializedPrompt } from "$lib/components/ComfyApp";
import { toast } from '@zerodevx/svelte-toast'
import type { GalleryOutput } from "./ComfyWidgetNodes";
import { get } from "svelte/store";
import queueState from "$lib/stores/queueState";
import notify from "$lib/notify";
import layoutState from "$lib/stores/layoutState";
export interface ComfyQueueEventsProperties extends Record<any, any> {
}
import queueState from "$lib/stores/queueState";
import { BuiltInSlotType, LiteGraph, NodeMode, type ITextWidget, type IToggleWidget, type SerializedLGraphNode, type SlotLayout } from "@litegraph-ts/core";
import { get } from "svelte/store";
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode";
import type { GalleryOutput } from "./ComfyWidgetNodes";
export class ComfyQueueEvents extends ComfyGraphNode {
override properties: ComfyQueueEventsProperties = {
}
static slotLayout: SlotLayout = {
outputs: [
{ name: "beforeQueued", type: BuiltInSlotType.EVENT },
@@ -57,7 +49,7 @@ LiteGraph.registerNodeType({
type: "actions/queue_events"
})
export interface ComfyStoreImagesActionProperties extends Record<any, any> {
export interface ComfyStoreImagesActionProperties extends ComfyGraphNodeProperties {
images: GalleryOutput | null
}
@@ -96,13 +88,14 @@ LiteGraph.registerNodeType({
type: "actions/store_images"
})
export interface ComfyCopyActionProperties extends Record<any, any> {
export interface ComfyCopyActionProperties extends ComfyGraphNodeProperties {
value: any
}
export class ComfyCopyAction extends ComfyGraphNode {
override properties: ComfyCopyActionProperties = {
value: null
value: null,
tags: []
}
static slotLayout: SlotLayout = {
@@ -148,7 +141,7 @@ LiteGraph.registerNodeType({
type: "actions/copy"
})
export interface ComfySwapActionProperties extends Record<any, any> {
export interface ComfySwapActionProperties extends ComfyGraphNodeProperties {
}
export class ComfySwapAction extends ComfyGraphNode {
@@ -182,13 +175,14 @@ LiteGraph.registerNodeType({
type: "actions/swap"
})
export interface ComfyNotifyActionProperties extends Record<any, any> {
export interface ComfyNotifyActionProperties extends ComfyGraphNodeProperties {
message: string
}
export class ComfyNotifyAction extends ComfyGraphNode {
override properties: ComfyNotifyActionProperties = {
message: "Nya."
message: "Nya.",
tags: []
}
static slotLayout: SlotLayout = {
@@ -213,7 +207,7 @@ LiteGraph.registerNodeType({
type: "actions/notify"
})
export interface ComfyExecuteSubgraphActionProperties extends Record<any, any> {
export interface ComfyExecuteSubgraphActionProperties extends ComfyGraphNodeProperties {
tag: string | null,
}
@@ -253,7 +247,7 @@ LiteGraph.registerNodeType({
type: "actions/execute_subgraph"
})
export interface ComfySetNodeModeActionProperties extends Record<any, any> {
export interface ComfySetNodeModeActionProperties extends ComfyGraphNodeProperties {
targetTags: string,
enable: boolean,
}
@@ -261,7 +255,8 @@ export interface ComfySetNodeModeActionProperties extends Record<any, any> {
export class ComfySetNodeModeAction extends ComfyGraphNode {
override properties: ComfySetNodeModeActionProperties = {
targetTags: "",
enable: false
enable: false,
tags: []
}
static slotLayout: SlotLayout = {

View File

@@ -17,7 +17,15 @@ export type DefaultWidgetLayout = {
inputs?: Record<number, DefaultWidgetSpec>,
}
export interface ComfyGraphNodeProperties extends Record<string, any> {
tags: string[]
}
export default class ComfyGraphNode extends LGraphNode {
override properties: ComfyGraphNodeProperties = {
tags: []
}
isBackendNode?: boolean;
beforeQueued?(subgraph: string | null): void;
@@ -58,6 +66,11 @@ export default class ComfyGraphNode extends LGraphNode {
return null;
}
constructor(title?: string) {
super(title)
this.addProperty("tags", [], "array")
}
private inheritSlotTypes(type: LConnectionKind, isConnected: boolean) {
// Prevent multiple connections to different types when we have no input
if (isConnected && type === LConnectionKind.OUTPUT) {
@@ -261,6 +274,7 @@ export default class ComfyGraphNode extends LGraphNode {
comfyInput.defaultWidgetNode = widgetNode.class as any
}
}
this.saveUserState = (o as any).saveUserState;
if (this.saveUserState == null)
this.saveUserState = true

View File

@@ -1,8 +1,8 @@
import { BuiltInSlotType, LiteGraph, type ITextWidget, type SlotLayout, clamp, type PropertyLayout, type IComboWidget } from "@litegraph-ts/core";
import ComfyGraphNode from "./ComfyGraphNode";
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode";
import type { GalleryOutput } from "./ComfyWidgetNodes";
export interface ComfyImageCacheNodeProperties extends Record<any, any> {
export interface ComfyImageCacheNodeProperties extends ComfyGraphNodeProperties {
images: GalleryOutput | null,
index: number,
filenames: Record<number, { filename: string | null, status: ImageCacheState }>,
@@ -18,6 +18,7 @@ type ImageCacheState = "none" | "uploading" | "failed" | "cached"
*/
export default class ComfyImageCacheNode extends ComfyGraphNode {
override properties: ComfyImageCacheNodeProperties = {
tags: [],
images: null,
index: 0,
filenames: {},

View File

@@ -1,8 +1,8 @@
import { BuiltInSlotType, LiteGraph, NodeMode, type INodeInputSlot, type SlotLayout, type INodeOutputSlot, LLink, LConnectionKind, type ITextWidget } from "@litegraph-ts/core";
import ComfyGraphNode from "./ComfyGraphNode";
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode";
import { Watch } from "@litegraph-ts/nodes-basic";
export interface ComfyPickFirstNodeProperties extends Record<any, any> {
export interface ComfyPickFirstNodeProperties extends ComfyGraphNodeProperties {
acceptNullLinkData: boolean
}
@@ -19,6 +19,7 @@ function nextLetter(s: string): string {
export default class ComfyPickFirstNode extends ComfyGraphNode {
override properties: ComfyPickFirstNodeProperties = {
tags: [],
acceptNullLinkData: false
}
@@ -136,10 +137,12 @@ export default class ComfyPickFirstNode extends ComfyGraphNode {
if (this.isValidLink(link)) {
// Copy frontend-only inputs.
const node = this.getInputNode(index);
if (node != null && !(node as any).isBackendNode) {
if (node != null) {
this.selected = index;
this.displayWidget.value = Watch.toString(link.data)
this.setOutputData(0, link.data)
if (!(node as any).isBackendNode) {
this.displayWidget.value = Watch.toString(link.data)
this.setOutputData(0, link.data)
}
return
}
}

View File

@@ -1,7 +1,7 @@
import { LiteGraph, type ContextMenuItem, type LGraphNode, type Vector2, LConnectionKind, LLink, LGraphCanvas, type SlotType, TitleMode, type SlotLayout, NodeMode } from "@litegraph-ts/core";
import ComfyGraphNode from "./ComfyGraphNode";
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode";
export interface ComfyRerouteProperties extends Record<any, any> {
export interface ComfyRerouteProperties extends ComfyGraphNodeProperties {
showOutputText: boolean;
horizontal: boolean;
}
@@ -22,6 +22,7 @@ export default class ComfyReroute extends ComfyGraphNode {
override collapsable: boolean = false;
override properties: ComfyRerouteProperties = {
tags: [],
showOutputText: ComfyReroute.defaultVisibility,
horizontal: false
}

View File

@@ -1,12 +1,13 @@
import { BuiltInSlotType, LConnectionKind, LLink, LiteGraph, NodeMode, type INodeInputSlot, type SlotLayout, type INodeOutputSlot } from "@litegraph-ts/core";
import ComfyGraphNode from "./ComfyGraphNode";
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode";
export interface ComfySelectorProperties extends Record<any, any> {
export interface ComfySelectorProperties extends ComfyGraphNodeProperties {
value: any
}
export default class ComfySelector extends ComfyGraphNode {
override properties: ComfySelectorProperties = {
tags: [],
value: null
}
@@ -78,12 +79,13 @@ LiteGraph.registerNodeType({
type: "utils/selector"
})
export interface ComfySelectorTwoProperties extends Record<any, any> {
export interface ComfySelectorTwoProperties extends ComfyGraphNodeProperties {
value: any
}
export class ComfySelectorTwo extends ComfyGraphNode {
override properties: ComfySelectorTwoProperties = {
tags: [],
value: null
}

View File

@@ -1,10 +1,10 @@
import { BuiltInSlotType, LiteGraph, type SlotLayout } from "@litegraph-ts/core";
import ComfyGraphNode, { type DefaultWidgetLayout } from "./ComfyGraphNode";
import ComfyGraphNode, { type ComfyGraphNodeProperties, type DefaultWidgetLayout } from "./ComfyGraphNode";
import { clamp } from "$lib/utils";
import ComboWidget from "$lib/widgets/ComboWidget.svelte";
import { ComfyComboNode } from "./ComfyWidgetNodes";
export interface ComfyValueControlProperties extends Record<any, any> {
export interface ComfyValueControlProperties extends ComfyGraphNodeProperties {
value: any,
action: "fixed" | "increment" | "decrement" | "randomize",
min: number,
@@ -16,6 +16,7 @@ const INT_MAX = 1125899906842624;
export default class ComfyValueControl extends ComfyGraphNode {
override properties: ComfyValueControlProperties = {
tags: [],
value: null,
action: "fixed",
min: -INT_MAX,

View File

@@ -1,21 +1,34 @@
import { LiteGraph, type ContextMenuItem, type LGraphNode, type Vector2, LConnectionKind, LLink, LGraphCanvas, type SlotType, TitleMode, type SlotLayout, LGraph, type INodeInputSlot, type ITextWidget, type INodeOutputSlot, type SerializedLGraphNode, BuiltInSlotType, type PropertyLayout, type IComboWidget, NodeMode } from "@litegraph-ts/core";
import ComfyGraphNode from "./ComfyGraphNode";
import { LiteGraph, type ContextMenuItem, type LGraphNode, type Vector2, LConnectionKind, LLink, LGraphCanvas, type SlotType, TitleMode, type SlotLayout, LGraph, type INodeInputSlot, type ITextWidget, type INodeOutputSlot, type SerializedLGraphNode, BuiltInSlotType, type PropertyLayout, type IComboWidget, NodeMode, type INumberWidget } from "@litegraph-ts/core";
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode";
import type { SvelteComponentDev } from "svelte/internal";
import { Watch } from "@litegraph-ts/nodes-basic";
import type IComfyInputSlot from "$lib/IComfyInputSlot";
import { writable, type Unsubscriber, type Writable, get } from "svelte/store";
import { clamp, convertComfyOutputToGradio, range } from "$lib/utils"
import layoutState from "$lib/stores/layoutState";
import type { FileData as GradioFileData } from "@gradio/upload";
import queueState from "$lib/stores/queueState";
import ComboWidget from "$lib/widgets/ComboWidget.svelte";
import RangeWidget from "$lib/widgets/RangeWidget.svelte";
import TextWidget from "$lib/widgets/TextWidget.svelte";
import GalleryWidget from "$lib/widgets/GalleryWidget.svelte";
import ButtonWidget from "$lib/widgets/ButtonWidget.svelte";
import CheckboxWidget from "$lib/widgets/CheckboxWidget.svelte";
import type { SvelteComponentDev } from "svelte/internal";
import { Watch } from "@litegraph-ts/nodes-basic";
import type IComfyInputSlot from "$lib/IComfyInputSlot";
import { writable, type Unsubscriber, type Writable, get } from "svelte/store";
import { clamp, range } from "$lib/utils"
import layoutState from "$lib/stores/layoutState";
import type { FileData as GradioFileData } from "@gradio/upload";
import queueState from "$lib/stores/queueState";
import RadioWidget from "$lib/widgets/RadioWidget.svelte";
export interface ComfyWidgetProperties extends Record<string, any> {
/*
* NOTE: If you want to add a new widget but it has the same input/output type
* as another one of the existing widgets, best to create a new "variant" of
* that widget instead.
*
* - Go to layoutState, look for `ALL_ATTRIBUTES,` insert or find a "variant"
* attribute and set `validNodeTypes` to the type of the litegraph node
* - Add a new entry in the `values` array, like "knob" or "dial" for ComfySliderWidget
* - Add an {#if widget.attrs.variant === <...>} statement in the corresponding Svelte component
*/
export interface ComfyWidgetProperties extends ComfyGraphNodeProperties {
defaultValue: any
}
@@ -98,9 +111,9 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
this.notifyPropsChanged();
// Also need to notify the parent container since it's what controls the
// hidden state of the widget
const layoutEntry = layoutState.findLayoutEntryForNode(this.id)
if (layoutEntry && layoutEntry.parent)
layoutEntry.parent.attrsChanged.set(get(layoutEntry.parent.attrsChanged) + 1)
// const layoutEntry = layoutState.findLayoutEntryForNode(this.id)
// if (layoutEntry && layoutEntry.parent)
// layoutEntry.parent.attrsChanged.set(get(layoutEntry.parent.attrsChanged) + 1)
return result;
}
@@ -131,7 +144,7 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
/*
* Logic to run if this widget can be treated as output (slider, combo, text)
*/
override onExecute() {
override onExecute(param: any, options: object) {
if (this.copyFromInputLink) {
if (this.inputs.length >= this.inputIndex) {
const data = this.getInputData(this.inputIndex)
@@ -186,6 +199,7 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
}
notifyPropsChanged() {
console.debug("propsChanged", this)
this.propsChanged.set(get(this.propsChanged) + 1)
}
@@ -248,6 +262,7 @@ export interface ComfySliderProperties extends ComfyWidgetProperties {
export class ComfySliderNode extends ComfyWidgetNode<number> {
override properties: ComfySliderProperties = {
tags: [],
defaultValue: 0,
min: 0,
max: 10,
@@ -312,6 +327,7 @@ export interface ComfyComboProperties extends ComfyWidgetProperties {
export class ComfyComboNode extends ComfyWidgetNode<string> {
override properties: ComfyComboProperties = {
tags: [],
defaultValue: "A",
values: ["A", "B", "C", "D"]
}
@@ -404,6 +420,7 @@ export interface ComfyTextProperties extends ComfyWidgetProperties {
export class ComfyTextNode extends ComfyWidgetNode<string> {
override properties: ComfyTextProperties = {
tags: [],
defaultValue: "",
multiline: false
}
@@ -462,6 +479,7 @@ export interface ComfyGalleryProperties extends ComfyWidgetProperties {
export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
override properties: ComfyGalleryProperties = {
tags: [],
defaultValue: [],
index: 0,
updateMode: "replace"
@@ -514,7 +532,7 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
const data = param as GalleryOutput
console.debug("[ComfyGalleryNode] Received output!", data)
const galleryItems: GradioFileData[] = this.convertItems(data)
const galleryItems: GradioFileData[] = convertComfyOutputToGradio(data)
if (this.properties.updateMode === "append") {
const currentValue = get(this.value)
@@ -532,18 +550,6 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
return `Images: ${value?.length || 0}`
}
private convertItems(output: GalleryOutput): GradioFileData[] {
return output.images.map(r => {
// TODO configure backend URL
const url = `http://${location.hostname}:8188` // TODO make configurable
const params = new URLSearchParams(r)
return {
name: null,
data: url + "/view?" + params
}
});
}
override setValue(value: any) {
if (Array.isArray(value)) {
super.setValue(value)
@@ -572,6 +578,7 @@ export interface ComfyButtonProperties extends ComfyWidgetProperties {
export class ComfyButtonNode extends ComfyWidgetNode<boolean> {
override properties: ComfyButtonProperties = {
tags: [],
defaultValue: false,
param: "bang"
}
@@ -614,6 +621,7 @@ export interface ComfyCheckboxProperties extends ComfyWidgetProperties {
export class ComfyCheckboxNode extends ComfyWidgetNode<boolean> {
override properties: ComfyCheckboxProperties = {
tags: [],
defaultValue: false,
}
@@ -646,3 +654,63 @@ LiteGraph.registerNodeType({
desc: "Checkbox that stores a boolean value",
type: "ui/checkbox"
})
export interface ComfyRadioProperties extends ComfyWidgetProperties {
choices: string[]
}
export class ComfyRadioNode extends ComfyWidgetNode<string> {
override properties: ComfyRadioProperties = {
tags: [],
choices: ["Choice A", "Choice B", "Choice C"],
defaultValue: "Choice A",
}
static slotLayout: SlotLayout = {
outputs: [
{ name: "value", type: "string" },
{ name: "index", type: "number" },
{ name: "changed", type: BuiltInSlotType.EVENT },
]
}
override svelteComponentType = RadioWidget;
override defaultValue = "";
override changedIndex = 2;
indexWidget: INumberWidget;
index = 0;
constructor(name?: string) {
super(name, "Choice A")
this.indexWidget = this.addWidget("number", "Index", this.index)
this.indexWidget.disabled = true;
}
override onExecute(param: any, options: object) {
super.onExecute(param, options);
this.setOutputData(1, this.index)
}
override setValue(value: string) {
const index = this.properties.choices.indexOf(value)
if (index == -1)
return;
this.index = index;
this.indexWidget.value = index;
const changed = value != get(this.value);
super.setValue(value)
if (changed)
this.triggerSlot(2, { value: value, index: index })
}
}
LiteGraph.registerNodeType({
class: ComfyRadioNode,
title: "UI.Radio",
desc: "Radio that outputs a string and index",
type: "ui/radio"
})