Files
Jony ba920f2b66 Publish current ComfyUI O1Key code baseline
Replace the prior release tree with the current plugin, frontend, tests, and documentation. Document retired node IDs and the public Gitea update source.
2026-09-24 19:56:48 +08:00

124 lines
4.8 KiB
JavaScript

import { app } from "../../../scripts/app.js";
const NODE_TYPE = "O1keyOmniFlashVideo";
const REFERENCE_GROUP = "参考图片";
const MEDIA_INPUTS = ["首帧图片", "尾帧图片", "源视频"];
const MODE_INPUTS = {
"文生视频": [],
"参考图视频": [REFERENCE_GROUP],
"首尾帧": ["首帧图片", "尾帧图片"],
"视频编辑": [REFERENCE_GROUP, "源视频"],
};
function isReferenceInput(input) {
return input.name.startsWith(`${REFERENCE_GROUP}.`)
|| /^参考图片\d+$/.test(input.name);
}
function inputOptions(input) {
return { label: input.label ?? input.name.split(".").at(-1), shape: input.shape };
}
function syncModeInputs(node) {
const state = node._o1keyOmniModeInputs;
if (!state || state.syncing) return;
const visible = MODE_INPUTS[state.mode.value] ?? MODE_INPUTS["文生视频"];
state.syncing = true;
try {
// Disable Autogrow before removing reference sockets; disconnects must
// not recreate inputs belonging to the previous mode.
if (visible.includes(REFERENCE_GROUP)) {
node.comfyDynamic.autogrow[REFERENCE_GROUP] = state.autogrow;
} else {
delete node.comfyDynamic.autogrow[REFERENCE_GROUP];
}
for (let index = node.inputs.length - 1; index >= 0; index--) {
const input = node.inputs[index];
const active = isReferenceInput(input)
? visible.includes(REFERENCE_GROUP)
: !MEDIA_INPUTS.includes(input.name) || visible.includes(input.name);
if (!active) node.removeInput(index);
}
for (const name of visible) {
const template = state.templates[name];
const exists = name === REFERENCE_GROUP
? node.inputs.some(isReferenceInput)
: node.inputs.some((input) => input.name === name);
if (!exists) node.addInput(template.name, template.type, inputOptions(template));
}
} finally {
state.syncing = false;
}
if (typeof node.computeSize === "function" && typeof node.setSize === "function") {
const size = node.computeSize([...node.size]);
node.setSize([node.size[0], size[1]]);
}
node.setDirtyCanvas?.(true, true);
}
function installModeInputs(node) {
if ((node?.comfyClass || node?.type) !== NODE_TYPE || node._o1keyOmniModeInputs) return;
const mode = node.widgets?.find((widget) => widget.name === "生成模式");
const autogrow = node.comfyDynamic?.autogrow?.[REFERENCE_GROUP];
if (!mode || !autogrow || !node.inputs || !node.addInput || !node.removeInput) return;
const reference = node.inputs.find(isReferenceInput) ?? {
name: `${REFERENCE_GROUP}.${autogrow.names?.[0] ?? "参考图片1"}`,
type: "IMAGE",
};
const templates = { [REFERENCE_GROUP]: { ...reference } };
for (const name of MEDIA_INPUTS) {
const type = name === "源视频" ? "VIDEO" : "IMAGE";
templates[name] = { ...(node.inputs.find((input) => input.name === name) ?? { name, type }) };
}
node._o1keyOmniModeInputs = { mode, autogrow, templates, syncing: false };
const originalConnectionsChange = node.onConnectionsChange;
node.onConnectionsChange = function () {
if (node._o1keyOmniModeInputs.syncing) return;
return originalConnectionsChange?.apply(this, arguments);
};
const originalCallback = mode.callback;
mode.callback = function () {
const result = originalCallback?.apply(this, arguments);
syncModeInputs(node);
return result;
};
syncModeInputs(node);
}
function installRunButton(node) {
if ((node?.comfyClass || node?.type) !== NODE_TYPE || node._o1keyOmniRunButton) return;
const button = node.addWidget("button", "开始生成", null, async () => {
if (node._o1keyOmniSubmitting) return;
node._o1keyOmniSubmitting = true;
button.disabled = true;
try {
const queued = await app.queuePrompt(0, 1, [node.id]);
if (queued === false) throw new Error("ComfyUI 未接受本次任务");
} catch (error) {
app.extensionManager?.toast?.add?.({
severity: "error",
summary: "Omni Flash 提交失败",
detail: String(error?.message || error),
});
} finally {
button.disabled = false;
node._o1keyOmniSubmitting = false;
}
}, { serialize: false });
button.serializeValue = () => undefined;
node._o1keyOmniRunButton = button;
}
app.registerExtension({
name: "o1key.omniFlashVideo",
nodeCreated(node) {
installRunButton(node);
installModeInputs(node);
},
loadedGraphNode(node) {
installRunButton(node);
installModeInputs(node);
syncModeInputs(node);
},
});