Files
DemonGatanjieu-Anomalous_Mo…/web/modules/ui_recipe_parameter_utils.js

132 lines
4.5 KiB
JavaScript

/** Pure ordering and value helpers for the Workflow Recipe parameter view. */
import { translate } from './locales.js';
const t = (key, params) => translate(key, params);
export function topologicalSortNodes(workflowNodes, workflowLinks) {
const inDegree = new Map();
const adj = new Map();
const allIds = new Set();
for (const node of workflowNodes) {
const id = String(node.id);
allIds.add(id);
inDegree.set(id, 0);
adj.set(id, []);
}
const rawLinks = workflowLinks;
const linksArray = Array.isArray(rawLinks) ? rawLinks : (rawLinks && typeof rawLinks === 'object' ? Object.values(rawLinks) : []);
for (const link of linksArray) {
if (!Array.isArray(link) || link.length < 4) continue;
const originId = String(link[1]);
const targetId = String(link[3]);
if (allIds.has(originId) && allIds.has(targetId)) {
adj.get(originId).push(targetId);
inDegree.set(targetId, inDegree.get(targetId) + 1);
}
}
const queue = [];
for (const [id, deg] of inDegree.entries()) {
if (deg === 0) queue.push(id);
}
const sorted = [];
while (queue.length > 0) {
const u = queue.shift();
sorted.push(u);
for (const v of adj.get(u)) {
inDegree.set(v, inDegree.get(v) - 1);
if (inDegree.get(v) === 0) queue.push(v);
}
}
for (const id of allIds) {
if (inDegree.get(id) > 0) sorted.push(id);
}
return sorted;
}
export function parameterNodeOrder(recipe) {
const summaries = Array.isArray(recipe?.params?.nodes) ? recipe.params.nodes : [];
const workflowNodes = Array.isArray(recipe?.workflow?.nodes) ? recipe.workflow.nodes : [];
const byId = new Map(workflowNodes.map((node) => [String(node?.id), node]));
const summaryById = new Map(summaries.map((node) => [String(node?.id), node]));
const orderedIds = topologicalSortNodes(workflowNodes, recipe?.workflow?.links);
const result = [];
const seen = new Set();
for (const id of orderedIds) {
const summary = summaryById.get(id);
const workflowNode = byId.get(id);
if (summary || workflowNode) {
result.push({ summary: summary || { id, type: workflowNode?.type, title: workflowNode?.title, widgets: [] }, workflowNode });
seen.add(id);
}
}
for (const summary of summaries) {
const id = String(summary?.id);
if (!seen.has(id)) result.push({ summary, workflowNode: byId.get(id) });
}
return result;
}
export function isVolatileParameter(node, widget, index) {
const widgetName = String(widget?.name || '').toLowerCase();
if (/(^|[_\s-])(seed|noise_seed|random_seed|variation_seed|last_seed)([_\s-]|$)/i.test(widgetName)) return true;
const nodeType = String(node?.type || '').toLowerCase();
if (nodeType === 'ksampler') return index === 0;
if (nodeType === 'ksampleradvanced') return index === 1;
return false;
}
export function cloneJson(value) {
try { return JSON.parse(JSON.stringify(value)); } catch (error) { return null; }
}
export function editorValueText(value) {
if (typeof value === 'string') return value;
if (value === undefined) return '';
try { return JSON.stringify(value); } catch (error) { return String(value); }
}
export function parseEditorValue(raw, original) {
if (typeof original === 'number') {
const value = Number(raw);
if (!Number.isFinite(value)) throw new Error('invalid number');
return value;
}
if (typeof original === 'boolean') {
if (raw !== 'true' && raw !== 'false') throw new Error('invalid boolean');
return raw === 'true';
}
if (original !== null && typeof original === 'object') return JSON.parse(raw);
return raw;
}
export function promptRoleLabel(role) {
return t({
positive: 'recipePromptRolePositive',
negative: 'recipePromptRoleNegative',
both: 'recipePromptRoleBoth',
ignored: 'recipePromptRoleIgnored',
unknown: 'recipePromptRoleUnknown',
}[role] || 'recipePromptRoleUnknown');
}
export function formatRecipeResolution(res) {
if (!res) return '';
if (typeof res === 'string' || typeof res === 'number') return String(res);
if (Array.isArray(res) && res.length >= 2) return `${res[0]}x${res[1]}`;
if (typeof res === 'object') {
const w = res.width ?? res.w ?? res.x;
const h = res.height ?? res.h ?? res.y;
if (w && h) return `${w}x${h}`;
}
return '';
}