Skip to content

Commit 110e4ef

Browse files
committed
If loading from API JSON manually inspect the loaded data and set widgets since ComfyUI can't automatically. Fixes #564
1 parent e5b2772 commit 110e4ef

7 files changed

Lines changed: 92 additions & 17 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "rgthree-comfy"
33
description = "Making ComfyUI more comfortable."
4-
version = "1.0.2508182334"
4+
version = "1.0.2508192121"
55
license = { file = "LICENSE" }
66
dependencies = []
77

src_web/comfyui/base_power_prompt.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export class PowerPrompt {
7878
}
7979
return (
8080
this.configuring ||
81-
rgthree.loadingApiJson ||
81+
!!rgthree.loadingApiJson ||
8282
(canConnect && !this.node.inputs[inputIndex]!.disabled)
8383
);
8484
};
@@ -103,7 +103,7 @@ export class PowerPrompt {
103103
}
104104
return (
105105
this.configuring ||
106-
rgthree.loadingApiJson ||
106+
!!rgthree.loadingApiJson ||
107107
(canConnect && !this.node.outputs[outputIndex]!.disabled)
108108
);
109109
};

src_web/comfyui/power_lora_loader.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type {
99
ICustomWidget,
1010
CanvasPointerEvent,
1111
} from "@comfyorg/frontend";
12-
import type {ComfyNodeDef} from "typings/comfy.js";
12+
import type {ComfyApiFormat, ComfyNodeDef} from "typings/comfy.js";
1313
import type {RgthreeModelInfo} from "typings/rgthree.js";
1414

1515
import {app} from "scripts/app.js";
@@ -74,17 +74,56 @@ class RgthreePowerLoraLoader extends RgthreeBaseServerNode {
7474

7575
// Prefetch loras list.
7676
rgthreeApi.getLoras();
77+
78+
// [🤮] If ComfyUI is loading from API JSON it doesn't pass us the actual information at all
79+
// (like, in a `configure` call) and tries to set the widget data on its own. Unfortunately,
80+
// since Power Lora Loader has dynamic widgets, this fails on ComfyUI's side. We can do so after
81+
// the fact but, unfortuntely, we need to do it after a timeout since we don't have any
82+
// information at this point to be able to tell what data we need (like, even the node id, let
83+
// alone the actual data).
84+
if (rgthree.loadingApiJson) {
85+
const fullApiJson = rgthree.loadingApiJson;
86+
setTimeout(() => {
87+
this.configureFromApiJson(fullApiJson);
88+
}, 16);
89+
}
90+
}
91+
92+
private configureFromApiJson(fullApiJson: ComfyApiFormat) {
93+
if (this.id == null) {
94+
const [n, v] = this.logger.errorParts("Cannot load from API JSON without node id.");
95+
console[n]?.(...v);
96+
return;
97+
}
98+
const nodeData =
99+
fullApiJson[this.id] || fullApiJson[String(this.id)] || fullApiJson[Number(this.id)];
100+
if (nodeData == null) {
101+
const [n, v] = this.logger.errorParts(`No node found in API JSON for node id ${this.id}.`);
102+
console[n]?.(...v);
103+
return;
104+
}
105+
this.configure({
106+
widgets_values: Object.values(nodeData.inputs).filter(
107+
(input) => typeof (input as any)?.["lora"] === "string",
108+
),
109+
});
77110
}
78111

79112
/**
80113
* Handles configuration from a saved workflow by first removing our default widgets that were
81114
* added in `onNodeCreated`, letting `super.configure` and do nothing, then create our lora
82115
* widgets and, finally, add back in our default widgets.
83116
*/
84-
override configure(info: ISerialisedNode): void {
117+
override configure(
118+
info: ISerialisedNode | {widgets_values: ISerialisedNode["widgets_values"]},
119+
): void {
85120
while (this.widgets?.length) this.removeWidget(0);
86121
this.widgetButtonSpacer = null;
87-
super.configure(info);
122+
// Since we may be calling into configure manually for just widgets_values setting (like, from
123+
// API JSON) we want to only call the parent class's configure with a real ISerialisedNode data.
124+
if ((info as ISerialisedNode).id != null) {
125+
super.configure(info as ISerialisedNode);
126+
}
88127

89128
(this as any)._tempWidth = this.size[0];
90129
(this as any)._tempHeight = this.size[1];

src_web/comfyui/rgthree.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ class LogSession {
198198
return this.logParts(LogLevel.WARN, message, ...args);
199199
}
200200

201+
errorParts(message?: string, ...args: any[]) {
202+
return this.logParts(LogLevel.ERROR, message, ...args);
203+
}
204+
201205
newSession(name?: string) {
202206
return new LogSession(`${this.name}${name}`);
203207
}
@@ -237,7 +241,11 @@ class Rgthree extends EventTarget {
237241
monitorLinkTimeout: number | null = null;
238242

239243
processingQueue = false;
240-
loadingApiJson = false;
244+
/**
245+
* The API Json currently being loaded, or null. Can be used as a falsy boolean to determine if
246+
* `app.loadApiJson` is currently executing.
247+
*/
248+
loadingApiJson: ComfyApiFormat | null = null;
241249
replacingReroute: NodeId | null = null;
242250
processingMouseDown = false;
243251
processingMouseUp = false;
@@ -698,12 +706,12 @@ class Rgthree extends EventTarget {
698706

699707
// Keep state for when the app is in the middle of loading from an api JSON file.
700708
const loadApiJson = app.loadApiJson;
701-
app.loadApiJson = async function () {
702-
rgthree.loadingApiJson = true;
709+
app.loadApiJson = async function(apiData: any, fileName: string) {
710+
rgthree.loadingApiJson = apiData as ComfyApiFormat;
703711
try {
704712
loadApiJson.apply(app, [...arguments] as any);
705713
} finally {
706-
rgthree.loadingApiJson = false;
714+
rgthree.loadingApiJson = null;
707715
}
708716
};
709717

web/comfyui/base_power_prompt.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export class PowerPrompt {
3838
]);
3939
}
4040
return (this.configuring ||
41-
rgthree.loadingApiJson ||
41+
!!rgthree.loadingApiJson ||
4242
(canConnect && !this.node.inputs[inputIndex].disabled));
4343
};
4444
const oldOnConnectOutput = this.node.onConnectOutput;
@@ -54,7 +54,7 @@ export class PowerPrompt {
5454
]);
5555
}
5656
return (this.configuring ||
57-
rgthree.loadingApiJson ||
57+
!!rgthree.loadingApiJson ||
5858
(canConnect && !this.node.outputs[outputIndex].disabled));
5959
};
6060
const onPropertyChanged = this.node.onPropertyChanged;

web/comfyui/power_lora_loader.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,38 @@ class RgthreePowerLoraLoader extends RgthreeBaseServerNode {
2424
this.widgetButtonSpacer = null;
2525
this.properties[PROP_LABEL_SHOW_STRENGTHS] = PROP_VALUE_SHOW_STRENGTHS_SINGLE;
2626
rgthreeApi.getLoras();
27+
if (rgthree.loadingApiJson) {
28+
const fullApiJson = rgthree.loadingApiJson;
29+
setTimeout(() => {
30+
this.configureFromApiJson(fullApiJson);
31+
}, 16);
32+
}
33+
}
34+
configureFromApiJson(fullApiJson) {
35+
var _b, _c;
36+
if (this.id == null) {
37+
const [n, v] = this.logger.errorParts("Cannot load from API JSON without node id.");
38+
(_b = console[n]) === null || _b === void 0 ? void 0 : _b.call(console, ...v);
39+
return;
40+
}
41+
const nodeData = fullApiJson[this.id] || fullApiJson[String(this.id)] || fullApiJson[Number(this.id)];
42+
if (nodeData == null) {
43+
const [n, v] = this.logger.errorParts(`No node found in API JSON for node id ${this.id}.`);
44+
(_c = console[n]) === null || _c === void 0 ? void 0 : _c.call(console, ...v);
45+
return;
46+
}
47+
this.configure({
48+
widgets_values: Object.values(nodeData.inputs).filter((input) => typeof (input === null || input === void 0 ? void 0 : input["lora"]) === "string"),
49+
});
2750
}
2851
configure(info) {
2952
var _b;
3053
while ((_b = this.widgets) === null || _b === void 0 ? void 0 : _b.length)
3154
this.removeWidget(0);
3255
this.widgetButtonSpacer = null;
33-
super.configure(info);
56+
if (info.id != null) {
57+
super.configure(info);
58+
}
3459
this._tempWidth = this.size[0];
3560
this._tempHeight = this.size[1];
3661
for (const widgetValue of info.widgets_values || []) {

web/comfyui/rgthree.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ class LogSession {
115115
warnParts(message, ...args) {
116116
return this.logParts(LogLevel.WARN, message, ...args);
117117
}
118+
errorParts(message, ...args) {
119+
return this.logParts(LogLevel.ERROR, message, ...args);
120+
}
118121
newSession(name) {
119122
return new LogSession(`${this.name}${name}`);
120123
}
@@ -132,7 +135,7 @@ class Rgthree extends EventTarget {
132135
this.monitorBadLinksAlerted = false;
133136
this.monitorLinkTimeout = null;
134137
this.processingQueue = false;
135-
this.loadingApiJson = false;
138+
this.loadingApiJson = null;
136139
this.replacingReroute = null;
137140
this.processingMouseDown = false;
138141
this.processingMouseUp = false;
@@ -470,13 +473,13 @@ class Rgthree extends EventTarget {
470473
}
471474
};
472475
const loadApiJson = app.loadApiJson;
473-
app.loadApiJson = async function () {
474-
rgthree.loadingApiJson = true;
476+
app.loadApiJson = async function (apiData, fileName) {
477+
rgthree.loadingApiJson = apiData;
475478
try {
476479
loadApiJson.apply(app, [...arguments]);
477480
}
478481
finally {
479-
rgthree.loadingApiJson = false;
482+
rgthree.loadingApiJson = null;
480483
}
481484
};
482485
const graphToPrompt = app.graphToPrompt;

0 commit comments

Comments
 (0)