Fast_deploy / ComfyUI-MiniMaxH3-Context-Loop /web /h3_plan_upgrade_core.mjs
dzmdd's picture
Upload folder using huggingface_hub (part 3)
8fb6433 verified
Raw History Blame Contribute Delete
3.93 kB
export const LEGACY_PLAN_NODE = "MiniMaxH3ChainPlan";
export const MODERN_PLAN_NODE = "MiniMaxH3ChainPlanModern";
export const MODERN_PLAN_WIDGET_NAMES = Object.freeze([
"plan_json", "run_name", "generation_fingerprint", "width", "height",
"encode_mode", "crop", "default_duration_seconds", "default_steps",
"base_seed", "segment_crf", "video_blend_frames",
]);
function graphLink(graph, id) {
if (id == null) return null;
return graph?.links?.[id] ?? graph?.links?.get?.(id) ?? null;
}
function inputConnected(node, name) {
const input = node?.inputs?.find((item) => item.name === name);
return input?.link !== null && input?.link !== undefined;
}
function widgetValue(node, name) {
return node?.widgets?.find((item) => item.name === name)?.value;
}
function cloneSerializable(value, fallback) {
try {
return typeof structuredClone === "function"
? structuredClone(value) : JSON.parse(JSON.stringify(value));
} catch (_error) {
return fallback;
}
}
/** Replace one legacy Plan without interpreting its positional widget array.
*
* Connections and supported values are resolved by name. The caller owns all
* confirmation/error UI so this helper remains testable without ComfyUI's DOM.
*/
export function upgradeLegacyPlanNode(node, {
createNode,
confirmUpgrade = () => true,
} = {}) {
const graph = node?.graph;
if (!graph || typeof createNode !== "function") {
return {ok:false, reason:"create_unavailable"};
}
if (!inputConnected(node, "chain_policy")) {
return {ok:false, reason:"policy_required"};
}
if (!confirmUpgrade()) return {ok:false, reason:"cancelled"};
const incoming = (node.inputs ?? []).map((input) => {
const link = graphLink(graph, input.link);
return link ? {
name: input.name,
originId: link.origin_id,
originSlot: link.origin_slot,
} : null;
}).filter(Boolean);
const outgoing = [];
for (const output of node.outputs ?? []) {
for (const linkId of output.links ?? []) {
const link = graphLink(graph, linkId);
if (link) outgoing.push({
name: output.name,
targetId: link.target_id,
targetSlot: link.target_slot,
});
}
}
const replacement = createNode(MODERN_PLAN_NODE);
if (!replacement) return {ok:false, reason:"modern_unregistered"};
for (const name of MODERN_PLAN_WIDGET_NAMES) {
const value = widgetValue(node, name);
if (value === undefined) continue;
const widget = replacement.widgets?.find((item) => item.name === name);
if (widget) widget.value = value;
}
replacement.pos = Array.isArray(node.pos) ? [...node.pos] : node.pos;
replacement.properties = cloneSerializable(node.properties, {});
replacement.color = node.color;
replacement.bgcolor = node.bgcolor;
replacement.mode = node.mode;
graph.add(replacement);
if (node.size != null) {
replacement.setSize?.(
Array.isArray(node.size) ? [...node.size] : node.size);
}
graph.remove(node);
for (const item of incoming) {
const origin = graph.getNodeById?.(item.originId);
const targetSlot = replacement.inputs?.findIndex(
(input) => input.name === item.name);
if (origin && targetSlot >= 0) {
origin.connect?.(item.originSlot, replacement, targetSlot);
}
}
for (const item of outgoing) {
const target = graph.getNodeById?.(item.targetId);
const originSlot = replacement.outputs?.findIndex(
(output) => output.name === item.name);
if (target && originSlot >= 0) {
replacement.connect?.(originSlot, target, item.targetSlot);
}
}
graph.setDirtyCanvas?.(true, true);
return {ok:true, node:replacement};
}