If loading from API JSON manually inspect the loaded data and set widgets since ComfyUI can't automatically. Fixes #564

This commit is contained in:
rgthree
2025-08-19 21:21:51 -04:00
parent e5b2772686
commit 110e4ef1db
7 changed files with 92 additions and 17 deletions
+2 -2
View File
@@ -78,7 +78,7 @@ export class PowerPrompt {
}
return (
this.configuring ||
rgthree.loadingApiJson ||
!!rgthree.loadingApiJson ||
(canConnect && !this.node.inputs[inputIndex]!.disabled)
);
};
@@ -103,7 +103,7 @@ export class PowerPrompt {
}
return (
this.configuring ||
rgthree.loadingApiJson ||
!!rgthree.loadingApiJson ||
(canConnect && !this.node.outputs[outputIndex]!.disabled)
);
};
+42 -3
View File
@@ -9,7 +9,7 @@ import type {
ICustomWidget,
CanvasPointerEvent,
} from "@comfyorg/frontend";
import type {ComfyNodeDef} from "typings/comfy.js";
import type {ComfyApiFormat, ComfyNodeDef} from "typings/comfy.js";
import type {RgthreeModelInfo} from "typings/rgthree.js";
import {app} from "scripts/app.js";
@@ -74,6 +74,39 @@ class RgthreePowerLoraLoader extends RgthreeBaseServerNode {
// Prefetch loras list.
rgthreeApi.getLoras();
// [🤮] If ComfyUI is loading from API JSON it doesn't pass us the actual information at all
// (like, in a `configure` call) and tries to set the widget data on its own. Unfortunately,
// since Power Lora Loader has dynamic widgets, this fails on ComfyUI's side. We can do so after
// the fact but, unfortuntely, we need to do it after a timeout since we don't have any
// information at this point to be able to tell what data we need (like, even the node id, let
// alone the actual data).
if (rgthree.loadingApiJson) {
const fullApiJson = rgthree.loadingApiJson;
setTimeout(() => {
this.configureFromApiJson(fullApiJson);
}, 16);
}
}
private configureFromApiJson(fullApiJson: ComfyApiFormat) {
if (this.id == null) {
const [n, v] = this.logger.errorParts("Cannot load from API JSON without node id.");
console[n]?.(...v);
return;
}
const nodeData =
fullApiJson[this.id] || fullApiJson[String(this.id)] || fullApiJson[Number(this.id)];
if (nodeData == null) {
const [n, v] = this.logger.errorParts(`No node found in API JSON for node id ${this.id}.`);
console[n]?.(...v);
return;
}
this.configure({
widgets_values: Object.values(nodeData.inputs).filter(
(input) => typeof (input as any)?.["lora"] === "string",
),
});
}
/**
@@ -81,10 +114,16 @@ class RgthreePowerLoraLoader extends RgthreeBaseServerNode {
* added in `onNodeCreated`, letting `super.configure` and do nothing, then create our lora
* widgets and, finally, add back in our default widgets.
*/
override configure(info: ISerialisedNode): void {
override configure(
info: ISerialisedNode | {widgets_values: ISerialisedNode["widgets_values"]},
): void {
while (this.widgets?.length) this.removeWidget(0);
this.widgetButtonSpacer = null;
super.configure(info);
// Since we may be calling into configure manually for just widgets_values setting (like, from
// API JSON) we want to only call the parent class's configure with a real ISerialisedNode data.
if ((info as ISerialisedNode).id != null) {
super.configure(info as ISerialisedNode);
}
(this as any)._tempWidth = this.size[0];
(this as any)._tempHeight = this.size[1];
+12 -4
View File
@@ -198,6 +198,10 @@ class LogSession {
return this.logParts(LogLevel.WARN, message, ...args);
}
errorParts(message?: string, ...args: any[]) {
return this.logParts(LogLevel.ERROR, message, ...args);
}
newSession(name?: string) {
return new LogSession(`${this.name}${name}`);
}
@@ -237,7 +241,11 @@ class Rgthree extends EventTarget {
monitorLinkTimeout: number | null = null;
processingQueue = false;
loadingApiJson = false;
/**
* The API Json currently being loaded, or null. Can be used as a falsy boolean to determine if
* `app.loadApiJson` is currently executing.
*/
loadingApiJson: ComfyApiFormat | null = null;
replacingReroute: NodeId | null = null;
processingMouseDown = false;
processingMouseUp = false;
@@ -698,12 +706,12 @@ class Rgthree extends EventTarget {
// Keep state for when the app is in the middle of loading from an api JSON file.
const loadApiJson = app.loadApiJson;
app.loadApiJson = async function () {
rgthree.loadingApiJson = true;
app.loadApiJson = async function(apiData: any, fileName: string) {
rgthree.loadingApiJson = apiData as ComfyApiFormat;
try {
loadApiJson.apply(app, [...arguments] as any);
} finally {
rgthree.loadingApiJson = false;
rgthree.loadingApiJson = null;
}
};