Spaces:
Running
on
Zero
Running
on
Zero
| import { BaseContextNode } from "./context.js"; | |
| import { RgthreeBaseServerNode } from "./base_node.js"; | |
| import { moveArrayItem, wait } from "../../rgthree/common/shared_utils.js"; | |
| import { RgthreeInvisibleWidget } from "./utils_widgets.js"; | |
| import { getContextOutputName, InputMutationOperation, } from "./services/context_service.js"; | |
| import { app } from "../../scripts/app.js"; | |
| import { SERVICE as CONTEXT_SERVICE } from "./services/context_service.js"; | |
| const OWNED_PREFIX = "+"; | |
| const REGEX_OWNED_PREFIX = /^\+\s*/; | |
| const REGEX_EMPTY_INPUT = /^\+\s*$/; | |
| export class DynamicContextNodeBase extends BaseContextNode { | |
| constructor() { | |
| super(...arguments); | |
| this.hasShadowInputs = false; | |
| } | |
| getContextInputsList() { | |
| return this.inputs; | |
| } | |
| provideInputsData() { | |
| const inputs = this.getContextInputsList(); | |
| return inputs | |
| .map((input, index) => ({ | |
| name: this.stripOwnedPrefix(input.name), | |
| type: String(input.type), | |
| index, | |
| })) | |
| .filter((i) => i.type !== "*"); | |
| } | |
| addOwnedPrefix(name) { | |
| return `+ ${this.stripOwnedPrefix(name)}`; | |
| } | |
| isOwnedInput(inputOrName) { | |
| const name = typeof inputOrName == "string" ? inputOrName : (inputOrName === null || inputOrName === void 0 ? void 0 : inputOrName.name) || ""; | |
| return REGEX_OWNED_PREFIX.test(name); | |
| } | |
| stripOwnedPrefix(name) { | |
| return name.replace(REGEX_OWNED_PREFIX, ""); | |
| } | |
| handleUpstreamMutation(mutation) { | |
| console.log(`[node ${this.id}] handleUpstreamMutation`, mutation); | |
| if (mutation.operation === InputMutationOperation.ADDED) { | |
| const slot = mutation.slot; | |
| if (!slot) { | |
| throw new Error("Cannot have an ADDED mutation without a provided slot data."); | |
| } | |
| this.addContextInput(this.stripOwnedPrefix(slot.name), slot.type, mutation.slotIndex); | |
| return; | |
| } | |
| if (mutation.operation === InputMutationOperation.REMOVED) { | |
| const slot = mutation.slot; | |
| if (!slot) { | |
| throw new Error("Cannot have an REMOVED mutation without a provided slot data."); | |
| } | |
| this.removeContextInput(mutation.slotIndex); | |
| return; | |
| } | |
| if (mutation.operation === InputMutationOperation.RENAMED) { | |
| const slot = mutation.slot; | |
| if (!slot) { | |
| throw new Error("Cannot have an RENAMED mutation without a provided slot data."); | |
| } | |
| this.renameContextInput(mutation.slotIndex, slot.name); | |
| return; | |
| } | |
| } | |
| clone() { | |
| const cloned = super.clone(); | |
| while (cloned.inputs.length > 1) { | |
| cloned.removeInput(cloned.inputs.length - 1); | |
| } | |
| while (cloned.widgets.length > 1) { | |
| cloned.removeWidget(cloned.widgets.length - 1); | |
| } | |
| while (cloned.outputs.length > 1) { | |
| cloned.removeOutput(cloned.outputs.length - 1); | |
| } | |
| return cloned; | |
| } | |
| onNodeCreated() { | |
| const node = this; | |
| this.addCustomWidget(new RgthreeInvisibleWidget("output_keys", "RGTHREE_DYNAMIC_CONTEXT_OUTPUTS", "", () => { | |
| return (node.outputs || []) | |
| .map((o, i) => i > 0 && o.name) | |
| .filter((n) => n !== false) | |
| .join(","); | |
| })); | |
| } | |
| addContextInput(name, type, slot = -1) { | |
| const inputs = this.getContextInputsList(); | |
| if (this.hasShadowInputs) { | |
| inputs.push({ name, type, link: null }); | |
| } | |
| else { | |
| this.addInput(name, type); | |
| } | |
| if (slot > -1) { | |
| moveArrayItem(inputs, inputs.length - 1, slot); | |
| } | |
| else { | |
| slot = inputs.length - 1; | |
| } | |
| if (type !== "*") { | |
| const output = this.addOutput(getContextOutputName(name), type); | |
| if (type === "COMBO" || String(type).includes(",") || Array.isArray(type)) { | |
| output.widget = true; | |
| } | |
| if (slot > -1) { | |
| moveArrayItem(this.outputs, this.outputs.length - 1, slot); | |
| } | |
| } | |
| this.fixInputsOutputsLinkSlots(); | |
| this.inputsMutated({ | |
| operation: InputMutationOperation.ADDED, | |
| node: this, | |
| slotIndex: slot, | |
| slot: inputs[slot], | |
| }); | |
| } | |
| removeContextInput(slotIndex) { | |
| if (this.hasShadowInputs) { | |
| const inputs = this.getContextInputsList(); | |
| const input = inputs.splice(slotIndex, 1)[0]; | |
| if (this.outputs[slotIndex]) { | |
| this.removeOutput(slotIndex); | |
| } | |
| } | |
| else { | |
| this.removeInput(slotIndex); | |
| } | |
| } | |
| renameContextInput(index, newName, forceOwnBool = null) { | |
| const inputs = this.getContextInputsList(); | |
| const input = inputs[index]; | |
| const oldName = input.name; | |
| newName = this.stripOwnedPrefix(newName.trim() || this.getSlotDefaultInputLabel(index)); | |
| if (forceOwnBool === true || (this.isOwnedInput(oldName) && forceOwnBool !== false)) { | |
| newName = this.addOwnedPrefix(newName); | |
| } | |
| if (oldName !== newName) { | |
| input.name = newName; | |
| input.removable = this.isOwnedInput(newName); | |
| this.outputs[index].name = getContextOutputName(inputs[index].name); | |
| this.inputsMutated({ | |
| node: this, | |
| operation: InputMutationOperation.RENAMED, | |
| slotIndex: index, | |
| slot: input, | |
| }); | |
| } | |
| } | |
| getSlotDefaultInputLabel(slotIndex) { | |
| const inputs = this.getContextInputsList(); | |
| const input = inputs[slotIndex]; | |
| let defaultLabel = this.stripOwnedPrefix(input.name).toLowerCase(); | |
| return defaultLabel.toLocaleLowerCase(); | |
| } | |
| inputsMutated(mutation) { | |
| CONTEXT_SERVICE.onInputChanges(this, mutation); | |
| } | |
| fixInputsOutputsLinkSlots() { | |
| if (!this.hasShadowInputs) { | |
| const inputs = this.getContextInputsList(); | |
| for (let index = inputs.length - 1; index > 0; index--) { | |
| const input = inputs[index]; | |
| if ((input === null || input === void 0 ? void 0 : input.link) != null) { | |
| app.graph.links[input.link].target_slot = index; | |
| } | |
| } | |
| } | |
| const outputs = this.outputs; | |
| for (let index = outputs.length - 1; index > 0; index--) { | |
| const output = outputs[index]; | |
| if (output) { | |
| output.nameLocked = true; | |
| for (const link of output.links || []) { | |
| app.graph.links[link].origin_slot = index; | |
| } | |
| } | |
| } | |
| } | |
| static setUp(comfyClass, nodeData) { | |
| RgthreeBaseServerNode.registerForOverride(comfyClass, nodeData, this); | |
| wait(500).then(() => { | |
| LiteGraph.slot_types_default_out["RGTHREE_DYNAMIC_CONTEXT"] = | |
| LiteGraph.slot_types_default_out["RGTHREE_DYNAMIC_CONTEXT"] || []; | |
| LiteGraph.slot_types_default_out["RGTHREE_DYNAMIC_CONTEXT"].push(comfyClass.comfyClass); | |
| }); | |
| } | |
| } | |