Fix workflow graph map sampler params
This commit is contained in:
+402
-334
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { R as e } from "./config-Cxv7acF8.js";
|
||||
import { t } from "./floatingViewerManager-I_zH7WzK.js";
|
||||
import { t } from "./floatingViewerManager-CYnEwEgo.js";
|
||||
import { r as n } from "./events-BnkL6-b6.js";
|
||||
//#region ui/features/viewer/LiveStreamTracker.ts
|
||||
var r = !1, i = null, a = null, o = null, s = null, c = null, l = 0, u = 0, d = 400, f = new Set([
|
||||
Vendored
+1
-1
@@ -219,7 +219,7 @@ function ye() {
|
||||
//#region ui/features/viewer/floatingViewerManager.ts
|
||||
var S = null, be = null;
|
||||
async function xe() {
|
||||
return S || (be ||= import("./FloatingViewer-Bn-T0zen.js").then((e) => (S = e.FloatingViewer, S)), be);
|
||||
return S || (be ||= import("./FloatingViewer-iLhVlgRh.js").then((e) => (S = e.FloatingViewer, S)), be);
|
||||
}
|
||||
var C = null, Se = null;
|
||||
async function Ce() {
|
||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { B as e, Ct as t, F as n, G as r, H as i, I as a, L as o, M as s, R as c, St as l, U as u, V as d, W as f, _ as p, _t as m, a as h, at as g, b as _, bt as v, c as y, ct as b, d as x, ft as S, g as C, h as w, ht as T, i as E, it as D, l as O, lt as k, m as A, mt as j, n as M, o as N, ot as P, p as F, pt as I, r as ee, s as te, t as ne, u as re, v as ie, vt as ae, wt as oe, x as se, xt as ce, yt as le, z as ue } from "./chunks/client-DZE_lzdb.js";
|
||||
import { $ as de, B as fe, F as pe, G as L, H as me, J as he, L as ge, N as _e, P as ve, Q as ye, T as be, U as xe, V as Se, W as Ce, X as we, Y as Te, Z as Ee, at as De, ct as Oe, d as ke, et as Ae, f as je, it as Me, l as R, nt as Ne, ot as Pe, q as Fe, st as Ie, t as z, tt as Le, u as Re, w as ze } from "./chunks/config-Cxv7acF8.js";
|
||||
import { a as Be, i as Ve, n as He, t as Ue } from "./chunks/graphTraversal-CjIZsRsP.js";
|
||||
import { _ as We, a as Ge, c as Ke, d as B, f as qe, g as Je, h as Ye, i as Xe, l as Ze, m as Qe, n as $e, o as et, p as tt, r as nt, s as rt, t as it, u as at, v as ot, y as st } from "./chunks/floatingViewerManager-I_zH7WzK.js";
|
||||
import { _ as We, a as Ge, c as Ke, d as B, f as qe, g as Je, h as Ye, i as Xe, l as Ze, m as Qe, n as $e, o as et, p as tt, r as nt, s as rt, t as it, u as at, v as ot, y as st } from "./chunks/floatingViewerManager-CYnEwEgo.js";
|
||||
import { A as ct, B as lt, C as V, D as ut, E as dt, F as ft, G as pt, H as mt, I as ht, J as gt, K as _t, L as vt, M as yt, N as bt, O as xt, P as St, R as Ct, S as wt, T as Tt, U as Et, V as Dt, W as Ot, Y as kt, b as At, d as jt, f as Mt, g as Nt, h as Pt, j as Ft, k as It, l as Lt, m as Rt, p as zt, q as Bt, s as Vt, t as Ht, u as Ut, v as Wt, w as Gt, x as Kt, y as qt, z as Jt } from "./chunks/SidebarWorkflowSection-Dw9T8b4-.js";
|
||||
import { i as Yt, n as Xt, r as H, t as Zt } from "./chunks/events-BnkL6-b6.js";
|
||||
import { a as Qt, c as $t, d as en, f as tn, l as nn, m as rn, o as an, p as on, r as sn, s as cn, t as ln, u as un, v as dn } from "./chunks/openMajoorSettings-BbE45fW7.js";
|
||||
@@ -31286,7 +31286,7 @@ function Sw(e = 1200) {
|
||||
}, Math.max(250, Number(e) || 0));
|
||||
}
|
||||
function Cw(e) {
|
||||
import("./chunks/LiveStreamTracker-C7oNiQmZ.js").then((t) => {
|
||||
import("./chunks/LiveStreamTracker-CEpotRa4.js").then((t) => {
|
||||
nw = t;
|
||||
try {
|
||||
t.initLiveStreamTracker(e);
|
||||
|
||||
@@ -633,10 +633,21 @@ function _isExpandedTextWidgetLabel(label: any) {
|
||||
|
||||
function _normalizePorts(ports: any) {
|
||||
if (!Array.isArray(ports)) return [];
|
||||
return ports.filter(Boolean).map((port: any) => ({
|
||||
name: String(port?.name || port?.label || "").trim(),
|
||||
type: String(port?.type || port?.slot_type || port?.data_type || "").trim(),
|
||||
}));
|
||||
return ports
|
||||
.filter((port: any) => port && !_portLooksLikeWidget(port))
|
||||
.map((port: any) => ({
|
||||
name: String(port?.name || port?.label || "").trim(),
|
||||
type: String(port?.type || port?.slot_type || port?.data_type || "").trim(),
|
||||
}));
|
||||
}
|
||||
|
||||
function _portLooksLikeWidget(port: any) {
|
||||
if (!port || typeof port !== "object") return false;
|
||||
if (port.widget === true) return true;
|
||||
if (port.widget && typeof port.widget === "object") return true;
|
||||
if (typeof port.widget === "string" && port.widget.trim()) return true;
|
||||
if (port.widget_index != null || port.widgetIndex != null) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function _formatPortInfo(item: any) {
|
||||
@@ -658,6 +669,12 @@ function _normalizePortToken(value: any) {
|
||||
}
|
||||
|
||||
function _normalizeWidgetEntries(node: any): Array<{ label: any; key?: any; value: any }> {
|
||||
const fromParams = getNodeParamEntries(node);
|
||||
const entries = Array.isArray(fromParams)
|
||||
? fromParams.map(([label, value]: any) => ({ label, value }))
|
||||
: [];
|
||||
if (entries.length) return entries.slice(0, 160);
|
||||
|
||||
const fromWidgets = getNodeWidgetValueEntries(node);
|
||||
if (Array.isArray(fromWidgets) && fromWidgets.length) {
|
||||
return fromWidgets.map((entry: any) => ({
|
||||
@@ -666,11 +683,7 @@ function _normalizeWidgetEntries(node: any): Array<{ label: any; key?: any; valu
|
||||
value: entry?.value,
|
||||
}));
|
||||
}
|
||||
const fromParams = getNodeParamEntries(node);
|
||||
const entries = Array.isArray(fromParams)
|
||||
? fromParams.map(([label, value]: any) => ({ label, value }))
|
||||
: [];
|
||||
return entries.slice(0, 160);
|
||||
return [];
|
||||
}
|
||||
|
||||
function _getNodeVisualCategory(node: any) {
|
||||
|
||||
@@ -44,10 +44,12 @@ export async function ensureWorkflowObjectInfo(workflow: any): Promise<unknown>
|
||||
|
||||
export function resolveAssetWorkflow(asset: any): any {
|
||||
const candidates = _collectWorkflowCandidates(asset);
|
||||
const promptGraph = _resolveAssetPromptGraph(asset);
|
||||
for (const candidate of candidates) {
|
||||
const parsed = _coerceObject(candidate);
|
||||
const workflow = _normalizeWorkflow(parsed);
|
||||
if (workflow) {
|
||||
_decorateWorkflowPromptInputs(workflow, promptGraph);
|
||||
_decorateWorkflowSubgraphNames(workflow);
|
||||
return workflow;
|
||||
}
|
||||
@@ -133,11 +135,21 @@ export function getNodeParamEntries(node: any) {
|
||||
|
||||
function _getNodeValueParamEntries(node: any) {
|
||||
const entries = [];
|
||||
const promptInputs =
|
||||
node?._mjrPromptInputs && typeof node._mjrPromptInputs === "object" ? node._mjrPromptInputs : null;
|
||||
const inputs = node?.inputs && typeof node.inputs === "object" ? node.inputs : null;
|
||||
|
||||
if (promptInputs && !Array.isArray(promptInputs)) {
|
||||
for (const [key, value] of Object.entries(promptInputs)) {
|
||||
if (_valueLooksLikePromptLink(value)) continue;
|
||||
entries.push([key, value]);
|
||||
}
|
||||
}
|
||||
|
||||
if (inputs && !Array.isArray(inputs)) {
|
||||
for (const [key, value] of Object.entries(inputs)) {
|
||||
if (_valueLooksLikePromptLink(value)) continue;
|
||||
if (entries.some(([existingKey]) => String(existingKey) === String(key))) continue;
|
||||
entries.push([key, value]);
|
||||
}
|
||||
}
|
||||
@@ -163,10 +175,10 @@ export function getNodeWidgetValueEntries(node: any) {
|
||||
return widgetsValues.map((value, index) => {
|
||||
const guessedLabel = _guessWidgetLabel(node, index, value);
|
||||
const label =
|
||||
objectInputNames[index] ||
|
||||
inputSlotNames[index] ||
|
||||
widgets[index]?.name ||
|
||||
widgets[index]?.label ||
|
||||
objectInputNames[index] ||
|
||||
guessedLabel ||
|
||||
`param ${index + 1}`;
|
||||
return { label, value, index };
|
||||
@@ -203,9 +215,6 @@ function _looksArrayLikeWidgetsValues(widgetsValuesRaw: any) {
|
||||
export function getNodeInputSlotNames(node: any) {
|
||||
const inputs = Array.isArray(node?.inputs) ? node.inputs : [];
|
||||
const widgetInputs = inputs.filter(_inputLooksLikeWidget);
|
||||
const unlinkedWidgetLikeInputs = inputs.filter(
|
||||
(input: any) => !_inputHasLink(input) && _inputTypeLooksWidgetCapable(input?.type),
|
||||
);
|
||||
const labelSource: any[] = [];
|
||||
const seen = new Set();
|
||||
const addInput = (input: any) => {
|
||||
@@ -215,7 +224,6 @@ export function getNodeInputSlotNames(node: any) {
|
||||
labelSource.push(input);
|
||||
};
|
||||
for (const input of widgetInputs) addInput(input);
|
||||
for (const input of unlinkedWidgetLikeInputs) addInput(input);
|
||||
return labelSource.map((input: any) =>
|
||||
String(
|
||||
input?.label ||
|
||||
@@ -303,6 +311,7 @@ function _inputLooksLikeWidget(input: any) {
|
||||
if (input.widget === true) return true;
|
||||
if (input.widget && typeof input.widget === "object") return true;
|
||||
if (typeof input.widget === "string" && input.widget.trim()) return true;
|
||||
if (input.widget_index != null || input.widgetIndex != null) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -345,6 +354,17 @@ function _guessWidgetLabel(node: any, index: any, value: any) {
|
||||
const haystack = `${type} ${title}`.toLowerCase();
|
||||
const valueText = String(value ?? "").toLowerCase();
|
||||
if (haystack.includes("ksamplerselect")) return "sampler_name";
|
||||
if (haystack.includes("ksampler")) {
|
||||
return [
|
||||
"seed",
|
||||
"control_after_generate",
|
||||
"steps",
|
||||
"cfg",
|
||||
"sampler_name",
|
||||
"scheduler",
|
||||
"denoise",
|
||||
][index] || null;
|
||||
}
|
||||
if (haystack.includes("manualsigmas")) return "sigmas";
|
||||
if (haystack.includes("randomnoise")) return index === 0 ? "noise_seed" : index === 1 ? "control_after_generate" : null;
|
||||
if (haystack.includes("cfgguider")) return "cfg";
|
||||
@@ -417,6 +437,24 @@ function _collectWorkflowCandidates(asset: any) {
|
||||
].filter((value: any) => value != null);
|
||||
}
|
||||
|
||||
function _resolveAssetPromptGraph(asset: any) {
|
||||
const raw = _coerceObject(asset?.metadata_raw);
|
||||
const meta = _coerceObject(asset?.metadata);
|
||||
const candidates = [
|
||||
asset?.prompt,
|
||||
asset?.Prompt,
|
||||
raw?.prompt,
|
||||
raw?.Prompt,
|
||||
meta?.prompt,
|
||||
meta?.Prompt,
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
const parsed = _coerceObject(candidate);
|
||||
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function _coerceObject(value: any) {
|
||||
if (!value) return null;
|
||||
if (typeof value === "object") return value;
|
||||
@@ -467,6 +505,61 @@ function _decorateWorkflowSubgraphNames(workflow: any, visited = new WeakSet())
|
||||
}
|
||||
}
|
||||
|
||||
function _decorateWorkflowPromptInputs(workflow: any, promptGraph: any) {
|
||||
if (!workflow || typeof workflow !== "object" || !promptGraph || typeof promptGraph !== "object") return;
|
||||
const promptNodes = _getPromptNodeEntries(promptGraph);
|
||||
if (!promptNodes.length) return;
|
||||
_decorateWorkflowPromptInputsInGraph(workflow, promptNodes, new WeakSet());
|
||||
}
|
||||
|
||||
function _decorateWorkflowPromptInputsInGraph(workflow: any, promptNodes: any[], visited: WeakSet<object>) {
|
||||
if (!workflow || typeof workflow !== "object" || visited.has(workflow)) return;
|
||||
visited.add(workflow);
|
||||
const definitions = _getSubgraphDefinitions(workflow);
|
||||
for (const node of Array.isArray(workflow?.nodes) ? workflow.nodes : []) {
|
||||
const match = _findPromptNodeMatch(node, promptNodes);
|
||||
if (match?.inputs && typeof match.inputs === "object" && !Array.isArray(match.inputs)) {
|
||||
node._mjrPromptInputs = match.inputs;
|
||||
}
|
||||
const subgraph = _getNodeSubgraph(workflow, node, definitions);
|
||||
if (subgraph) _decorateWorkflowPromptInputsInGraph(subgraph, promptNodes, visited);
|
||||
}
|
||||
}
|
||||
|
||||
function _getPromptNodeEntries(promptGraph: any) {
|
||||
if (!promptGraph || typeof promptGraph !== "object" || Array.isArray(promptGraph)) return [];
|
||||
const entries = [];
|
||||
for (const [id, value] of Object.entries(promptGraph)) {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
||||
const classType = String((value as any).class_type || (value as any).type || "").trim();
|
||||
const inputs = (value as any).inputs;
|
||||
if (!classType || !inputs || typeof inputs !== "object" || Array.isArray(inputs)) continue;
|
||||
const leafId = String(id).split(":").pop() || String(id);
|
||||
entries.push({ id: String(id), leafId, classType, inputs });
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
function _findPromptNodeMatch(node: any, promptNodes: any[]) {
|
||||
const nodeId = String(node?.id ?? node?.ID ?? "").trim();
|
||||
const nodeType = _normalizeNodeTypeForPromptMatch(getNodeType(node));
|
||||
if (!nodeId || !nodeType) return null;
|
||||
const exact = promptNodes.find(
|
||||
(entry) => entry.id === nodeId && _normalizeNodeTypeForPromptMatch(entry.classType) === nodeType,
|
||||
);
|
||||
if (exact) return exact;
|
||||
const matches = promptNodes.filter(
|
||||
(entry) => entry.leafId === nodeId && _normalizeNodeTypeForPromptMatch(entry.classType) === nodeType,
|
||||
);
|
||||
return matches.length === 1 ? matches[0] : null;
|
||||
}
|
||||
|
||||
function _normalizeNodeTypeForPromptMatch(value: any) {
|
||||
return String(value || "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
function _applySubgraphDefinitionMetadata(node: any, definitions: any) {
|
||||
if (!node || typeof node !== "object") return;
|
||||
const definitionKey = _getNodeSubgraphDefinitionKeys(node).find((key) => definitions.has(String(key)));
|
||||
|
||||
@@ -84,7 +84,7 @@ describe("workflow graph map data", () => {
|
||||
{ name: "width", type: "INT", link: 23, widget: { name: "width" } },
|
||||
{ name: "height", type: "INT", link: 24, widget: { name: "height" } },
|
||||
{ name: "length", type: "INT", link: 25, widget: { name: "length" } },
|
||||
{ name: "batch_size", type: "INT" },
|
||||
{ name: "batch_size", type: "INT", widget: { name: "batch_size" } },
|
||||
],
|
||||
widgets_values: [832, 480, 81, 1],
|
||||
};
|
||||
@@ -98,6 +98,122 @@ describe("workflow graph map data", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not infer unmarked socket inputs as widgets for core sampler nodes", () => {
|
||||
const node = {
|
||||
id: 3,
|
||||
type: "KSampler",
|
||||
inputs: [
|
||||
{ name: "model", type: "MODEL", link: 1 },
|
||||
{ name: "positive", type: "CONDITIONING", link: 2 },
|
||||
{ name: "negative", type: "CONDITIONING", link: 3 },
|
||||
{ name: "latent_image", type: "LATENT", link: 4 },
|
||||
{ name: "seed", type: "INT" },
|
||||
{ name: "steps", type: "INT" },
|
||||
{ name: "cfg", type: "FLOAT" },
|
||||
{ name: "sampler_name", type: "COMBO" },
|
||||
{ name: "scheduler", type: "COMBO" },
|
||||
{ name: "denoise", type: "FLOAT" },
|
||||
],
|
||||
widgets_values: [1088132929177955, "randomize", 20, 8, "euler", "simple", 1],
|
||||
};
|
||||
|
||||
expect(getNodeInputSlotNames(node)).toEqual([]);
|
||||
expect(getNodeWidgetValueEntries(node)).toEqual([
|
||||
{ label: "seed", value: 1088132929177955, index: 0 },
|
||||
{ label: "control_after_generate", value: "randomize", index: 1 },
|
||||
{ label: "steps", value: 20, index: 2 },
|
||||
{ label: "cfg", value: 8, index: 3 },
|
||||
{ label: "sampler_name", value: "euler", index: 4 },
|
||||
{ label: "scheduler", value: "simple", index: 5 },
|
||||
{ label: "denoise", value: 1, index: 6 },
|
||||
]);
|
||||
expect(getNodeParamEntries(node)).toEqual([
|
||||
["seed", 1088132929177955],
|
||||
["control_after_generate", "randomize"],
|
||||
["steps", 20],
|
||||
["cfg", 8],
|
||||
["sampler_name", "euler"],
|
||||
["scheduler", "simple"],
|
||||
["denoise", 1],
|
||||
]);
|
||||
});
|
||||
|
||||
it("uses prompt inputs for subgraph sampler parameters when widgets_values are ambiguous", () => {
|
||||
const workflow = resolveAssetWorkflow({
|
||||
workflow: {
|
||||
nodes: [
|
||||
{
|
||||
id: 95,
|
||||
type: "c20beb1e-2a45-4872-913e-21018c09c578",
|
||||
properties: {
|
||||
proxyWidgets: [
|
||||
["3", "seed"],
|
||||
["3", "steps"],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
definitions: {
|
||||
subgraphs: [
|
||||
{
|
||||
id: "c20beb1e-2a45-4872-913e-21018c09c578",
|
||||
nodes: [
|
||||
{
|
||||
id: 3,
|
||||
type: "KSampler",
|
||||
inputs: [
|
||||
{ name: "model", type: "MODEL", link: 13 },
|
||||
{ name: "positive", type: "CONDITIONING", link: 30 },
|
||||
{ name: "negative", type: "CONDITIONING", link: 33 },
|
||||
{ name: "latent_image", type: "LATENT", link: 427 },
|
||||
{ name: "seed", type: "INT", link: 71, widget: { name: "seed" } },
|
||||
{ name: "steps", type: "INT", link: 72, widget: { name: "steps" } },
|
||||
],
|
||||
widgets_values: [
|
||||
1088132929177955,
|
||||
"randomize",
|
||||
8,
|
||||
1,
|
||||
"res_multistep",
|
||||
"simple",
|
||||
1,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
prompt: {
|
||||
"95:3": {
|
||||
class_type: "KSampler",
|
||||
inputs: {
|
||||
seed: 1088132929177955,
|
||||
steps: 8,
|
||||
cfg: 1,
|
||||
sampler_name: "res_multistep",
|
||||
scheduler: "simple",
|
||||
denoise: 1,
|
||||
model: ["95:11", 0],
|
||||
positive: ["95:27", 0],
|
||||
negative: ["95:33", 0],
|
||||
latent_image: ["95:242", 0],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const sampler = findWorkflowNode(workflow, "95::3");
|
||||
|
||||
expect(getNodeParamEntries(sampler)).toEqual([
|
||||
["seed", 1088132929177955],
|
||||
["steps", 8],
|
||||
["cfg", 1],
|
||||
["sampler_name", "res_multistep"],
|
||||
["scheduler", "simple"],
|
||||
["denoise", 1],
|
||||
]);
|
||||
});
|
||||
|
||||
it("supports custom nodes that save widgets_values as a dictionary", () => {
|
||||
expect(
|
||||
getNodeWidgetValueEntries({
|
||||
|
||||
Reference in New Issue
Block a user