More UI improvements
This commit is contained in:
@@ -5,9 +5,9 @@ import queueState from "$lib/stores/queueState";
|
||||
import { BuiltInSlotType, LiteGraph, NodeMode, type ITextWidget, type IToggleWidget, type SerializedLGraphNode, type SlotLayout, type PropertyLayout } from "@litegraph-ts/core";
|
||||
import { get } from "svelte/store";
|
||||
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode";
|
||||
import type { ComfyWidgetNode, GalleryOutput } from "./ComfyWidgetNodes";
|
||||
import type { ComfyWidgetNode, GalleryOutput, GalleryOutputEntry } from "./ComfyWidgetNodes";
|
||||
import type { NotifyOptions } from "$lib/notify";
|
||||
import { convertComfyOutputToGradio } from "$lib/utils";
|
||||
import { convertComfyOutputToGradio, uploadImageToComfyUI, type ComfyUploadImageAPIResponse } from "$lib/utils";
|
||||
|
||||
export class ComfyQueueEvents extends ComfyGraphNode {
|
||||
static slotLayout: SlotLayout = {
|
||||
@@ -579,3 +579,83 @@ LiteGraph.registerNodeType({
|
||||
desc: "Wraps an event's parameter such that passing it into a ComfyWidgetNode's 'store' action will not trigger its 'changed' event",
|
||||
type: "events/no_change"
|
||||
})
|
||||
|
||||
export interface ComfyUploadImageActionProperties extends ComfyGraphNodeProperties {
|
||||
folderType: "output" | "temp"
|
||||
lastUploadedImageFile: string | null
|
||||
}
|
||||
|
||||
export class ComfyUploadImageAction extends ComfyGraphNode {
|
||||
override properties: ComfyUploadImageActionProperties = {
|
||||
tags: [],
|
||||
folderType: "output",
|
||||
lastUploadedImageFile: null
|
||||
}
|
||||
|
||||
static slotLayout: SlotLayout = {
|
||||
inputs: [
|
||||
{ name: "filename", type: "string" },
|
||||
{ name: "trigger", type: BuiltInSlotType.ACTION }
|
||||
],
|
||||
outputs: [
|
||||
{ name: "input_filename", type: "string" },
|
||||
{ name: "uploaded", type: BuiltInSlotType.EVENT }
|
||||
],
|
||||
}
|
||||
|
||||
private _promise = null;
|
||||
|
||||
displayWidget: ITextWidget;
|
||||
|
||||
constructor(title?: string) {
|
||||
super(title);
|
||||
this.displayWidget = this.addWidget<ITextWidget>(
|
||||
"text",
|
||||
"File",
|
||||
this.properties.lastUploadedImageFile,
|
||||
"lastUploadedImageFile"
|
||||
);
|
||||
this.displayWidget.disabled = true;
|
||||
}
|
||||
|
||||
override onExecute() {
|
||||
this.setOutputData(0, this.properties.lastUploadedImageFile)
|
||||
}
|
||||
|
||||
override onAction(action: any, param: any) {
|
||||
if (action !== "trigger" || this._promise != null)
|
||||
return;
|
||||
|
||||
const filename = this.getInputData(0)
|
||||
if (typeof filename !== "string" || !filename) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data: GalleryOutputEntry = {
|
||||
filename,
|
||||
subfolder: "",
|
||||
type: this.properties.folderType || "output"
|
||||
}
|
||||
|
||||
this._promise = uploadImageToComfyUI(data)
|
||||
.then((json: ComfyUploadImageAPIResponse) => {
|
||||
console.debug("[UploadImageAction] Succeeded", json)
|
||||
this.properties.lastUploadedImageFile = json.name;
|
||||
this.triggerSlot(1, this.properties.lastUploadedImageFile);
|
||||
this._promise = null;
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("Error uploading:", e)
|
||||
notify(`Error uploading image to ComfyUi: ${e}`, { type: "error", timeout: 10000 })
|
||||
this.properties.lastUploadedImageFile = null;
|
||||
this._promise = null;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType({
|
||||
class: ComfyUploadImageAction,
|
||||
title: "Comfy.UploadImageAction",
|
||||
desc: "Uploads an image from the specified ComfyUI folder into its input folder",
|
||||
type: "actions/store_images"
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { BuiltInSlotType, LiteGraph, type ITextWidget, type SlotLayout, clamp, type PropertyLayout, type IComboWidget, type SerializedLGraphNode } from "@litegraph-ts/core";
|
||||
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode";
|
||||
import type { GalleryOutput } from "./ComfyWidgetNodes";
|
||||
import { uploadImageToComfyUI, type ComfyUploadImageAPIResponse } from "$lib/utils";
|
||||
|
||||
export interface ComfyImageCacheNodeProperties extends ComfyGraphNodeProperties {
|
||||
images: GalleryOutput | null,
|
||||
@@ -12,10 +13,6 @@ export interface ComfyImageCacheNodeProperties extends ComfyGraphNodeProperties
|
||||
|
||||
type ImageCacheState = "none" | "uploading" | "failed" | "cached"
|
||||
|
||||
interface ComfyUploadImageAPIResponse {
|
||||
name: string
|
||||
}
|
||||
|
||||
/*
|
||||
* A node that can act as both an input and output image node by uploading
|
||||
* the output file into ComfyUI's input folder.
|
||||
@@ -174,23 +171,7 @@ export default class ComfyImageCacheNode extends ComfyGraphNode {
|
||||
this.properties.filenames[newIndex] = { filename: null, status: "uploading" }
|
||||
this.onPropertyChanged("filenames", this.properties.filenames)
|
||||
|
||||
const url = `http://${location.hostname}:8188` // TODO make configurable
|
||||
const params = new URLSearchParams(data)
|
||||
|
||||
const promise = fetch(url + "/view?" + params)
|
||||
.then((r) => r.blob())
|
||||
.then((blob) => {
|
||||
console.debug("Fetchin", url, params)
|
||||
const formData = new FormData();
|
||||
formData.append("image", blob, data.filename);
|
||||
return fetch(
|
||||
new Request(url + "/upload/image", {
|
||||
body: formData,
|
||||
method: 'POST'
|
||||
})
|
||||
)
|
||||
})
|
||||
.then((r) => r.json())
|
||||
const promise = uploadImageToComfyUI(data)
|
||||
.then((json: ComfyUploadImageAPIResponse) => {
|
||||
console.debug("Gottem", json)
|
||||
if (lastGenNumber === this.properties.genNumber) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode"
|
||||
export interface ComfyRerouteProperties extends ComfyGraphNodeProperties {
|
||||
showOutputText: boolean;
|
||||
horizontal: boolean;
|
||||
ignoreTypes: boolean;
|
||||
}
|
||||
|
||||
export default class ComfyReroute extends ComfyGraphNode {
|
||||
@@ -24,7 +25,8 @@ export default class ComfyReroute extends ComfyGraphNode {
|
||||
override properties: ComfyRerouteProperties = {
|
||||
tags: [],
|
||||
showOutputText: ComfyReroute.defaultVisibility,
|
||||
horizontal: false
|
||||
horizontal: false,
|
||||
ignoreTypes: false
|
||||
}
|
||||
|
||||
static slotLayout: SlotLayout = {
|
||||
@@ -61,6 +63,7 @@ export default class ComfyReroute extends ComfyGraphNode {
|
||||
override onConnectionsChange(type: LConnectionKind, slotIndex: number, isConnected: boolean, link: LLink, ioSlot: (INodeInputSlot | INodeOutputSlot)) {
|
||||
this.applyOrientation();
|
||||
|
||||
this.canInheritSlotTypes = !this.properties.ignoreTypes;
|
||||
super.onConnectionsChange(type, slotIndex, isConnected, link, ioSlot);
|
||||
};
|
||||
|
||||
|
||||
@@ -608,7 +608,7 @@ export type GalleryOutputEntry = {
|
||||
|
||||
export interface ComfyGalleryProperties extends ComfyWidgetProperties {
|
||||
index: number,
|
||||
updateMode: "replace" | "append"
|
||||
updateMode: "replace" | "append",
|
||||
}
|
||||
|
||||
export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
@@ -616,7 +616,7 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
tags: [],
|
||||
defaultValue: [],
|
||||
index: 0,
|
||||
updateMode: "replace"
|
||||
updateMode: "replace",
|
||||
}
|
||||
|
||||
static slotLayout: SlotLayout = {
|
||||
@@ -629,7 +629,7 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
{ name: "selected_index", type: "number" },
|
||||
{ name: "width", type: "number" },
|
||||
{ name: "height", type: "number" },
|
||||
{ name: "any_selected", type: "boolean" },
|
||||
{ name: "filename", type: "string" },
|
||||
]
|
||||
}
|
||||
|
||||
@@ -644,12 +644,15 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
override outputIndex = null;
|
||||
override changedIndex = null;
|
||||
|
||||
anyImageSelected: boolean = false;
|
||||
selectedFilename: string | null = null;
|
||||
|
||||
selectedIndexWidget: ITextWidget;
|
||||
modeWidget: IComboWidget;
|
||||
|
||||
constructor(name?: string) {
|
||||
super(name, [])
|
||||
this.selectedIndexWidget = this.addWidget("text", "Selected", String(this.properties.index), "index")
|
||||
this.selectedIndexWidget.disabled = true;
|
||||
this.modeWidget = this.addWidget("combo", "Mode", this.properties.updateMode, null, { property: "updateMode", values: ["replace", "append"] })
|
||||
}
|
||||
|
||||
@@ -662,10 +665,20 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
imageSize: Vector2 = [1, 1]
|
||||
|
||||
override onExecute() {
|
||||
this.setOutputData(0, this.properties.index)
|
||||
const index = this.properties.index;
|
||||
|
||||
this.setOutputData(0, index)
|
||||
this.setOutputData(1, this.imageSize[0])
|
||||
this.setOutputData(2, this.imageSize[1])
|
||||
this.setOutputData(3, this.anyImageSelected)
|
||||
|
||||
let filename: string | null = null;
|
||||
if (index != null) {
|
||||
const entry = get(this.value)[index];
|
||||
if (entry)
|
||||
filename = entry.name
|
||||
}
|
||||
|
||||
this.setOutputData(3, filename)
|
||||
}
|
||||
|
||||
override onAction(action: any, param: any, options: { action_call?: string }) {
|
||||
@@ -700,11 +713,8 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
}
|
||||
|
||||
override setValue(value: any, noChangedEvent: boolean = false) {
|
||||
console.warn("SETVALUE", value)
|
||||
super.setValue(value, noChangedEvent)
|
||||
|
||||
this.setProperty("index", 0)
|
||||
this.anyImageSelected = false;
|
||||
this.setProperty("index", null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -887,6 +897,9 @@ export class ComfyImageUploadNode extends ComfyWidgetNode<Array<GradioFileData>>
|
||||
}
|
||||
|
||||
static slotLayout: SlotLayout = {
|
||||
inputs: [
|
||||
{ name: "store", type: BuiltInSlotType.ACTION }
|
||||
],
|
||||
outputs: [
|
||||
{ name: "filename", type: "string" }, // TODO support batches
|
||||
{ name: "width", type: "number" },
|
||||
@@ -900,6 +913,7 @@ export class ComfyImageUploadNode extends ComfyWidgetNode<Array<GradioFileData>>
|
||||
override defaultValue = [];
|
||||
override outputIndex = null;
|
||||
override changedIndex = 3;
|
||||
override storeActionName = "store";
|
||||
override saveUserState = false;
|
||||
|
||||
imageSize: Vector2 = [1, 1];
|
||||
@@ -908,6 +922,18 @@ export class ComfyImageUploadNode extends ComfyWidgetNode<Array<GradioFileData>>
|
||||
super(name, [])
|
||||
}
|
||||
|
||||
override parseValue(value: any): GradioFileData[] {
|
||||
if (value == null)
|
||||
return []
|
||||
|
||||
if (typeof value === "string" && value !== "") { // Single filename
|
||||
return [{ name: value, data: value, orig_name: value, is_file: true }]
|
||||
}
|
||||
else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
override onExecute(param: any, options: object) {
|
||||
super.onExecute(param, options);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user