Strip user data from workflows if configured
This commit is contained in:
@@ -102,7 +102,7 @@
|
||||
if (!app?.lGraph)
|
||||
return;
|
||||
|
||||
const promptFilename = false; // TODO
|
||||
const promptFilename = true; // TODO
|
||||
|
||||
let filename = "workflow.json";
|
||||
if (promptFilename) {
|
||||
@@ -133,6 +133,7 @@
|
||||
|
||||
function loadWorkflow(): void {
|
||||
app.handleFile(fileInput.files[0]);
|
||||
fileInput.files = null;
|
||||
}
|
||||
|
||||
function doSaveLocal(): void {
|
||||
|
||||
@@ -27,7 +27,7 @@ import ComfyGraph from "$lib/ComfyGraph";
|
||||
import { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
|
||||
import { get } from "svelte/store";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import { promptToGraphVis } from "$lib/utils";
|
||||
import { promptToGraphVis, workflowToGraphVis } from "$lib/utils";
|
||||
|
||||
export const COMFYBOX_SERIAL_VERSION = 1;
|
||||
|
||||
@@ -145,9 +145,6 @@ export default class ComfyApp {
|
||||
this.resizeCanvas();
|
||||
window.addEventListener("resize", this.resizeCanvas.bind(this));
|
||||
|
||||
this.lGraph.start();
|
||||
this.lGraph.eventBus.on("afterExecute", () => this.lCanvas.draw(true))
|
||||
|
||||
this.alreadySetup = true;
|
||||
|
||||
return Promise.resolve();
|
||||
@@ -374,6 +371,9 @@ export default class ComfyApp {
|
||||
this.lCanvas.deserialize(data.canvas)
|
||||
|
||||
await this.refreshComboInNodes();
|
||||
|
||||
this.lGraph.start();
|
||||
this.lGraph.eventBus.on("afterExecute", () => this.lCanvas.draw(true))
|
||||
}
|
||||
|
||||
async initDefaultGraph() {
|
||||
@@ -606,6 +606,7 @@ export default class ComfyApp {
|
||||
'--toastBackground': 'var(--color-red-500)',
|
||||
}
|
||||
})
|
||||
console.error(promptToGraphVis(p))
|
||||
console.error("Error queuing prompt", mes, num, p)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -55,24 +55,21 @@ LiteGraph.registerNodeType({
|
||||
type: "actions/queue_events"
|
||||
})
|
||||
|
||||
export interface ComfyOnExecutedEventProperties extends Record<any, any> {
|
||||
images: GalleryOutput | null,
|
||||
filename: string | null
|
||||
export interface ComfyStoreImagesActionProperties extends Record<any, any> {
|
||||
images: GalleryOutput | null
|
||||
}
|
||||
|
||||
export class ComfyOnExecutedEvent extends ComfyGraphNode {
|
||||
override properties: ComfyOnExecutedEventProperties = {
|
||||
images: null,
|
||||
filename: null
|
||||
export class ComfyStoreImagesAction extends ComfyGraphNode {
|
||||
override properties: ComfyStoreImagesActionProperties = {
|
||||
images: null
|
||||
}
|
||||
|
||||
static slotLayout: SlotLayout = {
|
||||
inputs: [
|
||||
{ name: "images", type: "IMAGE" }
|
||||
{ name: "output", type: BuiltInSlotType.ACTION, options: { color_off: "rebeccapurple", color_on: "rebeccapurple" } }
|
||||
],
|
||||
outputs: [
|
||||
{ name: "images", type: "OUTPUT" },
|
||||
{ name: "onExecuted", type: BuiltInSlotType.EVENT },
|
||||
],
|
||||
}
|
||||
|
||||
@@ -81,20 +78,20 @@ export class ComfyOnExecutedEvent extends ComfyGraphNode {
|
||||
this.setOutputData(0, this.properties.images)
|
||||
}
|
||||
|
||||
override receiveOutput(output: any) {
|
||||
if (output && "images" in output) {
|
||||
this.setProperty("images", output as GalleryOutput)
|
||||
this.setOutputData(0, this.properties.images)
|
||||
this.triggerSlot(1, "bang")
|
||||
}
|
||||
override onAction(action: any, param: any) {
|
||||
if (action !== "store" || !param || !("images" in param))
|
||||
return;
|
||||
|
||||
this.setProperty("images", param as GalleryOutput)
|
||||
this.setOutputData(0, this.properties.images)
|
||||
}
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType({
|
||||
class: ComfyOnExecutedEvent,
|
||||
title: "Comfy.OnExecutedEvent",
|
||||
desc: "Triggers a 'bang' event when a prompt output is received.",
|
||||
type: "actions/on_executed"
|
||||
class: ComfyStoreImagesAction,
|
||||
title: "Comfy.StoreImagesAction",
|
||||
desc: "Stores images from an onExecuted callback",
|
||||
type: "actions/store_images"
|
||||
})
|
||||
|
||||
export interface ComfyCopyActionProperties extends Record<any, any> {
|
||||
|
||||
@@ -2,7 +2,9 @@ import LGraphCanvas from "@litegraph-ts/core/src/LGraphCanvas";
|
||||
import ComfyGraphNode from "./ComfyGraphNode";
|
||||
import ComfyWidgets from "$lib/widgets"
|
||||
import type { ComfyWidgetNode } from "./ComfyWidgetNodes";
|
||||
import type { SerializedLGraphNode } from "@litegraph-ts/core";
|
||||
import { BuiltInSlotType, type SerializedLGraphNode } from "@litegraph-ts/core";
|
||||
import type IComfyInputSlot from "$lib/IComfyInputSlot";
|
||||
import type { ComfyInputConfig } from "$lib/IComfyInputSlot";
|
||||
|
||||
/*
|
||||
* Base class for any node with configuration sent by the backend.
|
||||
@@ -26,7 +28,7 @@ export class ComfyBackendNode extends ComfyGraphNode {
|
||||
// It just returns a hash like { "ui": { "images": results } } internally.
|
||||
// So this will need to be hardcoded for now.
|
||||
if (["PreviewImage", "SaveImage"].indexOf(comfyClass) !== -1) {
|
||||
this.addOutput("output", "IMAGE");
|
||||
this.addOutput("onExecuted", BuiltInSlotType.EVENT, { color_off: "rebeccapurple", color_on: "rebeccapurple" });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,14 +38,19 @@ export class ComfyBackendNode extends ComfyGraphNode {
|
||||
*/
|
||||
tags: string[] = []
|
||||
|
||||
private static defaultInputConfigs: Record<string, Record<string, ComfyInputConfig>> = {}
|
||||
|
||||
private setup(nodeData: any) {
|
||||
var inputs = nodeData["input"]["required"];
|
||||
if (nodeData["input"]["optional"] != undefined) {
|
||||
inputs = Object.assign({}, nodeData["input"]["required"], nodeData["input"]["optional"])
|
||||
}
|
||||
|
||||
const config = { minWidth: 1, minHeight: 1 };
|
||||
ComfyBackendNode.defaultInputConfigs[this.type] = {}
|
||||
|
||||
for (const inputName in inputs) {
|
||||
const config = { minWidth: 1, minHeight: 1 };
|
||||
|
||||
const inputData = inputs[inputName];
|
||||
const type = inputData[0];
|
||||
|
||||
@@ -64,6 +71,9 @@ export class ComfyBackendNode extends ComfyGraphNode {
|
||||
this.addInput(inputName, type);
|
||||
}
|
||||
}
|
||||
|
||||
if ("widgetNodeType" in config)
|
||||
ComfyBackendNode.defaultInputConfigs[this.type][config.name] = config.config
|
||||
}
|
||||
|
||||
for (const o in nodeData["output"]) {
|
||||
@@ -72,39 +82,44 @@ export class ComfyBackendNode extends ComfyGraphNode {
|
||||
this.addOutput(outputName, output);
|
||||
}
|
||||
|
||||
const s = this.computeSize();
|
||||
s[0] = Math.max(config.minWidth, s[0] * 1.5);
|
||||
s[1] = Math.max(config.minHeight, s[1]);
|
||||
this.size = s;
|
||||
this.serialize_widgets = false;
|
||||
|
||||
// app.#invokeExtensionsAsync("nodeCreated", this);
|
||||
}
|
||||
|
||||
override onSerialize(o: SerializedLGraphNode) {
|
||||
super.onSerialize(o);
|
||||
(o as any).tags = this.tags
|
||||
for (const input of o.inputs) {
|
||||
// strip user-identifying data, it will be reinstantiated later
|
||||
if ((input as any).config != null) {
|
||||
(input as any).config = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override onConfigure(o: SerializedLGraphNode) {
|
||||
super.onConfigure(o);
|
||||
|
||||
this.tags = (o as any).tags || []
|
||||
|
||||
const configs = ComfyBackendNode.defaultInputConfigs[o.type]
|
||||
for (let index = 0; index < this.inputs.length; index++) {
|
||||
const input = this.inputs[index] as IComfyInputSlot
|
||||
const config = configs[input.name]
|
||||
if (config != null && index >= 0 && index < this.inputs.length) {
|
||||
if (input.config == null || Object.keys(input.config).length !== Object.keys(config).length) {
|
||||
console.error("SET", input, config)
|
||||
input.config = config
|
||||
}
|
||||
}
|
||||
else {
|
||||
input.config = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override onExecuted(outputData: any) {
|
||||
console.warn("onExecuted outputs", outputData)
|
||||
for (let index = 0; index < this.outputs.length; index++) {
|
||||
const output = this.outputs[index]
|
||||
if (output.type === "IMAGE") {
|
||||
this.setOutputData(index, outputData)
|
||||
for (const node of this.getOutputNodes(index)) {
|
||||
console.warn(node)
|
||||
if ("receiveOutput" in node) {
|
||||
const widgetNode = node as ComfyGraphNode;
|
||||
widgetNode.receiveOutput(outputData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.triggerSlot(0, outputData)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,17 @@ export default class ComfyGraphNode extends LGraphNode {
|
||||
|
||||
defaultWidgets?: DefaultWidgetLayout
|
||||
|
||||
/** Called when a backend node sends a ComfyUI output over a link */
|
||||
receiveOutput(output: any) {
|
||||
/*
|
||||
* If false, don't serialize user-set properties into the workflow.
|
||||
* Useful for removing personal information from shared workflows.
|
||||
*/
|
||||
saveUserState: boolean = true;
|
||||
|
||||
/*
|
||||
* Called to remove user-set properties from this node.
|
||||
*/
|
||||
stripUserState(o: SerializedLGraphNode) {
|
||||
o.widgets_values = []
|
||||
}
|
||||
|
||||
override onResize(size: Vector2) {
|
||||
@@ -56,6 +65,11 @@ export default class ComfyGraphNode extends LGraphNode {
|
||||
(serInput as any).defaultWidgetNode = null
|
||||
}
|
||||
}
|
||||
(o as any).saveUserState = this.saveUserState
|
||||
if (!this.saveUserState) {
|
||||
this.stripUserState(o)
|
||||
console.warn("[ComfyGraphNode] stripUserState", this, o)
|
||||
}
|
||||
}
|
||||
|
||||
override onConfigure(o: SerializedLGraphNode) {
|
||||
@@ -71,5 +85,8 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ export default class ComfyImageCacheNode extends ComfyGraphNode {
|
||||
inputs: [
|
||||
{ name: "images", type: "OUTPUT" },
|
||||
{ name: "index", type: "number" },
|
||||
{ name: "store", type: BuiltInSlotType.ACTION },
|
||||
{ name: "store", type: BuiltInSlotType.ACTION, options: { color_off: "rebeccapurple", color_on: "rebeccapurple" } },
|
||||
{ name: "clear", type: BuiltInSlotType.ACTION }
|
||||
],
|
||||
outputs: [
|
||||
@@ -204,7 +204,7 @@ export default class ComfyImageCacheNode extends ComfyGraphNode {
|
||||
}
|
||||
}
|
||||
|
||||
override onAction(action: any) {
|
||||
override onAction(action: any, param: any) {
|
||||
if (action === "clear") {
|
||||
this.setProperty("images", null)
|
||||
this.setProperty("filenames", {})
|
||||
@@ -213,12 +213,10 @@ export default class ComfyImageCacheNode extends ComfyGraphNode {
|
||||
return
|
||||
}
|
||||
|
||||
const link = this.getInputLink(0)
|
||||
|
||||
if (link.data && "images" in link.data) {
|
||||
if (param && "images" in param) {
|
||||
this.setProperty("genNumber", this.properties.genNumber + 1)
|
||||
|
||||
const output = link.data as GalleryOutput;
|
||||
const output = param as GalleryOutput;
|
||||
|
||||
if (this.properties.updateMode === "append" && this.properties.images != null) {
|
||||
const newImages = this.properties.images.images.concat(output.images)
|
||||
@@ -226,7 +224,7 @@ export default class ComfyImageCacheNode extends ComfyGraphNode {
|
||||
this.setProperty("images", this.properties.images)
|
||||
}
|
||||
else {
|
||||
this.setProperty("images", link.data as GalleryOutput)
|
||||
this.setProperty("images", param as GalleryOutput)
|
||||
this.setProperty("filenames", {})
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
||||
|
||||
copyFromInputLink: boolean = true;
|
||||
|
||||
abstract defaultValue: T;
|
||||
|
||||
/** Names of properties to add as inputs */
|
||||
// shownInputProperties: string[] = []
|
||||
|
||||
@@ -204,15 +206,21 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
||||
clampOneConfig(input: IComfyInputSlot) { }
|
||||
|
||||
override onSerialize(o: SerializedLGraphNode) {
|
||||
super.onSerialize(o);
|
||||
(o as any).comfyValue = get(this.value);
|
||||
(o as any).shownOutputProperties = this.shownOutputProperties
|
||||
super.onSerialize(o);
|
||||
}
|
||||
|
||||
override onConfigure(o: SerializedLGraphNode) {
|
||||
this.value.set((o as any).comfyValue);
|
||||
this.shownOutputProperties = (o as any).shownOutputProperties;
|
||||
}
|
||||
|
||||
override stripUserState(o: SerializedLGraphNode) {
|
||||
super.stripUserState(o);
|
||||
(o as any).comfyValue = this.defaultValue;
|
||||
o.properties.defaultValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ComfySliderProperties extends ComfyWidgetProperties {
|
||||
@@ -232,6 +240,7 @@ export class ComfySliderNode extends ComfyWidgetNode<number> {
|
||||
}
|
||||
|
||||
override svelteComponentType = RangeWidget
|
||||
override defaultValue = 0;
|
||||
|
||||
static slotLayout: SlotLayout = {
|
||||
inputs: [
|
||||
@@ -303,6 +312,7 @@ export class ComfyComboNode extends ComfyWidgetNode<string> {
|
||||
}
|
||||
|
||||
override svelteComponentType = ComboWidget
|
||||
override defaultValue = "A";
|
||||
|
||||
constructor(name?: string) {
|
||||
super(name, "A")
|
||||
@@ -346,13 +356,20 @@ export class ComfyComboNode extends ComfyWidgetNode<string> {
|
||||
}
|
||||
|
||||
override clampOneConfig(input: IComfyInputSlot) {
|
||||
if (input.config.values.indexOf(this.properties.value) === -1) {
|
||||
if (!input.config.values)
|
||||
this.setValue("")
|
||||
else if (input.config.values.indexOf(this.properties.value) === -1) {
|
||||
if (input.config.values.length === 0)
|
||||
this.setValue("")
|
||||
else
|
||||
this.setValue(input.config.defaultValue || input.config.values[0])
|
||||
}
|
||||
}
|
||||
|
||||
override stripUserState(o: SerializedLGraphNode) {
|
||||
super.stripUserState(o);
|
||||
o.properties.values = []
|
||||
}
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType({
|
||||
@@ -384,6 +401,7 @@ export class ComfyTextNode extends ComfyWidgetNode<string> {
|
||||
}
|
||||
|
||||
override svelteComponentType = TextWidget
|
||||
override defaultValue = "";
|
||||
|
||||
constructor(name?: string) {
|
||||
super(name, "")
|
||||
@@ -433,7 +451,7 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
static slotLayout: SlotLayout = {
|
||||
inputs: [
|
||||
{ name: "images", type: "OUTPUT" },
|
||||
{ name: "store", type: BuiltInSlotType.ACTION },
|
||||
{ name: "store", type: BuiltInSlotType.ACTION, options: { color_off: "rebeccapurple", color_on: "rebeccapurple" } },
|
||||
{ name: "clear", type: BuiltInSlotType.ACTION }
|
||||
],
|
||||
outputs: [
|
||||
@@ -446,6 +464,7 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
]
|
||||
|
||||
override svelteComponentType = GalleryWidget
|
||||
override defaultValue = []
|
||||
override copyFromInputLink = false;
|
||||
override outputIndex = null;
|
||||
override changedIndex = null;
|
||||
@@ -472,12 +491,11 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
this.setValue([])
|
||||
}
|
||||
else if (action === "store") {
|
||||
const link = this.getInputLink(0)
|
||||
if (link.data && "images" in link.data) {
|
||||
const data = link.data as GalleryOutput
|
||||
if (param && "images" in param) {
|
||||
const data = param as GalleryOutput
|
||||
console.debug("[ComfyGalleryNode] Received output!", data)
|
||||
|
||||
const galleryItems: GradioFileData[] = this.convertItems(link.data)
|
||||
const galleryItems: GradioFileData[] = this.convertItems(data)
|
||||
|
||||
if (this.properties.updateMode === "append") {
|
||||
const currentValue = get(this.value)
|
||||
@@ -546,8 +564,13 @@ export class ComfyButtonNode extends ComfyWidgetNode<boolean> {
|
||||
]
|
||||
}
|
||||
|
||||
override outputIndex = 1;
|
||||
override svelteComponentType = ButtonWidget;
|
||||
override defaultValue = false;
|
||||
override outputIndex = 1;
|
||||
|
||||
constructor(name?: string) {
|
||||
super(name, false)
|
||||
}
|
||||
|
||||
override setValue(value: any) {
|
||||
super.setValue(Boolean(value))
|
||||
@@ -558,10 +581,6 @@ export class ComfyButtonNode extends ComfyWidgetNode<boolean> {
|
||||
this.triggerSlot(0, this.properties.param);
|
||||
this.setValue(false) // TODO onRelease
|
||||
}
|
||||
|
||||
constructor(name?: string) {
|
||||
super(name, false)
|
||||
}
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType({
|
||||
@@ -587,6 +606,7 @@ export class ComfyCheckboxNode extends ComfyWidgetNode<boolean> {
|
||||
}
|
||||
|
||||
override svelteComponentType = CheckboxWidget;
|
||||
override defaultValue = false;
|
||||
|
||||
override setValue(value: any) {
|
||||
value = Boolean(value)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export { default as ComfyReroute } from "./ComfyReroute"
|
||||
export { ComfyWidgetNode, ComfySliderNode, ComfyComboNode, ComfyTextNode } from "./ComfyWidgetNodes"
|
||||
export { ComfyQueueEvents, ComfyCopyAction, ComfySwapAction, ComfyNotifyAction, ComfyOnExecutedEvent, ComfyExecuteSubgraphAction } from "./ComfyActionNodes"
|
||||
export { ComfyQueueEvents, ComfyCopyAction, ComfySwapAction, ComfyNotifyAction, ComfyStoreImagesAction, ComfyExecuteSubgraphAction } from "./ComfyActionNodes"
|
||||
export { default as ComfyValueControl } from "./ComfyValueControl"
|
||||
export { default as ComfySelector } from "./ComfySelector"
|
||||
export { default as ComfyImageCacheNode } from "./ComfyImageCacheNode"
|
||||
|
||||
@@ -381,6 +381,13 @@ const ALL_ATTRIBUTES: AttributesSpecList = [
|
||||
serialize: serializeStringArray,
|
||||
deserialize: deserializeStringArray
|
||||
},
|
||||
{
|
||||
name: "saveUserState",
|
||||
type: "boolean",
|
||||
location: "nodeVars",
|
||||
editable: true,
|
||||
defaultValue: true,
|
||||
},
|
||||
|
||||
// Range
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user