6244 lines
292 KiB
JavaScript
6244 lines
292 KiB
JavaScript
import { app } from "../../scripts/app.js";
|
|
import { api } from "../../scripts/api.js";
|
|
import { DEFAULT_DIMENSIONS_LIST, DEFAULT_MODELS_ARCH_LIST, DEFAULT_CONTROLNET_CONDITIONING_LIST,
|
|
RUNWARE_NODE_TYPES, MODEL_TYPES_TERMS, MODEL_LIST_TERMS
|
|
} from "./types.js";
|
|
|
|
const TIMEOUT_RANGE = { min: 5, default: 90, max: 99 };
|
|
const OUTPUT_QUALITY_RANGE = { min: 20, default: 95, max: 99 };
|
|
const CACHE_SIZE_RANGE = { min: 30, default: 150, max: 4096 };
|
|
|
|
/** Must match `audioInferenceInputs.MAX_VIDEOS` in modules/audioInferenceInputs.py */
|
|
const AUDIO_INFERENCE_INPUTS_MAX_VIDEOS = 4;
|
|
/** Must match `audioInferenceInputs.MAX_AUDIOS` in modules/audioInferenceInputs.py */
|
|
const AUDIO_INFERENCE_INPUTS_MAX_AUDIOS = 4;
|
|
|
|
let openDialog = false;
|
|
let lastTimeout = false;
|
|
let lastOutputFormat = false;
|
|
let lastOutputQuality = false;
|
|
let lastEnableImagesCaching = null;
|
|
let lastMinImageCacheSize = false;
|
|
|
|
async function queryLocalAPI(endpoint, data) {
|
|
try {
|
|
const resp = await api.fetchApi(`/${endpoint}`, {
|
|
method: "POST",
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify(data)
|
|
});
|
|
return await resp.json();
|
|
} catch (err) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const runwareLocalAPI = {
|
|
enhancePrompt: (userPrompt) => queryLocalAPI('promptEnhance', { userPrompt }),
|
|
setAPIKey: (apiKey) => queryLocalAPI('setAPIKey', { apiKey }),
|
|
setTimeout: (maxTimeout) => queryLocalAPI('setMaxTimeout', { maxTimeout }),
|
|
setOutputFormat: (outputFormat) => queryLocalAPI('setOutputFormat', { outputFormat }),
|
|
setOutputQuality: (outputQuality) => queryLocalAPI('setOutputQuality', { outputQuality }),
|
|
setEnableImagesCaching: (enableCaching) => queryLocalAPI('setEnableImagesCaching', { enableCaching }),
|
|
setMinImageCacheSize: (minCacheSize) => queryLocalAPI('setMinImageCacheSize', { minCacheSize }),
|
|
modelSearch: (modelQuery = "", modelArch = "all", modelType = "base", modelCat = "checkpoint", condtioning = "") =>
|
|
queryLocalAPI('modelSearch', { modelQuery, modelArch, modelType, modelCat, condtioning })
|
|
};
|
|
|
|
function mediaUUIDHandler(msgEvent) {
|
|
const mediaData = msgEvent.detail;
|
|
const mediaUUID = mediaData.mediaUUID;
|
|
const mediaNodeID = parseInt(mediaData.nodeID);
|
|
|
|
if(mediaData.success) {
|
|
const mediaNode = app.graph.getNodeById(mediaNodeID);
|
|
|
|
if(mediaNode !== null && mediaNode !== undefined) {
|
|
// Find the mediaUUID widget specifically
|
|
const mediaUUIDWidget = mediaNode.widgets.find(widget => widget.name === "mediaUUID");
|
|
|
|
if(mediaUUIDWidget) {
|
|
// Update both widget.value and inputEl.value for STRING widgets
|
|
if(mediaUUIDWidget.value !== undefined) {
|
|
mediaUUIDWidget.value = mediaUUID;
|
|
}
|
|
|
|
if(mediaUUIDWidget.inputEl) {
|
|
mediaUUIDWidget.inputEl.value = mediaUUID;
|
|
// Trigger change events to update the UI
|
|
mediaUUIDWidget.inputEl.dispatchEvent(new Event('input', { bubbles: true }));
|
|
mediaUUIDWidget.inputEl.dispatchEvent(new Event('change', { bubbles: true }));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function save3DFilepathHandler(msgEvent) {
|
|
const data = msgEvent.detail;
|
|
const filepath = data.filepath;
|
|
const nodeID = parseInt(data.nodeID, 10);
|
|
if (Number.isNaN(nodeID)) return false;
|
|
|
|
if(data.success && filepath) {
|
|
const node = app.graph.getNodeById(nodeID);
|
|
if(node !== null && node !== undefined) {
|
|
const filepathWidget = node.widgets.find(widget => widget.name === "filepath");
|
|
if(filepathWidget) {
|
|
if(filepathWidget.value !== undefined) {
|
|
filepathWidget.value = filepath;
|
|
}
|
|
if(filepathWidget.inputEl) {
|
|
filepathWidget.inputEl.value = filepath;
|
|
filepathWidget.inputEl.dispatchEvent(new Event('input', { bubbles: true }));
|
|
filepathWidget.inputEl.dispatchEvent(new Event('change', { bubbles: true }));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function captionNodeHandler(msgEvent) {
|
|
const captionData = msgEvent.detail;
|
|
const captionText = captionData.captionText;
|
|
const captionNodeID = parseInt(captionData.nodeID);
|
|
|
|
if(captionData.success) {
|
|
const captionNode = app.graph.getNodeById(captionNodeID);
|
|
if(captionNode !== null && captionNode !== undefined) {
|
|
// Find the imageCaption widget specifically
|
|
const imageCaptionWidget = captionNode.widgets.find(widget => widget.name === "imageCaption");
|
|
if(imageCaptionWidget && imageCaptionWidget.inputEl) {
|
|
imageCaptionWidget.inputEl.value = captionText;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function saveTextHandler(msgEvent) {
|
|
const data = msgEvent.detail;
|
|
const displayText = data.text;
|
|
const nodeID = parseInt(data.nodeID, 10);
|
|
if (!data.success || Number.isNaN(nodeID)) return false;
|
|
const node = app.graph.getNodeById(nodeID);
|
|
if (node === null || node === undefined) return false;
|
|
const widgetName = data.widgetName || "text";
|
|
const textWidget = node.widgets.find((w) => w.name === widgetName);
|
|
if (textWidget) {
|
|
if (textWidget.value !== undefined) {
|
|
textWidget.value = displayText;
|
|
}
|
|
if (textWidget.inputEl) {
|
|
textWidget.inputEl.value = displayText;
|
|
textWidget.inputEl.dispatchEvent(new Event("input", { bubbles: true }));
|
|
textWidget.inputEl.dispatchEvent(new Event("change", { bubbles: true }));
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function videoTranscriptionHandler(msgEvent) {
|
|
const transcriptionData = msgEvent.detail;
|
|
const transcriptionText = transcriptionData.transcriptionText;
|
|
const transcriptionNodeID = parseInt(transcriptionData.nodeID);
|
|
|
|
if(transcriptionData.success) {
|
|
const transcriptionNode = app.graph.getNodeById(transcriptionNodeID);
|
|
if(transcriptionNode !== null && transcriptionNode !== undefined) {
|
|
// Find the prompt widget (where transcription is displayed)
|
|
const promptWidget = transcriptionNode.widgets.find(widget => widget.name === "prompt");
|
|
if(promptWidget && promptWidget.inputEl) {
|
|
promptWidget.inputEl.value = transcriptionText;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function videoOutputsHandler(msgEvent) {
|
|
const outputData = msgEvent.detail;
|
|
const draftId = outputData.draftId || "";
|
|
const videoId = outputData.videoId || "";
|
|
const nodeID = outputData.nodeID;
|
|
|
|
if(outputData.success && nodeID !== undefined && nodeID !== null) {
|
|
const nodeIdInt = typeof nodeID === 'string' ? parseInt(nodeID) : nodeID;
|
|
const outputNode = app.graph.getNodeById(nodeIdInt);
|
|
|
|
if(outputNode !== null && outputNode !== undefined) {
|
|
const draftIdWidget = outputNode.widgets.find(widget => widget.name === "draftId");
|
|
const videoIdWidget = outputNode.widgets.find(widget => widget.name === "videoId");
|
|
|
|
if(draftIdWidget) {
|
|
if(draftIdWidget.value !== undefined) draftIdWidget.value = draftId;
|
|
if(draftIdWidget.inputEl) {
|
|
draftIdWidget.inputEl.value = draftId;
|
|
draftIdWidget.inputEl.dispatchEvent(new Event('input', { bubbles: true }));
|
|
draftIdWidget.inputEl.dispatchEvent(new Event('change', { bubbles: true }));
|
|
}
|
|
}
|
|
|
|
if(videoIdWidget) {
|
|
if(videoIdWidget.value !== undefined) videoIdWidget.value = videoId;
|
|
if(videoIdWidget.inputEl) {
|
|
videoIdWidget.inputEl.value = videoId;
|
|
videoIdWidget.inputEl.dispatchEvent(new Event('input', { bubbles: true }));
|
|
videoIdWidget.inputEl.dispatchEvent(new Event('change', { bubbles: true }));
|
|
}
|
|
}
|
|
|
|
outputNode.setDirtyCanvas(true);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function notifyUser(message, type="info", title = "Runware", life = 4.5) {
|
|
app.extensionManager.toast.add({
|
|
severity: type, // 'info', 'success', 'warn', 'error' \\
|
|
summary: title,
|
|
detail: message,
|
|
life: Math.floor(life * 1000)
|
|
});
|
|
}
|
|
|
|
async function promptEnhanceHandler(e) {
|
|
if(e.ctrlKey && e.altKey && e.key.toLowerCase() === 'e') {
|
|
const userPrompt = e.target.value.trim();
|
|
if(userPrompt.length <= 1) {
|
|
notifyUser("Prompt Is Too Short!", "error", "Runware Prompt Enhancer");
|
|
return;
|
|
} else if(userPrompt.length > 300) {
|
|
notifyUser("Prompt Must Not Exceed 300 Characters!", "error", "Runware Prompt Enhancer");
|
|
return;
|
|
}
|
|
const enhanceResults = await runwareLocalAPI.enhancePrompt(userPrompt);
|
|
if(enhanceResults.success) {
|
|
e.target.value = enhanceResults.enhancedPrompt;
|
|
} else {
|
|
notifyUser(enhanceResults.error, "error", "Runware Prompt Enhancer");
|
|
}
|
|
}
|
|
}
|
|
|
|
function remNode(node) {
|
|
app.graph.remove(node);
|
|
app.graph.setDirtyCanvas(true,true);
|
|
}
|
|
|
|
async function APIKeyHandler(apiManagerNode) {
|
|
const widgets = apiManagerNode.widgets;
|
|
for(const widget of widgets) {
|
|
if(widget.name === "API Key") {
|
|
appendWidgetCB(widget, async function(...args) {
|
|
if(openDialog) return;
|
|
const apiKey = args[0].trim();
|
|
if(apiKey.length < 30) {
|
|
notifyUser("Invalid API Key Set, Please Try Again!", "error", "Runware API Manager");
|
|
return;
|
|
}
|
|
const setAPIKeyResults = await runwareLocalAPI.setAPIKey(apiKey);
|
|
if(setAPIKeyResults.success) {
|
|
remNode(apiManagerNode);
|
|
notifyUser("API Key Set Successfully!", "success", "Runware API Manager");
|
|
} else {
|
|
notifyUser(setAPIKeyResults.error, "error", "Runware API Manager");
|
|
}
|
|
});
|
|
} else if(widget.name === "Max Timeout") {
|
|
if(lastTimeout) widget.value = lastTimeout;
|
|
appendWidgetCB(widget, async function(...args) {
|
|
const maxTimeout = parseInt(args[0]);
|
|
if(isNaN(maxTimeout) || maxTimeout < TIMEOUT_RANGE.min || maxTimeout > TIMEOUT_RANGE.max) {
|
|
notifyUser(`Invalid Timeout Value! Must be between ${TIMEOUT_RANGE.min} and ${TIMEOUT_RANGE.max} seconds.`, "error", "Runware API Manager");
|
|
widget.value = lastTimeout || TIMEOUT_RANGE.default;
|
|
return;
|
|
}
|
|
const setTimeoutResults = await runwareLocalAPI.setTimeout(maxTimeout);
|
|
if(setTimeoutResults.success) {
|
|
notifyUser("Timeout Set Successfully!", "success", "Runware API Manager");
|
|
lastTimeout = maxTimeout;
|
|
} else {
|
|
widget.value = lastTimeout || TIMEOUT_RANGE.default;
|
|
notifyUser(setTimeoutResults.error, "error", "Runware API Manager");
|
|
}
|
|
});
|
|
} else if(widget.name === "Image Output Format") {
|
|
if(lastOutputFormat) widget.value = lastOutputFormat;
|
|
appendWidgetCB(widget, async function(...args) {
|
|
const outputFormat = args[0].trim().toUpperCase();
|
|
const setFormatResults = await runwareLocalAPI.setOutputFormat(outputFormat);
|
|
if(setFormatResults.success) {
|
|
notifyUser("Default Image Output Format Set Successfully!", "success", "Runware API Manager");
|
|
lastOutputFormat = outputFormat;
|
|
} else {
|
|
notifyUser(setFormatResults.error, "error", "Runware API Manager");
|
|
}
|
|
});
|
|
} else if(widget.name === "Image Output Quality") {
|
|
if(lastOutputQuality) widget.value = lastOutputQuality;
|
|
appendWidgetCB(widget, async function(...args) {
|
|
const outputQuality = parseInt(args[0]);
|
|
if(isNaN(outputQuality) || outputQuality < OUTPUT_QUALITY_RANGE.min || outputQuality > OUTPUT_QUALITY_RANGE.max) {
|
|
notifyUser(`Invalid Quality Value! Must be between ${OUTPUT_QUALITY_RANGE.min} and ${OUTPUT_QUALITY_RANGE.max}.`, "error", "Runware API Manager");
|
|
widget.value = lastOutputQuality || OUTPUT_QUALITY_RANGE.default;
|
|
return;
|
|
}
|
|
const setQualityResults = await runwareLocalAPI.setOutputQuality(outputQuality);
|
|
if(setQualityResults.success) {
|
|
notifyUser("Default Image Output Quality Set Successfully!", "success", "Runware API Manager");
|
|
lastOutputQuality = outputQuality;
|
|
} else {
|
|
widget.value = lastOutputQuality || OUTPUT_QUALITY_RANGE.default;
|
|
notifyUser(setQualityResults.error, "error", "Runware API Manager");
|
|
}
|
|
});
|
|
} else if(widget.name === "Enable Images Caching") {
|
|
if(lastEnableImagesCaching !== null) widget.value = lastEnableImagesCaching;
|
|
appendWidgetCB(widget, async function(...args) {
|
|
const enableCaching = args[0];
|
|
const setCachingResults = await runwareLocalAPI.setEnableImagesCaching(enableCaching);
|
|
if(setCachingResults.success) {
|
|
notifyUser("Image Caching Setting Updated Successfully!", "success", "Runware API Manager");
|
|
lastEnableImagesCaching = enableCaching;
|
|
} else {
|
|
widget.value = lastEnableImagesCaching;
|
|
notifyUser(setCachingResults.error, "error", "Runware API Manager");
|
|
}
|
|
});
|
|
} else if(widget.name === "Min Image Cache Size") {
|
|
if(lastMinImageCacheSize !== false) widget.value = lastMinImageCacheSize;
|
|
appendWidgetCB(widget, async function(...args) {
|
|
const minCacheSize = parseFloat(args[0]);
|
|
if(isNaN(minCacheSize) || minCacheSize < CACHE_SIZE_RANGE.min || minCacheSize > CACHE_SIZE_RANGE.max) {
|
|
notifyUser(`Invalid cache size! Must be between ${CACHE_SIZE_RANGE.min} KB and ${CACHE_SIZE_RANGE.max} KB.`, "error", "Runware API Manager");
|
|
widget.value = lastMinImageCacheSize || CACHE_SIZE_RANGE.default;
|
|
return;
|
|
}
|
|
const setCacheSizeResults = await runwareLocalAPI.setMinImageCacheSize(minCacheSize);
|
|
if(setCacheSizeResults.success) {
|
|
notifyUser("Minimum Image Cache Size Updated Successfully!", "success", "Runware API Manager");
|
|
lastMinImageCacheSize = minCacheSize;
|
|
} else {
|
|
widget.value = lastMinImageCacheSize || CACHE_SIZE_RANGE.default;
|
|
notifyUser(setCacheSizeResults.error, "error", "Runware API Manager");
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
function addTriggerWords(prompt, triggerWords) {
|
|
if (!triggerWords?.trim()) return prompt;
|
|
const cleanedTriggerWords = triggerWords
|
|
.trim()
|
|
.replace(/,\s*$/, '')
|
|
.split(',')
|
|
.map(word => word.trim())
|
|
.filter(word => word.length);
|
|
if (!prompt?.trim()) return cleanedTriggerWords.join(', ');
|
|
const wordsToAdd = cleanedTriggerWords.filter(word =>
|
|
!new RegExp(`\\b${word}\\b`, 'i').test(prompt)
|
|
);
|
|
return wordsToAdd.length
|
|
? `${prompt}${prompt.endsWith(',') ? ' ' : ', '}${wordsToAdd.join(', ')}`
|
|
: prompt;
|
|
}
|
|
|
|
function handleCustomErrors(errObj) {
|
|
const errData = errObj.detail;
|
|
const errCode = errData.errorCode;
|
|
if(errCode === 401 && !openDialog) {
|
|
const dialog = new comfyAPI.asyncDialog.ComfyAsyncDialog();
|
|
const htmlContent = `
|
|
<center>
|
|
<div style="padding: auto 200px; text-align: center;">
|
|
<h2>Runware Inference Error</h2>
|
|
<h4>Your API Key is Invalid Or Undefined. You Need To Update It.</h4>
|
|
<form method="POST" id="runwareAPIKey">
|
|
<input
|
|
id="apiKey"
|
|
type="text"
|
|
placeholder="Enter Your API Key ..." minlength="30" maxlength="48"
|
|
style="padding: 5px; min-width: 300px; text-align: center; margin-top: 10px;" required>
|
|
|
|
<div style="margin-top: 15px; display: flex; justify-content: center; gap: 10px;">
|
|
<button id="setAPIKeyBTN" style="padding: 8px 15px; background-color: #6c5ce7; color: #ccc;">Set Your API Key</button>
|
|
<button id="getAPIKeyBTN" style="padding: 8px 15px; background-color: #dfe6e9; color: #000;">Create New API Key</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</center>
|
|
`;
|
|
dialog.showModal(htmlContent).then(() => {
|
|
openDialog = false;
|
|
});
|
|
openDialog = true;
|
|
dialog.element.addEventListener('close', () => {
|
|
openDialog = false;
|
|
});
|
|
|
|
const runwareAPIForm = document.getElementById("runwareAPIKey");
|
|
const apiKeyInput = document.getElementById("apiKey");
|
|
const getAPIKeyBTN = document.getElementById("getAPIKeyBTN");
|
|
const setAPIKeyBTN = document.getElementById("setAPIKeyBTN");
|
|
|
|
getAPIKeyBTN.onclick = (e) => {
|
|
e.preventDefault();
|
|
window.open("https://my.runware.ai/keys?utm_source=comfyui&utm_medium=referral&utm_campaign=comfyui_api_key_creation", "_blank");
|
|
};
|
|
|
|
async function authUser(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
const apiKey = apiKeyInput.value.trim();
|
|
if(apiKey.length < 30) {
|
|
runwareAPIForm.reportValidity();
|
|
return;
|
|
// notifyUser("Invalid API Key Set, Please Try Again!", "error", "Runware API Manager");
|
|
// return;
|
|
} else {
|
|
const setAPIKeyResults = await runwareLocalAPI.setAPIKey(apiKey);
|
|
if(setAPIKeyResults.success) {
|
|
dialog.close();
|
|
openDialog = false;
|
|
notifyUser("API Key Set Successfully!", "success", "Runware API Manager");
|
|
} else {
|
|
notifyUser(setAPIKeyResults.error, "error", "Runware API Manager");
|
|
}
|
|
}
|
|
};
|
|
|
|
setAPIKeyBTN.onclick = async (e) => {
|
|
authUser(e);
|
|
};
|
|
|
|
runwareAPIForm.onsubmit = async (e) => {
|
|
authUser(e);
|
|
};
|
|
}
|
|
}
|
|
|
|
function appendWidgetCB(node, newCB) {
|
|
const oldNodeCB = node.callback;
|
|
if(typeof oldNodeCB === "function") {
|
|
node.callback = function(...args) {
|
|
oldNodeCB?.apply(this, args);
|
|
newCB?.apply(this, args);
|
|
}
|
|
} else {
|
|
node.callback = newCB;
|
|
}
|
|
}
|
|
|
|
async function syncDimensionsNodeHandler(node, dimensionsWidget) {
|
|
const nodeWidgets = node.widgets;
|
|
let widthWidget = false, heightWidget = false;
|
|
for(const nodeWidget of nodeWidgets) {
|
|
const widgetName = nodeWidget.name;
|
|
const widgetType = nodeWidget.type;
|
|
if(widgetName === "width" && widgetType === "number") widthWidget = nodeWidget;
|
|
if(widgetName === "height" && widgetType === "number") heightWidget = nodeWidget;
|
|
}
|
|
|
|
appendWidgetCB(dimensionsWidget, function(...args) {
|
|
const chosenDimension = args[0];
|
|
if(chosenDimension === "Custom" || chosenDimension === "None") return;
|
|
const dimensionValue = DEFAULT_DIMENSIONS_LIST[chosenDimension];
|
|
if(!dimensionValue) return;
|
|
const [width, height] = dimensionValue.split("x");
|
|
widthWidget.callback(width, "customSetOperation");
|
|
heightWidget.callback(height, "customSetOperation");
|
|
});
|
|
|
|
if(widthWidget !== false) {
|
|
appendWidgetCB(widthWidget, function(...args) {
|
|
if(args[1] === "customSetOperation") return;
|
|
dimensionsWidget.value = "Custom";
|
|
});
|
|
}
|
|
|
|
if(heightWidget !== false) {
|
|
appendWidgetCB(heightWidget, function(...args) {
|
|
if(args[1] === "customSetOperation") return;
|
|
dimensionsWidget.value = "Custom";
|
|
});
|
|
}
|
|
}
|
|
|
|
const shortenAirCode = input => !input || !input.startsWith('urn:air:') ? input : input.match(/urn:air:.*?:.*?(civitai:\d+@\d+)$/)?.[1] || input;
|
|
|
|
async function searchNodeHandler(searchNode, searchInputWidget) {
|
|
const searchNodeWidgets = searchNode.widgets;
|
|
let modelArchWidget = false, modelTypeWidget = false, modelListWidget = false,
|
|
defaultWidgetValues = {}, triggerWordsList = {
|
|
"civitai:58390@62833": "", "civitai:82098@87153": "", "civitai:122359@135867": "",
|
|
"civitai:14171@16677": "mix4", "civitai:13941@16576": "", "civitai:25995@32988": "full body, chibi"
|
|
}, embeddingTriggerWordsList = {
|
|
"civitai:7808@9208": "easynegative", "civitai:4629@5637": "ng_deepnegative_v1_75t",
|
|
"civitai:56519@60938": "negative_hand", "civitai:72437@77169": "BadDream",
|
|
"civitai:11772@25820": "verybadimagenegative_v1.3", "civitai:71961@94057": "FastNegativeV2",
|
|
};
|
|
let isLora = false, isControlNet = false, isEmbedding = false, isVAE = false, modelTypeValue = false;
|
|
if(searchNode.comfyClass === RUNWARE_NODE_TYPES.LORASEARCH) isLora = true;
|
|
if(searchNode.comfyClass === RUNWARE_NODE_TYPES.CONTROLNET) isControlNet = true;
|
|
if(searchNode.comfyClass === RUNWARE_NODE_TYPES.EMBEDDING) isEmbedding = true;
|
|
if(searchNode.comfyClass === RUNWARE_NODE_TYPES.VAE) isVAE = true;
|
|
|
|
for(const searchWidget of searchNodeWidgets) {
|
|
const widgetName = searchWidget.name;
|
|
const widgetType = searchWidget.type;
|
|
if(widgetName === "Model Architecture" && widgetType === "combo") {
|
|
modelArchWidget = searchWidget;
|
|
defaultWidgetValues["modelArch"] = searchWidget.options.values;
|
|
}
|
|
if(MODEL_TYPES_TERMS.includes(widgetName) && widgetType === "combo") {
|
|
modelTypeWidget = searchWidget;
|
|
defaultWidgetValues["modelType"] = searchWidget.options.values;
|
|
}
|
|
if(MODEL_LIST_TERMS.includes(widgetName) && widgetType === "combo") {
|
|
modelListWidget = searchWidget;
|
|
defaultWidgetValues["modelList"] = searchWidget.options.values;
|
|
}
|
|
}
|
|
|
|
function resetValues() {
|
|
if(modelArchWidget) {
|
|
modelArchWidget.options.values = defaultWidgetValues["modelArch"];
|
|
modelArchWidget.value = defaultWidgetValues["modelArch"][0];
|
|
}
|
|
if(modelTypeWidget) {
|
|
modelTypeWidget.options.values = defaultWidgetValues["modelType"];
|
|
modelTypeWidget.value = defaultWidgetValues["modelType"][0];
|
|
}
|
|
if(modelListWidget) {
|
|
modelListWidget.options.values = defaultWidgetValues["modelList"];
|
|
modelListWidget.value = defaultWidgetValues["modelList"][0];
|
|
}
|
|
}
|
|
|
|
async function searchModels(exactQuery = null, returnOutput = false) {
|
|
let searchQuery;
|
|
if(exactQuery) {
|
|
searchQuery = exactQuery;
|
|
} else {
|
|
searchQuery = searchInputWidget.value.trim();
|
|
}
|
|
searchQuery = shortenAirCode(searchQuery);
|
|
const modelArchValue = DEFAULT_MODELS_ARCH_LIST[modelArchWidget.value];
|
|
if(isControlNet) {
|
|
modelTypeValue = DEFAULT_CONTROLNET_CONDITIONING_LIST[modelTypeWidget.value];
|
|
} else {
|
|
if(isEmbedding) {
|
|
modelTypeValue = "embeddings";
|
|
} else if(isVAE) {
|
|
modelTypeValue = "vae";
|
|
} else {
|
|
modelTypeValue = modelTypeWidget.value.toLowerCase().replace("model", "").trim();
|
|
}
|
|
}
|
|
|
|
let modelSearchResults = null;
|
|
if(isControlNet) {
|
|
modelSearchResults = await runwareLocalAPI.modelSearch(searchQuery, modelArchValue, "", "controlnet", modelTypeValue);
|
|
} else if(isLora || isEmbedding || isVAE) {
|
|
modelSearchResults = await runwareLocalAPI.modelSearch(searchQuery, modelArchValue, "", modelTypeValue);
|
|
} else {
|
|
modelSearchResults = await runwareLocalAPI.modelSearch(searchQuery, modelArchValue, modelTypeValue);
|
|
}
|
|
|
|
if(modelSearchResults.success) {
|
|
const modelListArray = [];
|
|
modelSearchResults.modelList.forEach(modelObj => {
|
|
if(isLora) triggerWordsList[modelObj.air] = modelObj.positiveTriggerWords?.trim() || false;
|
|
if(isEmbedding) embeddingTriggerWordsList[modelObj.air] = modelObj.positiveTriggerWords?.trim() || false;
|
|
modelListArray.push(`${modelObj.air} (${modelObj.name} ${modelObj.version})`);
|
|
});
|
|
|
|
if(exactQuery) {
|
|
const extraSearch = await searchModels(null, true);
|
|
if(extraSearch) {
|
|
const newModelList = [...new Set([...modelListArray, ...extraSearch])];
|
|
modelListWidget.options.values = newModelList;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(returnOutput) return modelListArray;
|
|
modelListWidget.options.values = modelListArray;
|
|
modelListWidget.value = modelListArray[0];
|
|
} else {
|
|
if(returnOutput) return false;
|
|
if(exactQuery) {
|
|
notifyUser("Failed To Load Workflow's Model List Value!", "error", "Runware Search");
|
|
return;
|
|
}
|
|
notifyUser(modelSearchResults.error, "error", "Runware Search");
|
|
}
|
|
}
|
|
|
|
function findTargetWidget(currentNode, targetWidgetName, depth = 1) {
|
|
try {
|
|
if(depth < 0) return false;
|
|
const nodeOutputs = currentNode.outputs;
|
|
if(nodeOutputs.length === 0) return false;
|
|
const outputLinks = nodeOutputs[0].links;
|
|
if(outputLinks.length === 0) return false;
|
|
for(const linkID of outputLinks) {
|
|
const linkInfo = app.graph.links[linkID];
|
|
const linkNodeID = linkInfo.target_id;
|
|
if(!linkNodeID) continue;
|
|
const targetNode = app.graph.getNodeById(linkNodeID);
|
|
let widgetFound = false;
|
|
if(targetNode.widgets !== undefined && targetNode.widgets.length > 0){
|
|
widgetFound = targetNode.widgets.find(widget => widget.name === targetWidgetName) || false;
|
|
}
|
|
if(widgetFound) {
|
|
return widgetFound;
|
|
} else {
|
|
return findTargetWidget(targetNode, targetWidgetName, depth - 1);
|
|
}
|
|
}
|
|
} catch(e) {
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if(isLora) {
|
|
const runwareButton = document.createElement("button");
|
|
runwareButton.textContent = "Add Lora To Prompt";
|
|
runwareButton.style = "max-height: 50px; background-color: #333; color: #ccc;";
|
|
searchNode.addDOMWidget("addLora", "custom", runwareButton, {
|
|
selectOn: ['focus', 'click'],
|
|
});
|
|
|
|
runwareButton.addEventListener("click", async () => {
|
|
const chosenLora = modelListWidget.value.split(" ")[0];
|
|
if(!triggerWordsList.hasOwnProperty(chosenLora)) return;
|
|
const triggerWords = triggerWordsList[chosenLora];
|
|
if(triggerWords.length > 0) {
|
|
const positivePromptWidget = findTargetWidget(searchNode, "positivePrompt");
|
|
if(!positivePromptWidget) {
|
|
notifyUser("Lora Node Is Not Linked To Any Runware Inference Node!", "error", "Runware Lora Connector");
|
|
return;
|
|
}
|
|
const positivePromptWithTrigger = addTriggerWords(positivePromptWidget.value, triggerWords);
|
|
if(positivePromptWidget.value === positivePromptWithTrigger) {
|
|
notifyUser("Trigger Words Already Exists", "info", "Runware Lora Connector");
|
|
return;
|
|
}
|
|
positivePromptWidget.value = positivePromptWithTrigger;
|
|
notifyUser("Trigger Words Added Successfully!", "success", "Runware Lora Connector");
|
|
} else {
|
|
notifyUser("No Trigger Words Found For This Lora!", "warn", "Runware Lora Connector");
|
|
}
|
|
});
|
|
} else if(isEmbedding) {
|
|
const runwareButton = document.createElement("button");
|
|
runwareButton.textContent = "Add Embedding To Negative Prompt";
|
|
runwareButton.style = "max-height: 50px; background-color: #333; color: #ccc;";
|
|
searchNode.addDOMWidget("addEmbedding", "custom", runwareButton, {
|
|
selectOn: ['focus', 'click'],
|
|
});
|
|
|
|
runwareButton.addEventListener("click", async () => {
|
|
const chosenEmbedding = modelListWidget.value.split(" ")[0];
|
|
if (!embeddingTriggerWordsList.hasOwnProperty(chosenEmbedding)) return;
|
|
const triggerWords = embeddingTriggerWordsList[chosenEmbedding];
|
|
if(triggerWords.length > 0) {
|
|
const negativePromptWidget = findTargetWidget(searchNode, "negativePrompt");
|
|
if(!negativePromptWidget) {
|
|
notifyUser("Embedding Node Is Not Linked To Any Runware Inference Node!", "error", "Runware Embedding Connector");
|
|
return;
|
|
}
|
|
const negativePromptWithTrigger = addTriggerWords(negativePromptWidget.value, triggerWords);
|
|
if(negativePromptWidget.value === negativePromptWithTrigger) {
|
|
notifyUser("Trigger Words Already Exists", "info", "Runware Embedding Connector");
|
|
return;
|
|
}
|
|
negativePromptWidget.value = negativePromptWithTrigger;
|
|
notifyUser("Trigger Words Added Successfully!", "success", "Runware Embedding Connector");
|
|
} else {
|
|
notifyUser("No Trigger Words Found For This Embedding!", "warn", "Runware Embedding Connector");
|
|
}
|
|
});
|
|
}
|
|
|
|
appendWidgetCB(searchInputWidget, async function(...args) {
|
|
let searchQuery = args[0].trim();
|
|
const shortenSearchQuery = shortenAirCode(searchQuery);
|
|
if(searchQuery !== shortenSearchQuery) {
|
|
searchQuery = shortenSearchQuery;
|
|
searchInputWidget.value = searchQuery;
|
|
}
|
|
if(searchQuery.length === 0) {
|
|
resetValues();
|
|
} else if(searchQuery.length < 2) {
|
|
notifyUser("Invalid Search Value, Search Query must be at least 2 characters!", "error", "Runware Search");
|
|
return;
|
|
} else {
|
|
await searchModels();
|
|
}
|
|
});
|
|
|
|
appendWidgetCB(modelArchWidget, async function(...args) {
|
|
await searchModels();
|
|
});
|
|
|
|
if(!isVAE && !isEmbedding) {
|
|
appendWidgetCB(modelTypeWidget, async function(...args) {
|
|
await searchModels();
|
|
});
|
|
}
|
|
|
|
appendWidgetCB(searchNode, async function(...args) {
|
|
try {
|
|
let modelListValues = modelListWidget.options.values;
|
|
if(modelListValues.length <= 0) return;
|
|
modelListValues = modelListValues.map(model => model.split(" ")[0]);
|
|
const modelListCRValue = modelListWidget.value.split(" ")[0];
|
|
if(!modelListValues.includes(modelListCRValue)) {
|
|
searchModels(modelListCRValue);
|
|
}
|
|
} catch(e) {}
|
|
});
|
|
}
|
|
|
|
function toggleWidgetEnabled(widget, enabled, node) {
|
|
if (!widget || !widget.name) return;
|
|
|
|
// Use the same simple approach as videoInferenceDimensionsHandler
|
|
// Set widget disabled property
|
|
widget.disabled = !enabled;
|
|
|
|
// Disable/enable widgets using inputEl if available (same pattern as videoInferenceDimensionsHandler)
|
|
if (widget.inputEl) {
|
|
widget.inputEl.disabled = !enabled;
|
|
widget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
widget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
widget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
// For combo/dropdown widgets, also try to disable the options element
|
|
if (widget.options && widget.options.element) {
|
|
widget.options.element.disabled = !enabled;
|
|
widget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
widget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available (same as videoInferenceDimensionsHandler)
|
|
if (!widget.inputEl && node) {
|
|
const nodeElement = node.htmlElements?.widgetsContainer || node.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${widget.name}"], textarea[name="${widget.name}"], select[name="${widget.name}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function videoUpscalerToggleHandler(videoUpscalerNode) {
|
|
if (!videoUpscalerNode?.widgets) return;
|
|
|
|
const useUpscaleFactorWidget = videoUpscalerNode.widgets.find(w => w && w.name === "useUpscaleFactor");
|
|
const upscaleFactorWidget = videoUpscalerNode.widgets.find(w => w && w.name === "upscaleFactor");
|
|
const useFpsWidget = videoUpscalerNode.widgets.find(w => w && w.name === "useFps");
|
|
const fpsWidget = videoUpscalerNode.widgets.find(w => w && w.name === "fps");
|
|
const useDimensionWidget = videoUpscalerNode.widgets.find(w => w && w.name === "useDimension");
|
|
const widthWidget = videoUpscalerNode.widgets.find(w => w && w.name === "width");
|
|
const heightWidget = videoUpscalerNode.widgets.find(w => w && w.name === "height");
|
|
|
|
function applyToggleState() {
|
|
if (useUpscaleFactorWidget && upscaleFactorWidget) {
|
|
const enabled = useUpscaleFactorWidget.value === true;
|
|
toggleWidgetEnabled(upscaleFactorWidget, enabled, videoUpscalerNode);
|
|
}
|
|
|
|
if (useFpsWidget && fpsWidget) {
|
|
const enabled = useFpsWidget.value === true;
|
|
toggleWidgetEnabled(fpsWidget, enabled, videoUpscalerNode);
|
|
}
|
|
|
|
if (useDimensionWidget && widthWidget && heightWidget) {
|
|
const enabled = useDimensionWidget.value === "custom";
|
|
toggleWidgetEnabled(widthWidget, enabled, videoUpscalerNode);
|
|
toggleWidgetEnabled(heightWidget, enabled, videoUpscalerNode);
|
|
}
|
|
|
|
videoUpscalerNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Initialize state once widgets are rendered
|
|
setTimeout(applyToggleState, 100);
|
|
|
|
if (useUpscaleFactorWidget) {
|
|
appendWidgetCB(useUpscaleFactorWidget, () => {
|
|
setTimeout(applyToggleState, 50);
|
|
});
|
|
}
|
|
if (useFpsWidget) {
|
|
appendWidgetCB(useFpsWidget, () => {
|
|
setTimeout(applyToggleState, 50);
|
|
});
|
|
}
|
|
if (useDimensionWidget) {
|
|
appendWidgetCB(useDimensionWidget, () => {
|
|
setTimeout(applyToggleState, 50);
|
|
});
|
|
}
|
|
}
|
|
|
|
function useParameterToggleHandler(node) {
|
|
// Prevent double registration
|
|
if (node._useParameterToggleHandlerRegistered) return;
|
|
node._useParameterToggleHandlerRegistered = true;
|
|
|
|
// Define explicit mappings: "useParameterName" -> ["parameter1", "parameter2", ...]
|
|
const parameterMappings = {
|
|
// Image Inference
|
|
"useSteps": ["steps"],
|
|
"useSeed": ["seed"],
|
|
"useCFGScale": ["cfgScale"], // Image inference uses lowercase cfgScale
|
|
"useScheduler": ["scheduler"],
|
|
"useClipSkip": ["clipSkip"],
|
|
"useUpscaleFactor": ["upscaleFactor"],
|
|
|
|
// Video Inference
|
|
"useCustomDimensions": ["width", "height"], // Note: Also handled separately in videoInferenceDimensionsHandler
|
|
"useDuration": ["duration"],
|
|
"useFps": ["fps"],
|
|
"useSchedulers": ["scheduler"],
|
|
"useCFGScale": ["cfgScale"],
|
|
"useTtl": ["ttl"],
|
|
// useSteps and useSeed are same as image inference, handled by fallback
|
|
|
|
// Upscaler specific mappings (override for nodes that have CFGScale with capital C)
|
|
"usePrompts": ["positivePrompt", "negativePrompt"],
|
|
"useClarityParams": ["controlNetWeight", "strength", "scheduler"],
|
|
"useCCSRParams": ["colorFix", "tileDiffusion"],
|
|
"useLatentParams": ["clipSkip"],
|
|
|
|
// Audio Inference
|
|
"usePositivePrompt": ["positivePrompt"],
|
|
"useSeed": ["seed"],
|
|
"useSteps": ["steps"],
|
|
"useStrength": ["strength"],
|
|
|
|
// Accelerator Options
|
|
"useCacheDistance": ["cacheDistance"],
|
|
"useTeaCacheDistance": ["teaCacheDistance"],
|
|
"useDeepCacheOptions": ["deepCacheInterval", "deepCacheBranchId"],
|
|
"useCacheSteps": ["cacheStartStep", "cacheEndStep"],
|
|
"useCachePercentageSteps": ["cacheStartStepPercentage", "cacheEndStepPercentage"],
|
|
"useCacheMaxConsecutiveSteps": ["cacheMaxConsecutiveSteps"],
|
|
|
|
// Bytedance Provider Settings
|
|
"useCameraFixed": ["cameraFixed"],
|
|
"useMaxSequentialImages": ["maxSequentialImages"],
|
|
"useFastMode": ["fastMode"],
|
|
|
|
// OpenAI Provider Settings (these are dropdowns, not booleans, but handle them anyway)
|
|
"useBackground": ["background"],
|
|
"useStyle": ["style"],
|
|
|
|
// Mask Margin
|
|
"Mask Margin": ["maskMargin"],
|
|
};
|
|
|
|
// Node-specific overrides for parameters that have different names in different nodes
|
|
// Format: nodeClass -> { "useParam": ["param1", "param2"] }
|
|
const nodeSpecificMappings = {
|
|
// Upscaler uses CFGScale (capital C) instead of cfgScale
|
|
[RUNWARE_NODE_TYPES.UPSCALER]: {
|
|
"useCFGScale": ["CFGScale"],
|
|
},
|
|
// Audio Inference uses CFGScale (capital C)
|
|
[RUNWARE_NODE_TYPES.AUDIOINFERENCE]: {
|
|
"useCFGScale": ["CFGScale"],
|
|
},
|
|
};
|
|
|
|
// Wait for widgets to be ready
|
|
function initializeHandler() {
|
|
if (!node.widgets || node.widgets.length === 0) {
|
|
setTimeout(initializeHandler, 100);
|
|
return;
|
|
}
|
|
|
|
// Find all "use" widgets and their corresponding parameter widgets upfront (like videoInferenceDimensionsHandler does)
|
|
const togglePairs = [];
|
|
|
|
// Find all "use" widgets
|
|
node.widgets.forEach(widget => {
|
|
if (!widget || !widget.name) return;
|
|
|
|
const isUseWidget = widget.name.startsWith("use") && (widget.type === "BOOLEAN" || widget.type === "COMBO");
|
|
const isMaskMargin = widget.name === "Mask Margin" && widget.type === "BOOLEAN";
|
|
|
|
if (!isUseWidget && !isMaskMargin) return;
|
|
|
|
const useParamName = widget.name;
|
|
|
|
// Get corresponding parameters - check node-specific mappings first, then general mappings
|
|
let paramNames = [];
|
|
const nodeClass = node.comfyClass;
|
|
if (nodeClass && nodeSpecificMappings[nodeClass] && nodeSpecificMappings[nodeClass][useParamName]) {
|
|
paramNames = nodeSpecificMappings[nodeClass][useParamName];
|
|
} else {
|
|
paramNames = parameterMappings[useParamName] || [];
|
|
}
|
|
|
|
// Handle special case: remove "use" prefix and lowercase first letter
|
|
if (paramNames.length === 0) {
|
|
const paramName = useParamName.replace(/^use/, "").replace(/^[A-Z]/, (match) => match.toLowerCase());
|
|
paramNames = [paramName];
|
|
}
|
|
|
|
// Find the actual parameter widgets
|
|
const paramWidgets = [];
|
|
paramNames.forEach(paramName => {
|
|
const paramWidget = node.widgets.find(w => w && w.name === paramName);
|
|
if (paramWidget) {
|
|
paramWidgets.push(paramWidget);
|
|
} else {
|
|
// If mapped parameter doesn't exist, try fallback auto-detection
|
|
const fallbackParamName = useParamName.replace(/^use/, "").replace(/^[A-Z]/, (match) => match.toLowerCase());
|
|
if (fallbackParamName !== paramName) {
|
|
const fallbackWidget = node.widgets.find(w => w && w.name === fallbackParamName);
|
|
if (fallbackWidget) {
|
|
paramWidgets.push(fallbackWidget);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
if (paramWidgets.length > 0) {
|
|
togglePairs.push({
|
|
useWidget: widget,
|
|
paramWidgets: paramWidgets
|
|
});
|
|
}
|
|
});
|
|
|
|
// Create toggle functions for each pair (like toggleDimensionsEnabled in videoInferenceDimensionsHandler)
|
|
togglePairs.forEach(pair => {
|
|
const { useWidget, paramWidgets } = pair;
|
|
|
|
function toggleEnabled() {
|
|
// Determine if enabled based on widget type
|
|
let enabled = false;
|
|
if (useWidget.type === "BOOLEAN") {
|
|
enabled = useWidget.value === true;
|
|
} else if (useWidget.type === "COMBO") {
|
|
enabled = useWidget.value === "enable" || useWidget.value === "Enable";
|
|
}
|
|
|
|
// Apply to each parameter widget (exactly like toggleDimensionsEnabled does)
|
|
paramWidgets.forEach(paramWidget => {
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = node.htmlElements?.widgetsContainer || node.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramWidget.name}"], textarea[name="${paramWidget.name}"], select[name="${paramWidget.name}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback (exactly like videoInferenceDimensionsHandler does)
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
}
|
|
|
|
// Start initialization
|
|
setTimeout(initializeHandler, 200);
|
|
}
|
|
|
|
function upscalerToggleHandler(upscalerNode) {
|
|
// Find all "use" parameter widgets for Upscaler
|
|
const useUpscaleFactorWidget = upscalerNode.widgets.find(w => w.name === "useUpscaleFactor");
|
|
const upscaleFactorWidget = upscalerNode.widgets.find(w => w.name === "upscaleFactor");
|
|
const useStepsWidget = upscalerNode.widgets.find(w => w.name === "useSteps");
|
|
const stepsWidget = upscalerNode.widgets.find(w => w.name === "steps");
|
|
const useSeedWidget = upscalerNode.widgets.find(w => w.name === "useSeed");
|
|
const seedWidget = upscalerNode.widgets.find(w => w.name === "seed");
|
|
const useCFGScaleWidget = upscalerNode.widgets.find(w => w.name === "useCFGScale");
|
|
const cfgScaleWidget = upscalerNode.widgets.find(w => w.name === "CFGScale");
|
|
const usePromptsWidget = upscalerNode.widgets.find(w => w.name === "usePrompts");
|
|
const positivePromptWidget = upscalerNode.widgets.find(w => w.name === "positivePrompt");
|
|
const negativePromptWidget = upscalerNode.widgets.find(w => w.name === "negativePrompt");
|
|
const useClarityParamsWidget = upscalerNode.widgets.find(w => w.name === "useClarityParams");
|
|
const controlNetWeightWidget = upscalerNode.widgets.find(w => w.name === "controlNetWeight");
|
|
const strengthWidget = upscalerNode.widgets.find(w => w.name === "strength");
|
|
const schedulerWidget = upscalerNode.widgets.find(w => w.name === "scheduler");
|
|
const useCCSRParamsWidget = upscalerNode.widgets.find(w => w.name === "useCCSRParams");
|
|
const colorFixWidget = upscalerNode.widgets.find(w => w.name === "colorFix");
|
|
const tileDiffusionWidget = upscalerNode.widgets.find(w => w.name === "tileDiffusion");
|
|
const useLatentParamsWidget = upscalerNode.widgets.find(w => w.name === "useLatentParams");
|
|
const clipSkipWidget = upscalerNode.widgets.find(w => w.name === "clipSkip");
|
|
|
|
// Helper function to toggle widget enabled state (exact same pattern)
|
|
function toggleWidgetState(useWidget, paramWidgets, paramNames) {
|
|
if (!useWidget || !paramWidgets || paramWidgets.length === 0) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
// Apply to each parameter widget
|
|
paramWidgets.forEach((paramWidget, idx) => {
|
|
if (!paramWidget) return;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = upscalerNode.htmlElements?.widgetsContainer || upscalerNode.htmlElements;
|
|
if (nodeElement && paramNames[idx]) {
|
|
const input = nodeElement.querySelector(`input[name="${paramNames[idx]}"], textarea[name="${paramNames[idx]}"], select[name="${paramNames[idx]}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
upscalerNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up all toggle handlers
|
|
if (useUpscaleFactorWidget && upscaleFactorWidget) {
|
|
toggleWidgetState(useUpscaleFactorWidget, [upscaleFactorWidget], ["upscaleFactor"]);
|
|
}
|
|
|
|
if (useStepsWidget && stepsWidget) {
|
|
toggleWidgetState(useStepsWidget, [stepsWidget], ["steps"]);
|
|
}
|
|
|
|
if (useSeedWidget && seedWidget) {
|
|
toggleWidgetState(useSeedWidget, [seedWidget], ["seed"]);
|
|
}
|
|
|
|
if (useCFGScaleWidget && cfgScaleWidget) {
|
|
toggleWidgetState(useCFGScaleWidget, [cfgScaleWidget], ["CFGScale"]);
|
|
}
|
|
|
|
if (usePromptsWidget && positivePromptWidget && negativePromptWidget) {
|
|
toggleWidgetState(usePromptsWidget, [positivePromptWidget, negativePromptWidget], ["positivePrompt", "negativePrompt"]);
|
|
}
|
|
|
|
if (useClarityParamsWidget && controlNetWeightWidget && strengthWidget && schedulerWidget) {
|
|
toggleWidgetState(useClarityParamsWidget, [controlNetWeightWidget, strengthWidget, schedulerWidget], ["controlNetWeight", "strength", "scheduler"]);
|
|
}
|
|
|
|
if (useCCSRParamsWidget && colorFixWidget && tileDiffusionWidget) {
|
|
toggleWidgetState(useCCSRParamsWidget, [colorFixWidget, tileDiffusionWidget], ["colorFix", "tileDiffusion"]);
|
|
}
|
|
|
|
if (useLatentParamsWidget && clipSkipWidget) {
|
|
toggleWidgetState(useLatentParamsWidget, [clipSkipWidget], ["clipSkip"]);
|
|
}
|
|
|
|
const useTargetMegapixelsWidget = upscalerNode.widgets.find(w => w.name === "useTargetMegapixels");
|
|
const targetMegapixelsWidget = upscalerNode.widgets.find(w => w.name === "targetMegapixels");
|
|
if (useTargetMegapixelsWidget && targetMegapixelsWidget) {
|
|
toggleWidgetState(useTargetMegapixelsWidget, [targetMegapixelsWidget], ["targetMegapixels"]);
|
|
}
|
|
}
|
|
|
|
function imageUpscalerSettingsToggleHandler(settingsNode) {
|
|
const useEnhanceDetailsWidget = settingsNode.widgets.find(w => w.name === "useEnhanceDetails");
|
|
const enhanceDetailsWidget = settingsNode.widgets.find(w => w.name === "enhanceDetails");
|
|
const useRealismWidget = settingsNode.widgets.find(w => w.name === "useRealism");
|
|
const realismWidget = settingsNode.widgets.find(w => w.name === "realism");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "pointer" : "not-allowed";
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = settingsNode.htmlElements?.widgetsContainer || settingsNode.htmlElements;
|
|
if (nodeElement && paramName) {
|
|
const input = nodeElement.querySelector(
|
|
`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`
|
|
);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "pointer" : "not-allowed";
|
|
}
|
|
}
|
|
}
|
|
|
|
settingsNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
if (useEnhanceDetailsWidget && enhanceDetailsWidget) {
|
|
toggleWidgetState(useEnhanceDetailsWidget, enhanceDetailsWidget, "enhanceDetails");
|
|
}
|
|
if (useRealismWidget && realismWidget) {
|
|
toggleWidgetState(useRealismWidget, realismWidget, "realism");
|
|
}
|
|
}
|
|
|
|
function audioInferenceToggleHandler(audioInferenceNode) {
|
|
// Find all "use" parameter widgets for Audio Inference
|
|
const usePositivePromptWidget = audioInferenceNode.widgets.find(w => w.name === "usePositivePrompt");
|
|
const positivePromptWidget = audioInferenceNode.widgets.find(w => w.name === "positivePrompt");
|
|
const useDurationWidget = audioInferenceNode.widgets.find(w => w.name === "useDuration");
|
|
const durationWidget = audioInferenceNode.widgets.find(w => w.name === "duration");
|
|
const useSampleRateWidget = audioInferenceNode.widgets.find(w => w.name === "useSampleRate");
|
|
const sampleRateWidget = audioInferenceNode.widgets.find(w => w.name === "sampleRate");
|
|
const useBitrateWidget = audioInferenceNode.widgets.find(w => w.name === "useBitrate");
|
|
const bitrateWidget = audioInferenceNode.widgets.find(w => w.name === "bitrate");
|
|
const useSeedWidget = audioInferenceNode.widgets.find(w => w.name === "useSeed");
|
|
const seedWidget = audioInferenceNode.widgets.find(w => w.name === "seed");
|
|
const useStepsWidget = audioInferenceNode.widgets.find(w => w.name === "useSteps");
|
|
const stepsWidget = audioInferenceNode.widgets.find(w => w.name === "steps");
|
|
const useStrengthWidget = audioInferenceNode.widgets.find(w => w.name === "useStrength");
|
|
const strengthWidget = audioInferenceNode.widgets.find(w => w.name === "strength");
|
|
const useCFGScaleWidget = audioInferenceNode.widgets.find(w => w.name === "useCFGScale");
|
|
const CFGScaleWidget = audioInferenceNode.widgets.find(w => w.name === "CFGScale");
|
|
const useChannelsWidget = audioInferenceNode.widgets.find(w => w.name === "useChannels");
|
|
const channelsWidget = audioInferenceNode.widgets.find(w => w.name === "channels");
|
|
|
|
// Helper function to toggle widget enabled state (exact same pattern)
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = audioInferenceNode.htmlElements?.widgetsContainer || audioInferenceNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
audioInferenceNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up all toggle handlers
|
|
if (usePositivePromptWidget && positivePromptWidget) {
|
|
toggleWidgetState(usePositivePromptWidget, positivePromptWidget, "positivePrompt");
|
|
}
|
|
|
|
if (useDurationWidget && durationWidget) {
|
|
toggleWidgetState(useDurationWidget, durationWidget, "duration");
|
|
}
|
|
|
|
if (useSampleRateWidget && sampleRateWidget) {
|
|
toggleWidgetState(useSampleRateWidget, sampleRateWidget, "sampleRate");
|
|
}
|
|
|
|
if (useBitrateWidget && bitrateWidget) {
|
|
toggleWidgetState(useBitrateWidget, bitrateWidget, "bitrate");
|
|
}
|
|
|
|
if (useSeedWidget && seedWidget) {
|
|
toggleWidgetState(useSeedWidget, seedWidget, "seed");
|
|
}
|
|
|
|
if (useStepsWidget && stepsWidget) {
|
|
toggleWidgetState(useStepsWidget, stepsWidget, "steps");
|
|
}
|
|
|
|
if (useStrengthWidget && strengthWidget) {
|
|
toggleWidgetState(useStrengthWidget, strengthWidget, "strength");
|
|
}
|
|
|
|
if (useCFGScaleWidget && CFGScaleWidget) {
|
|
toggleWidgetState(useCFGScaleWidget, CFGScaleWidget, "CFGScale");
|
|
}
|
|
|
|
if (useChannelsWidget && channelsWidget) {
|
|
toggleWidgetState(useChannelsWidget, channelsWidget, "channels");
|
|
}
|
|
}
|
|
|
|
function audioSettingsToggleHandler(settingsNode) {
|
|
if (!settingsNode?.widgets) return;
|
|
|
|
const useTemperatureWidget = settingsNode.widgets.find(w => w && w.name === "useTemperature");
|
|
const temperatureWidget = settingsNode.widgets.find(w => w && w.name === "temperature");
|
|
const useAudioTemperatureWidget = settingsNode.widgets.find(w => w && w.name === "useAudioTemperature");
|
|
const audioTemperatureWidget = settingsNode.widgets.find(w => w && w.name === "audioTemperature");
|
|
const useTopKWidget = settingsNode.widgets.find(w => w && w.name === "useTopK");
|
|
const topKWidget = settingsNode.widgets.find(w => w && w.name === "topK");
|
|
const useIncludePrefixWidget = settingsNode.widgets.find(w => w && w.name === "useIncludePrefix");
|
|
const includePrefixWidget = settingsNode.widgets.find(w => w && w.name === "includePrefix");
|
|
const useLyricsWidget = settingsNode.widgets.find(w => w && w.name === "useLyrics");
|
|
const lyricsWidget = settingsNode.widgets.find(w => w && w.name === "lyrics");
|
|
const useInstrumentalWidget = settingsNode.widgets.find(w => w && w.name === "useInstrumental");
|
|
const instrumentalWidget = settingsNode.widgets.find(w => w && w.name === "instrumental");
|
|
const useLyricsOptimizerWidget = settingsNode.widgets.find(w => w && w.name === "useLyricsOptimizer");
|
|
const lyricsOptimizerWidget = settingsNode.widgets.find(w => w && w.name === "lyricsOptimizer");
|
|
const useGuidanceTypeWidget = settingsNode.widgets.find(w => w && w.name === "useGuidanceType");
|
|
const guidanceTypeWidget = settingsNode.widgets.find(w => w && w.name === "guidanceType");
|
|
const useLanguageBoostWidget = settingsNode.widgets.find(w => w && w.name === "useLanguageBoost");
|
|
const languageBoostWidget = settingsNode.widgets.find(w => w && w.name === "languageBoost");
|
|
const useTurboWidget = settingsNode.widgets.find(w => w && w.name === "useTurbo");
|
|
const turboWidget = settingsNode.widgets.find(w => w && w.name === "turbo");
|
|
const useTextNormalizationWidget = settingsNode.widgets.find(w => w && w.name === "useTextNormalization");
|
|
const textNormalizationWidget = settingsNode.widgets.find(w => w && w.name === "textNormalization");
|
|
const useBpmWidget = settingsNode.widgets.find(w => w && w.name === "useBpm");
|
|
const bpmWidget = settingsNode.widgets.find(w => w && w.name === "bpm");
|
|
const useKeyScaleWidget = settingsNode.widgets.find(w => w && w.name === "useKeyScale");
|
|
const keyScaleWidget = settingsNode.widgets.find(w => w && w.name === "keyScale");
|
|
const useTimeSignatureWidget = settingsNode.widgets.find(w => w && w.name === "useTimeSignature");
|
|
const timeSignatureWidget = settingsNode.widgets.find(w => w && w.name === "timeSignature");
|
|
const useVocalLanguageWidget = settingsNode.widgets.find(w => w && w.name === "useVocalLanguage");
|
|
const vocalLanguageWidget = settingsNode.widgets.find(w => w && w.name === "vocalLanguage");
|
|
const useCoverConditioningScaleWidget = settingsNode.widgets.find(w => w && w.name === "useCoverConditioningScale");
|
|
const coverConditioningScaleWidget = settingsNode.widgets.find(w => w && w.name === "coverConditioningScale");
|
|
const useRepaintingStartWidget = settingsNode.widgets.find(w => w && w.name === "useRepaintingStart");
|
|
const repaintingStartWidget = settingsNode.widgets.find(w => w && w.name === "repaintingStart");
|
|
const useRepaintingEndWidget = settingsNode.widgets.find(w => w && w.name === "useRepaintingEnd");
|
|
const repaintingEndWidget = settingsNode.widgets.find(w => w && w.name === "repaintingEnd");
|
|
const useXVectorOnlyWidget = settingsNode.widgets.find(w => w && w.name === "useXVectorOnly");
|
|
const xVectorOnlyWidget = settingsNode.widgets.find(w => w && w.name === "xVectorOnly");
|
|
const useMaxNewTokensWidget = settingsNode.widgets.find(w => w && w.name === "useMaxNewTokens");
|
|
const maxNewTokensWidget = settingsNode.widgets.find(w => w && w.name === "maxNewTokens");
|
|
const useTranscriptWidget = settingsNode.widgets.find(w => w && w.name === "useTranscript");
|
|
const transcriptWidget = settingsNode.widgets.find(w => w && w.name === "transcript");
|
|
const useCfgIntervalStartWidget = settingsNode.widgets.find(w => w && w.name === "useCfgIntervalStart");
|
|
const cfgIntervalStartWidget = settingsNode.widgets.find(w => w && w.name === "cfgIntervalStart");
|
|
const useCfgIntervalEndWidget = settingsNode.widgets.find(w => w && w.name === "useCfgIntervalEnd");
|
|
const cfgIntervalEndWidget = settingsNode.widgets.find(w => w && w.name === "cfgIntervalEnd");
|
|
const useNormalizeLoudnessWidget = settingsNode.widgets.find(w => w && w.name === "useNormalizeLoudness");
|
|
const normalizeLoudnessWidget = settingsNode.widgets.find(w => w && w.name === "normalizeLoudness");
|
|
const useTopPWidget = settingsNode.widgets.find(w => w && w.name === "useTopP");
|
|
const topPWidget = settingsNode.widgets.find(w => w && w.name === "topP");
|
|
const useChunkLengthWidget = settingsNode.widgets.find(w => w && w.name === "useChunkLength");
|
|
const chunkLengthWidget = settingsNode.widgets.find(w => w && w.name === "chunkLength");
|
|
const useMinChunkLengthWidget = settingsNode.widgets.find(w => w && w.name === "useMinChunkLength");
|
|
const minChunkLengthWidget = settingsNode.widgets.find(w => w && w.name === "minChunkLength");
|
|
const useNormalizeWidget = settingsNode.widgets.find(w => w && w.name === "useNormalize");
|
|
const normalizeWidget = settingsNode.widgets.find(w => w && w.name === "normalize");
|
|
const useLatencyWidget = settingsNode.widgets.find(w => w && w.name === "useLatency");
|
|
const latencyWidget = settingsNode.widgets.find(w => w && w.name === "latency");
|
|
const useMaxTokensWidget = settingsNode.widgets.find(w => w && w.name === "useMaxTokens");
|
|
const maxTokensWidget = settingsNode.widgets.find(w => w && w.name === "maxTokens");
|
|
const useRepetitionPenaltyWidget = settingsNode.widgets.find(w => w && w.name === "useRepetitionPenalty");
|
|
const repetitionPenaltyWidget = settingsNode.widgets.find(w => w && w.name === "repetitionPenalty");
|
|
const useConditionOnPreviousChunksWidget = settingsNode.widgets.find(w => w && w.name === "useConditionOnPreviousChunks");
|
|
const conditionOnPreviousChunksWidget = settingsNode.widgets.find(w => w && w.name === "conditionOnPreviousChunks");
|
|
const useEarlyStopThresholdWidget = settingsNode.widgets.find(w => w && w.name === "useEarlyStopThreshold");
|
|
const earlyStopThresholdWidget = settingsNode.widgets.find(w => w && w.name === "earlyStopThreshold");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function applyState() {
|
|
const enabled = useWidget.value === true;
|
|
toggleWidgetEnabled(paramWidget, enabled, settingsNode);
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
settingsNode.setDirtyCanvas(true);
|
|
}
|
|
setTimeout(applyState, 100);
|
|
appendWidgetCB(useWidget, () => setTimeout(applyState, 50));
|
|
}
|
|
|
|
if (useTemperatureWidget && temperatureWidget) toggleWidgetState(useTemperatureWidget, temperatureWidget, "temperature");
|
|
if (useAudioTemperatureWidget && audioTemperatureWidget) toggleWidgetState(useAudioTemperatureWidget, audioTemperatureWidget, "audioTemperature");
|
|
if (useTopKWidget && topKWidget) toggleWidgetState(useTopKWidget, topKWidget, "topK");
|
|
if (useIncludePrefixWidget && includePrefixWidget) toggleWidgetState(useIncludePrefixWidget, includePrefixWidget, "includePrefix");
|
|
if (useLyricsWidget && lyricsWidget) toggleWidgetState(useLyricsWidget, lyricsWidget, "lyrics");
|
|
if (useInstrumentalWidget && instrumentalWidget) toggleWidgetState(useInstrumentalWidget, instrumentalWidget, "instrumental");
|
|
if (useLyricsOptimizerWidget && lyricsOptimizerWidget) toggleWidgetState(useLyricsOptimizerWidget, lyricsOptimizerWidget, "lyricsOptimizer");
|
|
if (useGuidanceTypeWidget && guidanceTypeWidget) toggleWidgetState(useGuidanceTypeWidget, guidanceTypeWidget, "guidanceType");
|
|
if (useLanguageBoostWidget && languageBoostWidget) toggleWidgetState(useLanguageBoostWidget, languageBoostWidget, "languageBoost");
|
|
if (useTurboWidget && turboWidget) toggleWidgetState(useTurboWidget, turboWidget, "turbo");
|
|
if (useTextNormalizationWidget && textNormalizationWidget) toggleWidgetState(useTextNormalizationWidget, textNormalizationWidget, "textNormalization");
|
|
if (useBpmWidget && bpmWidget) toggleWidgetState(useBpmWidget, bpmWidget, "bpm");
|
|
if (useKeyScaleWidget && keyScaleWidget) toggleWidgetState(useKeyScaleWidget, keyScaleWidget, "keyScale");
|
|
if (useTimeSignatureWidget && timeSignatureWidget) toggleWidgetState(useTimeSignatureWidget, timeSignatureWidget, "timeSignature");
|
|
if (useVocalLanguageWidget && vocalLanguageWidget) toggleWidgetState(useVocalLanguageWidget, vocalLanguageWidget, "vocalLanguage");
|
|
if (useCoverConditioningScaleWidget && coverConditioningScaleWidget) toggleWidgetState(useCoverConditioningScaleWidget, coverConditioningScaleWidget, "coverConditioningScale");
|
|
if (useRepaintingStartWidget && repaintingStartWidget) toggleWidgetState(useRepaintingStartWidget, repaintingStartWidget, "repaintingStart");
|
|
if (useRepaintingEndWidget && repaintingEndWidget) toggleWidgetState(useRepaintingEndWidget, repaintingEndWidget, "repaintingEnd");
|
|
if (useXVectorOnlyWidget && xVectorOnlyWidget) toggleWidgetState(useXVectorOnlyWidget, xVectorOnlyWidget, "xVectorOnly");
|
|
if (useMaxNewTokensWidget && maxNewTokensWidget) toggleWidgetState(useMaxNewTokensWidget, maxNewTokensWidget, "maxNewTokens");
|
|
if (useTranscriptWidget && transcriptWidget) toggleWidgetState(useTranscriptWidget, transcriptWidget, "transcript");
|
|
if (useCfgIntervalStartWidget && cfgIntervalStartWidget) toggleWidgetState(useCfgIntervalStartWidget, cfgIntervalStartWidget, "cfgIntervalStart");
|
|
if (useCfgIntervalEndWidget && cfgIntervalEndWidget) toggleWidgetState(useCfgIntervalEndWidget, cfgIntervalEndWidget, "cfgIntervalEnd");
|
|
if (useNormalizeLoudnessWidget && normalizeLoudnessWidget) toggleWidgetState(useNormalizeLoudnessWidget, normalizeLoudnessWidget, "normalizeLoudness");
|
|
if (useTopPWidget && topPWidget) toggleWidgetState(useTopPWidget, topPWidget, "topP");
|
|
if (useChunkLengthWidget && chunkLengthWidget) toggleWidgetState(useChunkLengthWidget, chunkLengthWidget, "chunkLength");
|
|
if (useMinChunkLengthWidget && minChunkLengthWidget) toggleWidgetState(useMinChunkLengthWidget, minChunkLengthWidget, "minChunkLength");
|
|
if (useNormalizeWidget && normalizeWidget) toggleWidgetState(useNormalizeWidget, normalizeWidget, "normalize");
|
|
if (useLatencyWidget && latencyWidget) toggleWidgetState(useLatencyWidget, latencyWidget, "latency");
|
|
if (useMaxTokensWidget && maxTokensWidget) toggleWidgetState(useMaxTokensWidget, maxTokensWidget, "maxTokens");
|
|
if (useRepetitionPenaltyWidget && repetitionPenaltyWidget) toggleWidgetState(useRepetitionPenaltyWidget, repetitionPenaltyWidget, "repetitionPenalty");
|
|
if (useConditionOnPreviousChunksWidget && conditionOnPreviousChunksWidget) toggleWidgetState(useConditionOnPreviousChunksWidget, conditionOnPreviousChunksWidget, "conditionOnPreviousChunks");
|
|
if (useEarlyStopThresholdWidget && earlyStopThresholdWidget) toggleWidgetState(useEarlyStopThresholdWidget, earlyStopThresholdWidget, "earlyStopThreshold");
|
|
}
|
|
|
|
function textInferenceSettingsToggleHandler(settingsNode) {
|
|
if (!settingsNode?.widgets) return;
|
|
|
|
const useSystemPromptWidget = settingsNode.widgets.find(w => w && w.name === "useSystemPrompt");
|
|
const systemWidget = settingsNode.widgets.find(w => w && (w.name === "systemPrompt" || w.name === "system"));
|
|
const useMaxTokensWidget = settingsNode.widgets.find(w => w && w.name === "useMaxTokens");
|
|
const maxTokensWidget = settingsNode.widgets.find(w => w && w.name === "maxTokens");
|
|
const useTemperatureWidget = settingsNode.widgets.find(w => w && w.name === "useTemperature");
|
|
const temperatureWidget = settingsNode.widgets.find(w => w && w.name === "temperature");
|
|
const useTopPWidget = settingsNode.widgets.find(w => w && w.name === "useTopP");
|
|
const topPWidget = settingsNode.widgets.find(w => w && w.name === "topP");
|
|
const useTopKWidget = settingsNode.widgets.find(w => w && w.name === "useTopK");
|
|
const topKWidget = settingsNode.widgets.find(w => w && w.name === "topK");
|
|
const useStopSequencesWidget = settingsNode.widgets.find(w => w && w.name === "useStopSequences");
|
|
const stopSequencesWidget = settingsNode.widgets.find(w => w && w.name === "stopSequences");
|
|
const usePresencePenaltyWidget = settingsNode.widgets.find(w => w && w.name === "usePresencePenalty");
|
|
const presencePenaltyWidget = settingsNode.widgets.find(w => w && w.name === "presencePenalty");
|
|
const useFrequencyPenaltyWidget = settingsNode.widgets.find(w => w && w.name === "useFrequencyPenalty");
|
|
const frequencyPenaltyWidget = settingsNode.widgets.find(w => w && w.name === "frequencyPenalty");
|
|
const useToolsWidget = settingsNode.widgets.find(w => w && w.name === "useTools");
|
|
const toolsWidget = settingsNode.widgets.find(w => w && w.name === "tools");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function applyState() {
|
|
const enabled = useWidget.value === true;
|
|
toggleWidgetEnabled(paramWidget, enabled, settingsNode);
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
settingsNode.setDirtyCanvas(true);
|
|
}
|
|
setTimeout(applyState, 100);
|
|
appendWidgetCB(useWidget, () => setTimeout(applyState, 50));
|
|
}
|
|
|
|
if (useSystemPromptWidget && systemWidget) toggleWidgetState(useSystemPromptWidget, systemWidget);
|
|
if (useMaxTokensWidget && maxTokensWidget) toggleWidgetState(useMaxTokensWidget, maxTokensWidget);
|
|
if (useTemperatureWidget && temperatureWidget) toggleWidgetState(useTemperatureWidget, temperatureWidget);
|
|
if (useTopPWidget && topPWidget) toggleWidgetState(useTopPWidget, topPWidget);
|
|
if (useTopKWidget && topKWidget) toggleWidgetState(useTopKWidget, topKWidget);
|
|
if (useStopSequencesWidget && stopSequencesWidget) toggleWidgetState(useStopSequencesWidget, stopSequencesWidget);
|
|
if (usePresencePenaltyWidget && presencePenaltyWidget) toggleWidgetState(usePresencePenaltyWidget, presencePenaltyWidget);
|
|
if (useFrequencyPenaltyWidget && frequencyPenaltyWidget) toggleWidgetState(useFrequencyPenaltyWidget, frequencyPenaltyWidget);
|
|
if (useToolsWidget && toolsWidget) toggleWidgetState(useToolsWidget, toolsWidget);
|
|
}
|
|
|
|
function videoSettingsToggleHandler(settingsNode) {
|
|
if (!settingsNode?.widgets) return;
|
|
|
|
const useDraftWidget = settingsNode.widgets.find(w => w && w.name === "useDraft");
|
|
const draftWidget = settingsNode.widgets.find(w => w && w.name === "draft");
|
|
const useAudioWidget = settingsNode.widgets.find(w => w && w.name === "useAudio");
|
|
const audioWidget = settingsNode.widgets.find(w => w && w.name === "audio");
|
|
const usePreserveAudioWidget = settingsNode.widgets.find(w => w && w.name === "usePreserveAudio");
|
|
const preserveAudioWidget = settingsNode.widgets.find(w => w && w.name === "preserveAudio");
|
|
const useSourceAudioSyncWidget = settingsNode.widgets.find(w => w && w.name === "useSourceAudioSync");
|
|
const sourceAudioSyncWidget = settingsNode.widgets.find(w => w && w.name === "sourceAudioSync");
|
|
const useTurboWidget = settingsNode.widgets.find(w => w && w.name === "useTurbo");
|
|
const turboWidget = settingsNode.widgets.find(w => w && w.name === "turbo");
|
|
const useLoopWidget = settingsNode.widgets.find(w => w && w.name === "useLoop");
|
|
const loopWidget = settingsNode.widgets.find(w => w && w.name === "loop");
|
|
const useHdrWidget = settingsNode.widgets.find(w => w && w.name === "useHdr");
|
|
const hdrWidget = settingsNode.widgets.find(w => w && w.name === "hdr");
|
|
const useExrExportWidget = settingsNode.widgets.find(w => w && w.name === "useExrExport");
|
|
const exrExportWidget = settingsNode.widgets.find(w => w && w.name === "exrExport");
|
|
const useVoicePromptWidget = settingsNode.widgets.find(w => w && w.name === "useVoicePrompt");
|
|
const voicePromptWidget = settingsNode.widgets.find(w => w && w.name === "voicePrompt");
|
|
const useSafetyFilterWidget = settingsNode.widgets.find(w => w && w.name === "useSafetyFilter");
|
|
const safetyFilterWidget = settingsNode.widgets.find(w => w && w.name === "safetyFilter");
|
|
const usePromptUpsamplingWidget = settingsNode.widgets.find(w => w && w.name === "usePromptUpsampling");
|
|
const promptUpsamplingWidget = settingsNode.widgets.find(w => w && w.name === "promptUpsampling");
|
|
const useBackgroundColorWidget = settingsNode.widgets.find(w => w && w.name === "useBackgroundColor");
|
|
const backgroundColorWidget = settingsNode.widgets.find(w => w && w.name === "backgroundColor");
|
|
const useRemoveBackgroundWidget = settingsNode.widgets.find(w => w && w.name === "useRemoveBackground");
|
|
const removeBackgroundWidget = settingsNode.widgets.find(w => w && w.name === "removeBackground");
|
|
const useExpressivenessWidget = settingsNode.widgets.find(w => w && w.name === "useExpressiveness");
|
|
const expressivenessWidget = settingsNode.widgets.find(w => w && w.name === "expressiveness");
|
|
const useVoiceDescriptionWidget = settingsNode.widgets.find(w => w && w.name === "useVoiceDescription");
|
|
const voiceDescriptionWidget = settingsNode.widgets.find(w => w && w.name === "voiceDescription");
|
|
const useStyleWidget = settingsNode.widgets.find(w => w && w.name === "useStyle");
|
|
const styleWidget = settingsNode.widgets.find(w => w && w.name === "style");
|
|
const useThinkingWidget = settingsNode.widgets.find(w => w && w.name === "useThinking");
|
|
const thinkingWidget = settingsNode.widgets.find(w => w && w.name === "thinking");
|
|
const useMultiClipWidget = settingsNode.widgets.find(w => w && w.name === "useMultiClip");
|
|
const multiClipWidget = settingsNode.widgets.find(w => w && w.name === "multiClip");
|
|
const useShotTypeWidget = settingsNode.widgets.find(w => w && w.name === "useShotType");
|
|
const shotTypeWidget = settingsNode.widgets.find(w => w && w.name === "shotType");
|
|
const usePromptExtendWidget = settingsNode.widgets.find(w => w && w.name === "usePromptExtend");
|
|
const promptExtendWidget = settingsNode.widgets.find(w => w && w.name === "promptExtend");
|
|
const useSyncModeWidget = settingsNode.widgets.find(w => w && w.name === "useSyncMode");
|
|
const syncModeWidget = settingsNode.widgets.find(w => w && w.name === "syncMode");
|
|
const useModeWidget = settingsNode.widgets.find(w => w && w.name === "useMode");
|
|
const modeWidget = settingsNode.widgets.find(w => w && w.name === "mode");
|
|
const useEmotionWidget = settingsNode.widgets.find(w => w && w.name === "useEmotion");
|
|
const emotionWidget = settingsNode.widgets.find(w => w && w.name === "emotion");
|
|
const useTemperatureWidget = settingsNode.widgets.find(w => w && w.name === "useTemperature");
|
|
const temperatureWidget = settingsNode.widgets.find(w => w && w.name === "temperature");
|
|
const useOcclusionDetectionWidget = settingsNode.widgets.find(w => w && w.name === "useOcclusionDetection");
|
|
const occlusionDetectionWidget = settingsNode.widgets.find(w => w && w.name === "occlusionDetection");
|
|
const useKeyframeIdWidget = settingsNode.widgets.find(w => w && w.name === "useKeyframeId");
|
|
const keyframeIdWidget = settingsNode.widgets.find(w => w && w.name === "keyframeId");
|
|
const useFitWidget = settingsNode.widgets.find(w => w && w.name === "useFit");
|
|
const fitWidget = settingsNode.widgets.find(w => w && w.name === "fit");
|
|
const useCaptionWidget = settingsNode.widgets.find(w => w && w.name === "useCaption");
|
|
const captionWidget = settingsNode.widgets.find(w => w && w.name === "caption");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function applyState() {
|
|
const enabled = useWidget.value === true;
|
|
toggleWidgetEnabled(paramWidget, enabled, settingsNode);
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
settingsNode.setDirtyCanvas(true);
|
|
}
|
|
setTimeout(applyState, 100);
|
|
appendWidgetCB(useWidget, () => setTimeout(applyState, 50));
|
|
}
|
|
|
|
if (useDraftWidget && draftWidget) toggleWidgetState(useDraftWidget, draftWidget, "draft");
|
|
if (useAudioWidget && audioWidget) toggleWidgetState(useAudioWidget, audioWidget, "audio");
|
|
if (usePreserveAudioWidget && preserveAudioWidget) toggleWidgetState(usePreserveAudioWidget, preserveAudioWidget, "preserveAudio");
|
|
if (useSourceAudioSyncWidget && sourceAudioSyncWidget) toggleWidgetState(useSourceAudioSyncWidget, sourceAudioSyncWidget, "sourceAudioSync");
|
|
if (useTurboWidget && turboWidget) toggleWidgetState(useTurboWidget, turboWidget, "turbo");
|
|
if (useLoopWidget && loopWidget) toggleWidgetState(useLoopWidget, loopWidget, "loop");
|
|
if (useHdrWidget && hdrWidget) toggleWidgetState(useHdrWidget, hdrWidget, "hdr");
|
|
if (useExrExportWidget && exrExportWidget) toggleWidgetState(useExrExportWidget, exrExportWidget, "exrExport");
|
|
if (useVoicePromptWidget && voicePromptWidget) toggleWidgetState(useVoicePromptWidget, voicePromptWidget, "voicePrompt");
|
|
if (useSafetyFilterWidget && safetyFilterWidget) toggleWidgetState(useSafetyFilterWidget, safetyFilterWidget, "safetyFilter");
|
|
if (usePromptUpsamplingWidget && promptUpsamplingWidget) toggleWidgetState(usePromptUpsamplingWidget, promptUpsamplingWidget, "promptUpsampling");
|
|
if (useBackgroundColorWidget && backgroundColorWidget) toggleWidgetState(useBackgroundColorWidget, backgroundColorWidget, "backgroundColor");
|
|
if (useRemoveBackgroundWidget && removeBackgroundWidget) toggleWidgetState(useRemoveBackgroundWidget, removeBackgroundWidget, "removeBackground");
|
|
if (useExpressivenessWidget && expressivenessWidget) toggleWidgetState(useExpressivenessWidget, expressivenessWidget, "expressiveness");
|
|
if (useVoiceDescriptionWidget && voiceDescriptionWidget) toggleWidgetState(useVoiceDescriptionWidget, voiceDescriptionWidget, "voiceDescription");
|
|
if (useStyleWidget && styleWidget) toggleWidgetState(useStyleWidget, styleWidget, "style");
|
|
if (useThinkingWidget && thinkingWidget) toggleWidgetState(useThinkingWidget, thinkingWidget, "thinking");
|
|
if (useMultiClipWidget && multiClipWidget) toggleWidgetState(useMultiClipWidget, multiClipWidget, "multiClip");
|
|
if (useShotTypeWidget && shotTypeWidget) toggleWidgetState(useShotTypeWidget, shotTypeWidget, "shotType");
|
|
if (usePromptExtendWidget && promptExtendWidget) toggleWidgetState(usePromptExtendWidget, promptExtendWidget, "promptExtend");
|
|
if (useSyncModeWidget && syncModeWidget) toggleWidgetState(useSyncModeWidget, syncModeWidget, "syncMode");
|
|
if (useModeWidget && modeWidget) toggleWidgetState(useModeWidget, modeWidget, "mode");
|
|
if (useEmotionWidget && emotionWidget) toggleWidgetState(useEmotionWidget, emotionWidget, "emotion");
|
|
if (useTemperatureWidget && temperatureWidget) toggleWidgetState(useTemperatureWidget, temperatureWidget, "temperature");
|
|
if (useOcclusionDetectionWidget && occlusionDetectionWidget) toggleWidgetState(useOcclusionDetectionWidget, occlusionDetectionWidget, "occlusionDetection");
|
|
if (useKeyframeIdWidget && keyframeIdWidget) toggleWidgetState(useKeyframeIdWidget, keyframeIdWidget, "keyframeId");
|
|
if (useFitWidget && fitWidget) toggleWidgetState(useFitWidget, fitWidget, "fit");
|
|
if (useCaptionWidget && captionWidget) toggleWidgetState(useCaptionWidget, captionWidget, "caption");
|
|
}
|
|
|
|
function videoInferenceSettingsTtsToggleHandler(node) {
|
|
if (!node?.widgets) return;
|
|
|
|
const useStabilityWidget = node.widgets.find(w => w && w.name === "useStability");
|
|
const stabilityWidget = node.widgets.find(w => w && w.name === "stability");
|
|
const useSimilarityBoostWidget = node.widgets.find(w => w && w.name === "useSimilarityBoost");
|
|
const similarityBoostWidget = node.widgets.find(w => w && w.name === "similarityBoost");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function applyState() {
|
|
const enabled = useWidget.value === true;
|
|
toggleWidgetEnabled(paramWidget, enabled, node);
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
setTimeout(applyState, 100);
|
|
appendWidgetCB(useWidget, () => setTimeout(applyState, 50));
|
|
}
|
|
|
|
if (useStabilityWidget && stabilityWidget) toggleWidgetState(useStabilityWidget, stabilityWidget, "stability");
|
|
if (useSimilarityBoostWidget && similarityBoostWidget) toggleWidgetState(useSimilarityBoostWidget, similarityBoostWidget, "similarityBoost");
|
|
}
|
|
|
|
function videoInferenceSettingsActiveSpeakerDetectionToggleHandler(node) {
|
|
if (!node?.widgets) return;
|
|
|
|
const useAutoDetectWidget = node.widgets.find(w => w && w.name === "useAutoDetect");
|
|
const autoDetectWidget = node.widgets.find(w => w && w.name === "autoDetect");
|
|
const useFrameNumberWidget = node.widgets.find(w => w && w.name === "useFrameNumber");
|
|
const frameNumberWidget = node.widgets.find(w => w && w.name === "frameNumber");
|
|
const useCoordinatesWidget = node.widgets.find(w => w && w.name === "useCoordinates");
|
|
const coordinateXWidget = node.widgets.find(w => w && w.name === "coordinateX");
|
|
const coordinateYWidget = node.widgets.find(w => w && w.name === "coordinateY");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function applyState() {
|
|
const enabled = useWidget.value === true;
|
|
toggleWidgetEnabled(paramWidget, enabled, node);
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
setTimeout(applyState, 100);
|
|
appendWidgetCB(useWidget, () => setTimeout(applyState, 50));
|
|
}
|
|
|
|
if (useAutoDetectWidget && autoDetectWidget) toggleWidgetState(useAutoDetectWidget, autoDetectWidget, "autoDetect");
|
|
if (useFrameNumberWidget && frameNumberWidget) toggleWidgetState(useFrameNumberWidget, frameNumberWidget, "frameNumber");
|
|
if (useCoordinatesWidget && coordinateXWidget) toggleWidgetState(useCoordinatesWidget, coordinateXWidget, "coordinateX");
|
|
if (useCoordinatesWidget && coordinateYWidget) toggleWidgetState(useCoordinatesWidget, coordinateYWidget, "coordinateY");
|
|
}
|
|
|
|
function videoInferenceSettingsActiveSpeakerBoundingBoxesToggleHandler(node) {
|
|
if (!node?.widgets) return;
|
|
|
|
const useBox1Widget = node.widgets.find(w => w && w.name === "useBox1");
|
|
const box1Widget = node.widgets.find(w => w && w.name === "box1");
|
|
const useBox2Widget = node.widgets.find(w => w && w.name === "useBox2");
|
|
const box2Widget = node.widgets.find(w => w && w.name === "box2");
|
|
const useBox3Widget = node.widgets.find(w => w && w.name === "useBox3");
|
|
const box3Widget = node.widgets.find(w => w && w.name === "box3");
|
|
const useBox4Widget = node.widgets.find(w => w && w.name === "useBox4");
|
|
const box4Widget = node.widgets.find(w => w && w.name === "box4");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function applyState() {
|
|
const enabled = useWidget.value === true;
|
|
toggleWidgetEnabled(paramWidget, enabled, node);
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
setTimeout(applyState, 100);
|
|
appendWidgetCB(useWidget, () => setTimeout(applyState, 50));
|
|
}
|
|
|
|
if (useBox1Widget && box1Widget) toggleWidgetState(useBox1Widget, box1Widget, "box1");
|
|
if (useBox2Widget && box2Widget) toggleWidgetState(useBox2Widget, box2Widget, "box2");
|
|
if (useBox3Widget && box3Widget) toggleWidgetState(useBox3Widget, box3Widget, "box3");
|
|
if (useBox4Widget && box4Widget) toggleWidgetState(useBox4Widget, box4Widget, "box4");
|
|
}
|
|
|
|
function videoInferenceSettingsSegmentsToggleHandler(node) {
|
|
if (!node?.widgets) return;
|
|
|
|
function byName(name) {
|
|
return node.widgets.find(w => w && w.name === name);
|
|
}
|
|
|
|
function togglePair(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function applyState() {
|
|
const enabled = useWidget.value === true;
|
|
toggleWidgetEnabled(paramWidget, enabled, node);
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
setTimeout(applyState, 100);
|
|
appendWidgetCB(useWidget, () => setTimeout(applyState, 50));
|
|
}
|
|
|
|
function wireSegment(idx) {
|
|
const useSegment = byName(`useSegment${idx}`);
|
|
const start = byName(`segment${idx}StartTime`);
|
|
const end = byName(`segment${idx}EndTime`);
|
|
const audio = byName(`segment${idx}Audio`);
|
|
const useCrop = byName(`useSegment${idx}AudioCrop`);
|
|
const cropStart = byName(`segment${idx}AudioStartTime`);
|
|
const cropEnd = byName(`segment${idx}AudioEndTime`);
|
|
|
|
function toggleCropTimeWidget(paramWidget) {
|
|
if (!useSegment || !useCrop || !paramWidget) return;
|
|
function applyState() {
|
|
const enabled = useSegment.value === true && useCrop.value === true;
|
|
toggleWidgetEnabled(paramWidget, enabled, node);
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
setTimeout(applyState, 100);
|
|
appendWidgetCB(useSegment, () => setTimeout(applyState, 50));
|
|
appendWidgetCB(useCrop, () => setTimeout(applyState, 50));
|
|
}
|
|
|
|
if (useSegment && start) togglePair(useSegment, start, `segment${idx}StartTime`);
|
|
if (useSegment && end) togglePair(useSegment, end, `segment${idx}EndTime`);
|
|
if (useSegment && audio) togglePair(useSegment, audio, `segment${idx}Audio`);
|
|
if (useSegment && useCrop) togglePair(useSegment, useCrop, `useSegment${idx}AudioCrop`);
|
|
if (cropStart) toggleCropTimeWidget(cropStart);
|
|
if (cropEnd) toggleCropTimeWidget(cropEnd);
|
|
}
|
|
|
|
wireSegment(1);
|
|
wireSegment(2);
|
|
wireSegment(3);
|
|
wireSegment(4);
|
|
}
|
|
|
|
function videoInferenceSettingsControlToggleHandler(node) {
|
|
if (!node?.widgets) return;
|
|
|
|
const useAutoControlsWidget = node.widgets.find(w => w && w.name === "useAutoControls");
|
|
const autoControlsWidget = node.widgets.find(w => w && w.name === "autoControls");
|
|
const useStrengthWidget = node.widgets.find(w => w && w.name === "useStrength");
|
|
const strengthWidget = node.widgets.find(w => w && w.name === "strength");
|
|
const useDepthBlurWidget = node.widgets.find(w => w && w.name === "useDepthBlur");
|
|
const depthBlurWidget = node.widgets.find(w => w && w.name === "depthBlur");
|
|
const useFaceWidget = node.widgets.find(w => w && w.name === "useFace");
|
|
const faceWidget = node.widgets.find(w => w && w.name === "face");
|
|
const useNormalsAugmentationWidget = node.widgets.find(w => w && w.name === "useNormalsAugmentation");
|
|
const normalsAugmentationWidget = node.widgets.find(w => w && w.name === "normalsAugmentation");
|
|
const usePoseStrengthWidget = node.widgets.find(w => w && w.name === "usePoseStrength");
|
|
const poseStrengthWidget = node.widgets.find(w => w && w.name === "poseStrength");
|
|
const useTrajectorySparsityWidget = node.widgets.find(w => w && w.name === "useTrajectorySparsity");
|
|
const trajectorySparsityWidget = node.widgets.find(w => w && w.name === "trajectorySparsity");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function applyState() {
|
|
const enabled = useWidget.value === true;
|
|
toggleWidgetEnabled(paramWidget, enabled, node);
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
setTimeout(applyState, 100);
|
|
appendWidgetCB(useWidget, () => setTimeout(applyState, 50));
|
|
}
|
|
|
|
if (useAutoControlsWidget && autoControlsWidget) toggleWidgetState(useAutoControlsWidget, autoControlsWidget, "autoControls");
|
|
if (useStrengthWidget && strengthWidget) toggleWidgetState(useStrengthWidget, strengthWidget, "strength");
|
|
if (useDepthBlurWidget && depthBlurWidget) toggleWidgetState(useDepthBlurWidget, depthBlurWidget, "depthBlur");
|
|
if (useFaceWidget && faceWidget) toggleWidgetState(useFaceWidget, faceWidget, "face");
|
|
if (useNormalsAugmentationWidget && normalsAugmentationWidget) toggleWidgetState(useNormalsAugmentationWidget, normalsAugmentationWidget, "normalsAugmentation");
|
|
if (usePoseStrengthWidget && poseStrengthWidget) toggleWidgetState(usePoseStrengthWidget, poseStrengthWidget, "poseStrength");
|
|
if (useTrajectorySparsityWidget && trajectorySparsityWidget) toggleWidgetState(useTrajectorySparsityWidget, trajectorySparsityWidget, "trajectorySparsity");
|
|
}
|
|
|
|
function audioInferenceSpeechToggleHandler(speechNode) {
|
|
if (!speechNode?.widgets) return;
|
|
|
|
const useVoiceWidget = speechNode.widgets.find(w => w && w.name === "useVoice");
|
|
const voiceWidget = speechNode.widgets.find(w => w && w.name === "voice");
|
|
const useSpeedWidget = speechNode.widgets.find(w => w && w.name === "useSpeed");
|
|
const speedWidget = speechNode.widgets.find(w => w && w.name === "speed");
|
|
const useVolumeWidget = speechNode.widgets.find(w => w && w.name === "useVolume");
|
|
const volumeWidget = speechNode.widgets.find(w => w && w.name === "volume");
|
|
const usePitchWidget = speechNode.widgets.find(w => w && w.name === "usePitch");
|
|
const pitchWidget = speechNode.widgets.find(w => w && w.name === "pitch");
|
|
const useEmotionWidget = speechNode.widgets.find(w => w && w.name === "useEmotion");
|
|
const emotionWidget = speechNode.widgets.find(w => w && w.name === "emotion");
|
|
const useToneWidget = speechNode.widgets.find(w => w && w.name === "useTone");
|
|
const toneWidget = speechNode.widgets.find(w => w && w.name === "tone");
|
|
const useLanguageWidget = speechNode.widgets.find(w => w && w.name === "useLanguage");
|
|
const languageWidget = speechNode.widgets.find(w => w && w.name === "language");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function applyState() {
|
|
const enabled = useWidget.value === true;
|
|
toggleWidgetEnabled(paramWidget, enabled, speechNode);
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
speechNode.setDirtyCanvas(true);
|
|
}
|
|
setTimeout(applyState, 100);
|
|
appendWidgetCB(useWidget, () => setTimeout(applyState, 50));
|
|
}
|
|
|
|
if (useSpeedWidget && speedWidget) toggleWidgetState(useSpeedWidget, speedWidget, "speed");
|
|
if (useVolumeWidget && volumeWidget) toggleWidgetState(useVolumeWidget, volumeWidget, "volume");
|
|
if (usePitchWidget && pitchWidget) toggleWidgetState(usePitchWidget, pitchWidget, "pitch");
|
|
if (useEmotionWidget && emotionWidget) toggleWidgetState(useEmotionWidget, emotionWidget, "emotion");
|
|
if (useToneWidget && toneWidget) toggleWidgetState(useToneWidget, toneWidget, "tone");
|
|
if (useLanguageWidget && languageWidget) toggleWidgetState(useLanguageWidget, languageWidget, "language");
|
|
if (useVoiceWidget && voiceWidget) toggleWidgetState(useVoiceWidget, voiceWidget, "voice");
|
|
}
|
|
|
|
function acceleratorOptionsToggleHandler(acceleratorNode) {
|
|
// Find all "use" parameter widgets for Accelerator Options
|
|
const useCacheDistanceWidget = acceleratorNode.widgets.find(w => w.name === "useCacheDistance");
|
|
const cacheDistanceWidget = acceleratorNode.widgets.find(w => w.name === "cacheDistance");
|
|
const useTeaCacheDistanceWidget = acceleratorNode.widgets.find(w => w.name === "useTeaCacheDistance");
|
|
const teaCacheDistanceWidget = acceleratorNode.widgets.find(w => w.name === "teaCacheDistance");
|
|
const useDeepCacheOptionsWidget = acceleratorNode.widgets.find(w => w.name === "useDeepCacheOptions");
|
|
const deepCacheIntervalWidget = acceleratorNode.widgets.find(w => w.name === "deepCacheInterval");
|
|
const deepCacheBranchIdWidget = acceleratorNode.widgets.find(w => w.name === "deepCacheBranchId");
|
|
const useCacheStepsWidget = acceleratorNode.widgets.find(w => w.name === "useCacheSteps");
|
|
const cacheStartStepWidget = acceleratorNode.widgets.find(w => w.name === "cacheStartStep");
|
|
const cacheEndStepWidget = acceleratorNode.widgets.find(w => w.name === "cacheEndStep");
|
|
const useCachePercentageStepsWidget = acceleratorNode.widgets.find(w => w.name === "useCachePercentageSteps");
|
|
const cacheStartStepPercentageWidget = acceleratorNode.widgets.find(w => w.name === "cacheStartStepPercentage");
|
|
const cacheEndStepPercentageWidget = acceleratorNode.widgets.find(w => w.name === "cacheEndStepPercentage");
|
|
const useCacheMaxConsecutiveStepsWidget = acceleratorNode.widgets.find(w => w.name === "useCacheMaxConsecutiveSteps");
|
|
const cacheMaxConsecutiveStepsWidget = acceleratorNode.widgets.find(w => w.name === "cacheMaxConsecutiveSteps");
|
|
|
|
// Helper function to toggle widget enabled state (exact same pattern)
|
|
function toggleWidgetState(useWidget, paramWidgets, paramNames) {
|
|
if (!useWidget || !paramWidgets || paramWidgets.length === 0) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
paramWidgets.forEach((paramWidget, idx) => {
|
|
if (!paramWidget) return;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = acceleratorNode.htmlElements?.widgetsContainer || acceleratorNode.htmlElements;
|
|
if (nodeElement && paramNames[idx]) {
|
|
const input = nodeElement.querySelector(`input[name="${paramNames[idx]}"], textarea[name="${paramNames[idx]}"], select[name="${paramNames[idx]}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
acceleratorNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up all toggle handlers
|
|
if (useCacheDistanceWidget && cacheDistanceWidget) {
|
|
toggleWidgetState(useCacheDistanceWidget, [cacheDistanceWidget], ["cacheDistance"]);
|
|
}
|
|
|
|
if (useTeaCacheDistanceWidget && teaCacheDistanceWidget) {
|
|
toggleWidgetState(useTeaCacheDistanceWidget, [teaCacheDistanceWidget], ["teaCacheDistance"]);
|
|
}
|
|
|
|
if (useDeepCacheOptionsWidget && deepCacheIntervalWidget && deepCacheBranchIdWidget) {
|
|
toggleWidgetState(useDeepCacheOptionsWidget, [deepCacheIntervalWidget, deepCacheBranchIdWidget], ["deepCacheInterval", "deepCacheBranchId"]);
|
|
}
|
|
|
|
if (useCacheStepsWidget && cacheStartStepWidget && cacheEndStepWidget) {
|
|
toggleWidgetState(useCacheStepsWidget, [cacheStartStepWidget, cacheEndStepWidget], ["cacheStartStep", "cacheEndStep"]);
|
|
}
|
|
|
|
if (useCachePercentageStepsWidget && cacheStartStepPercentageWidget && cacheEndStepPercentageWidget) {
|
|
toggleWidgetState(useCachePercentageStepsWidget, [cacheStartStepPercentageWidget, cacheEndStepPercentageWidget], ["cacheStartStepPercentage", "cacheEndStepPercentage"]);
|
|
}
|
|
|
|
if (useCacheMaxConsecutiveStepsWidget && cacheMaxConsecutiveStepsWidget) {
|
|
toggleWidgetState(useCacheMaxConsecutiveStepsWidget, [cacheMaxConsecutiveStepsWidget], ["cacheMaxConsecutiveSteps"]);
|
|
}
|
|
}
|
|
|
|
function bytedanceProviderSettingsToggleHandler(bytedanceNode) {
|
|
// Find all "use" parameter widgets for Bytedance Provider Settings
|
|
const useCameraFixedWidget = bytedanceNode.widgets.find(w => w.name === "useCameraFixed");
|
|
const cameraFixedWidget = bytedanceNode.widgets.find(w => w.name === "cameraFixed");
|
|
const useMaxSequentialImagesWidget = bytedanceNode.widgets.find(w => w.name === "useMaxSequentialImages");
|
|
const maxSequentialImagesWidget = bytedanceNode.widgets.find(w => w.name === "maxSequentialImages");
|
|
const useFastModeWidget = bytedanceNode.widgets.find(w => w.name === "useFastMode");
|
|
const fastModeWidget = bytedanceNode.widgets.find(w => w.name === "fastMode");
|
|
const useAudioWidget = bytedanceNode.widgets.find(w => w.name === "useAudio");
|
|
const audioWidget = bytedanceNode.widgets.find(w => w.name === "audio");
|
|
const useDraftWidget = bytedanceNode.widgets.find(w => w.name === "useDraft");
|
|
const draftWidget = bytedanceNode.widgets.find(w => w.name === "draft");
|
|
const useOptimizePromptModeWidget = bytedanceNode.widgets.find(w => w.name === "useOptimizePromptMode");
|
|
const optimizePromptModeWidget = bytedanceNode.widgets.find(w => w.name === "optimizePromptMode");
|
|
|
|
// Helper function to toggle widget enabled state (exact same pattern)
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = bytedanceNode.htmlElements?.widgetsContainer || bytedanceNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bytedanceNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up all toggle handlers
|
|
if (useCameraFixedWidget && cameraFixedWidget) {
|
|
toggleWidgetState(useCameraFixedWidget, cameraFixedWidget, "cameraFixed");
|
|
}
|
|
|
|
if (useMaxSequentialImagesWidget && maxSequentialImagesWidget) {
|
|
toggleWidgetState(useMaxSequentialImagesWidget, maxSequentialImagesWidget, "maxSequentialImages");
|
|
}
|
|
|
|
if (useFastModeWidget && fastModeWidget) {
|
|
toggleWidgetState(useFastModeWidget, fastModeWidget, "fastMode");
|
|
}
|
|
|
|
if (useAudioWidget && audioWidget) {
|
|
toggleWidgetState(useAudioWidget, audioWidget, "audio");
|
|
}
|
|
|
|
if (useDraftWidget && draftWidget) {
|
|
toggleWidgetState(useDraftWidget, draftWidget, "draft");
|
|
}
|
|
|
|
if (useOptimizePromptModeWidget && optimizePromptModeWidget) {
|
|
toggleWidgetState(useOptimizePromptModeWidget, optimizePromptModeWidget, "optimizePromptMode");
|
|
}
|
|
}
|
|
|
|
function ultralyticsProviderSettingsToggleHandler(ultralyticsNode) {
|
|
const useParamPairs = [
|
|
["useMaskBlur", "maskBlur"],
|
|
["useMaskPadding", "maskPadding"],
|
|
["useConfidence", "confidence"],
|
|
["usePositivePrompt", "positivePrompt"],
|
|
["useNegativePrompt", "negativePrompt"],
|
|
["useSteps", "steps"],
|
|
["useCFGScale", "CFGScale"],
|
|
["useStrength", "strength"],
|
|
["useInpaintSize", "inpaintSize"],
|
|
];
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = ultralyticsNode.htmlElements?.widgetsContainer || ultralyticsNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
|
|
ultralyticsNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
useParamPairs.forEach(([useName, paramName]) => {
|
|
const useWidget = ultralyticsNode.widgets.find(w => w.name === useName);
|
|
const paramWidget = ultralyticsNode.widgets.find(w => w.name === paramName);
|
|
if (useWidget && paramWidget) {
|
|
toggleWidgetState(useWidget, paramWidget, paramName);
|
|
}
|
|
});
|
|
}
|
|
|
|
function xaiProviderSettingsToggleHandler(xaiNode) {
|
|
const useQualityWidget = xaiNode.widgets.find(w => w.name === "useQuality");
|
|
const qualityWidget = xaiNode.widgets.find(w => w.name === "quality");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = xaiNode.htmlElements?.widgetsContainer || xaiNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
|
|
xaiNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
if (useQualityWidget && qualityWidget) {
|
|
toggleWidgetState(useQualityWidget, qualityWidget, "quality");
|
|
}
|
|
}
|
|
|
|
function viduProviderSettingsToggleHandler(viduNode) {
|
|
const useAudioWidget = viduNode.widgets.find(w => w.name === "useAudio");
|
|
const audioWidget = viduNode.widgets.find(w => w.name === "audio");
|
|
const useBgmWidget = viduNode.widgets.find(w => w.name === "useBgm");
|
|
const bgmWidget = viduNode.widgets.find(w => w.name === "bgm");
|
|
const useStyleWidget = viduNode.widgets.find(w => w.name === "useStyle");
|
|
const styleWidget = viduNode.widgets.find(w => w.name === "style");
|
|
const useMovementAmplitudeWidget = viduNode.widgets.find(w => w.name === "useMovementAmplitude");
|
|
const movementAmplitudeWidget = viduNode.widgets.find(w => w.name === "movementAmplitude");
|
|
const useTemplateNameWidget = viduNode.widgets.find(w => w.name === "useTemplateName");
|
|
const templateNameWidget = viduNode.widgets.find(w => w.name === "templateName");
|
|
const useTemplateAreaWidget = viduNode.widgets.find(w => w.name === "useTemplateArea");
|
|
const templateAreaWidget = viduNode.widgets.find(w => w.name === "templateArea");
|
|
const useTemplateBeastWidget = viduNode.widgets.find(w => w.name === "useTemplateBeast");
|
|
const templateBeastWidget = viduNode.widgets.find(w => w.name === "templateBeast");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = viduNode.htmlElements?.widgetsContainer || viduNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
|
|
viduNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
if (useAudioWidget && audioWidget) {
|
|
toggleWidgetState(useAudioWidget, audioWidget, "audio");
|
|
}
|
|
if (useBgmWidget && bgmWidget) {
|
|
toggleWidgetState(useBgmWidget, bgmWidget, "bgm");
|
|
}
|
|
if (useStyleWidget && styleWidget) {
|
|
toggleWidgetState(useStyleWidget, styleWidget, "style");
|
|
}
|
|
if (useMovementAmplitudeWidget && movementAmplitudeWidget) {
|
|
toggleWidgetState(useMovementAmplitudeWidget, movementAmplitudeWidget, "movementAmplitude");
|
|
}
|
|
if (useTemplateNameWidget && templateNameWidget) {
|
|
toggleWidgetState(useTemplateNameWidget, templateNameWidget, "templateName");
|
|
}
|
|
if (useTemplateAreaWidget && templateAreaWidget) {
|
|
toggleWidgetState(useTemplateAreaWidget, templateAreaWidget, "templateArea");
|
|
}
|
|
if (useTemplateBeastWidget && templateBeastWidget) {
|
|
toggleWidgetState(useTemplateBeastWidget, templateBeastWidget, "templateBeast");
|
|
}
|
|
}
|
|
|
|
function sourcefulProviderSettingsToggleHandler(sourcefulNode) {
|
|
const useTransparencyWidget = sourcefulNode.widgets.find(w => w.name === "useTransparency");
|
|
const transparencyWidget = sourcefulNode.widgets.find(w => w.name === "transparency");
|
|
const useEnhancePromptWidget = sourcefulNode.widgets.find(w => w.name === "useEnhancePrompt");
|
|
const enhancePromptWidget = sourcefulNode.widgets.find(w => w.name === "enhancePrompt");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = sourcefulNode.htmlElements?.widgetsContainer || sourcefulNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
|
|
sourcefulNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
if (useTransparencyWidget && transparencyWidget) {
|
|
toggleWidgetState(useTransparencyWidget, transparencyWidget, "transparency");
|
|
}
|
|
if (useEnhancePromptWidget && enhancePromptWidget) {
|
|
toggleWidgetState(useEnhancePromptWidget, enhancePromptWidget, "enhancePrompt");
|
|
}
|
|
}
|
|
|
|
function sourcefulProviderSettingsFontsToggleHandler(fontsNode) {
|
|
if (!fontsNode?.widgets) return;
|
|
if (fontsNode._sourcefulProviderSettingsFontsToggleHandlerRegistered) return;
|
|
fontsNode._sourcefulProviderSettingsFontsToggleHandlerRegistered = true;
|
|
|
|
function toggleFontGroup(useWidget, fontUrlWidget, textWidget, fontParamName, textParamName) {
|
|
if (!useWidget || !fontUrlWidget || !textWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
[fontUrlWidget, textWidget].forEach(paramWidget => {
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
});
|
|
|
|
const nodeElement = fontsNode.htmlElements?.widgetsContainer || fontsNode.htmlElements;
|
|
if (nodeElement) {
|
|
[fontParamName, textParamName].forEach(paramName => {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
});
|
|
}
|
|
|
|
fontsNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
for (let i = 1; i <= 2; i++) {
|
|
const useFontWidget = fontsNode.widgets.find(w => w && w.name === `useFont${i}`);
|
|
const fontUrlWidget = fontsNode.widgets.find(w => w && w.name === `fontUrl${i}`);
|
|
const textWidget = fontsNode.widgets.find(w => w && w.name === `text${i}`);
|
|
if (useFontWidget && fontUrlWidget && textWidget) {
|
|
toggleFontGroup(useFontWidget, fontUrlWidget, textWidget, `fontUrl${i}`, `text${i}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
function threeDInferenceToggleHandler(node) {
|
|
const useSeedWidget = node.widgets.find(w => w && w.name === "useSeed");
|
|
const seedWidget = node.widgets.find(w => w && w.name === "seed");
|
|
const useOutputQualityWidget = node.widgets.find(w => w.name === "useOutputQuality");
|
|
const outputQualityWidget = node.widgets.find(w => w.name === "outputQuality");
|
|
|
|
if (useSeedWidget && seedWidget) {
|
|
function toggleSeed() {
|
|
const enabled = useSeedWidget.value === true;
|
|
toggleWidgetEnabled(seedWidget, enabled, node);
|
|
if (seedWidget.options && seedWidget.options.element) {
|
|
seedWidget.options.element.disabled = !enabled;
|
|
seedWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
seedWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
setTimeout(toggleSeed, 100);
|
|
appendWidgetCB(useSeedWidget, () => setTimeout(toggleSeed, 50));
|
|
}
|
|
|
|
if (!useOutputQualityWidget || !outputQualityWidget) return;
|
|
function toggleEnabled() {
|
|
const enabled = useOutputQualityWidget.value === true;
|
|
toggleWidgetEnabled(outputQualityWidget, enabled, node);
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
appendWidgetCB(useOutputQualityWidget, () => setTimeout(toggleEnabled, 50));
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
function threeDInferenceSettingsToggleHandler(node) {
|
|
const pairs = [
|
|
["useTextureSize", "textureSize"],
|
|
["useDecimationTarget", "decimationTarget"],
|
|
["useRemesh", "remesh"],
|
|
["useResolution", "resolution"],
|
|
["useImageAutoFix", "imageAutoFix"],
|
|
["useFaceLimit", "faceLimit"],
|
|
["useTexture", "texture"],
|
|
["usePbr", "pbr"],
|
|
["useTextureSeed", "textureSeed"],
|
|
["useTextureAlignment", "textureAlignment"],
|
|
["useTextureQuality", "textureQuality"],
|
|
["useAutoSize", "autoSize"],
|
|
["useOrientation", "orientation"],
|
|
["useQuad", "quad"],
|
|
["useCompress", "compress"],
|
|
["useSmartLowPoly", "smartLowPoly"],
|
|
["useGenerateParts", "generateParts"],
|
|
["useExportUv", "exportUv"],
|
|
["useGeometryQuality", "geometryQuality"],
|
|
["useOriginalAlpha", "originalAlpha"],
|
|
["useMaterial", "material"],
|
|
["useQuality", "quality"],
|
|
["usePolyCount", "polyCount"],
|
|
["useTaPose", "taPose"],
|
|
["useBoundingBox", "boundingBox"],
|
|
["useMeshMode", "meshMode"],
|
|
["useAddons", "addons"],
|
|
["useHdTexture", "hdTexture"],
|
|
["useMeshType", "meshType"],
|
|
["useTopology", "topology"],
|
|
["useDecimation", "decimation"],
|
|
["useSymmetry", "symmetry"],
|
|
["usePose", "pose"],
|
|
["useImageEnhancement", "imageEnhancement"],
|
|
["useRemoveLighting", "removeLighting"],
|
|
["useOrigin", "origin"],
|
|
["useModeration", "moderation"],
|
|
["useSavePreRemeshedModel", "savePreRemeshedModel"],
|
|
["useTexturePrompt", "texturePrompt"],
|
|
["useFaceCount", "faceCount"],
|
|
["useGenerateType", "generateType"],
|
|
["usePolygonType", "polygonType"],
|
|
["useGeometryOnly", "geometryOnly"],
|
|
["useRemeshBand", "remeshBand"],
|
|
["useRemeshProject", "remeshProject"],
|
|
["useTextureFormat", "textureFormat"],
|
|
["useAlphaMode", "alphaMode"],
|
|
];
|
|
pairs.forEach(([useName, paramName]) => {
|
|
const useW = node.widgets.find(w => w.name === useName);
|
|
const paramW = node.widgets.find(w => w.name === paramName);
|
|
if (!useW || !paramW) return;
|
|
function toggleEnabled() {
|
|
const enabled = useW.value === true;
|
|
toggleWidgetEnabled(paramW, enabled, node);
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
appendWidgetCB(useW, () => setTimeout(toggleEnabled, 50));
|
|
setTimeout(toggleEnabled, 100);
|
|
});
|
|
}
|
|
|
|
function threeDInferenceSettingsLatToggleHandler(node) {
|
|
const pairs = [
|
|
["useGuidanceStrength", "guidanceStrength"],
|
|
["useGuidanceRescale", "guidanceRescale"],
|
|
["useSteps", "steps"],
|
|
["useRescaleT", "rescaleT"],
|
|
];
|
|
pairs.forEach(([useName, paramName]) => {
|
|
const useW = node.widgets.find(w => w.name === useName);
|
|
const paramW = node.widgets.find(w => w.name === paramName);
|
|
if (!useW || !paramW) return;
|
|
function toggleEnabled() {
|
|
const enabled = useW.value === true;
|
|
toggleWidgetEnabled(paramW, enabled, node);
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
appendWidgetCB(useW, () => setTimeout(toggleEnabled, 50));
|
|
setTimeout(toggleEnabled, 100);
|
|
});
|
|
}
|
|
|
|
function threeDInferenceSettingsMeshClusterToggleHandler(node) {
|
|
const pairs = [
|
|
["useThresholdConeHalfAngleRad", "thresholdConeHalfAngleRad"],
|
|
["useRefineIterations", "refineIterations"],
|
|
["useGlobalIterations", "globalIterations"],
|
|
["useSmoothStrength", "smoothStrength"],
|
|
];
|
|
pairs.forEach(([useName, paramName]) => {
|
|
const useW = node.widgets.find(w => w.name === useName);
|
|
const paramW = node.widgets.find(w => w.name === paramName);
|
|
if (!useW || !paramW) return;
|
|
function toggleEnabled() {
|
|
const enabled = useW.value === true;
|
|
toggleWidgetEnabled(paramW, enabled, node);
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
appendWidgetCB(useW, () => setTimeout(toggleEnabled, 50));
|
|
setTimeout(toggleEnabled, 100);
|
|
});
|
|
}
|
|
|
|
function threeDInferenceSettingsDracoCompressionToggleHandler(node) {
|
|
const pairs = [
|
|
["useEnabled", "enabled"],
|
|
["useLevel", "level"],
|
|
["useQuantizationPosition", "quantizationPosition"],
|
|
["useQuantizationNormal", "quantizationNormal"],
|
|
["useQuantizationTexCoord", "quantizationTexCoord"],
|
|
];
|
|
pairs.forEach(([useName, paramName]) => {
|
|
const useW = node.widgets.find(w => w.name === useName);
|
|
const paramW = node.widgets.find(w => w.name === paramName);
|
|
if (!useW || !paramW) return;
|
|
function toggleEnabled() {
|
|
const enabled = useW.value === true;
|
|
toggleWidgetEnabled(paramW, enabled, node);
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
appendWidgetCB(useW, () => setTimeout(toggleEnabled, 50));
|
|
setTimeout(toggleEnabled, 100);
|
|
});
|
|
}
|
|
|
|
function openaiProviderSettingsToggleHandler(openaiNode) {
|
|
// Find all "use" parameter widgets for OpenAI Provider Settings (these are COMBO widgets)
|
|
const useBackgroundWidget = openaiNode.widgets.find(w => w.name === "useBackground");
|
|
const backgroundWidget = openaiNode.widgets.find(w => w.name === "background");
|
|
const useStyleWidget = openaiNode.widgets.find(w => w.name === "useStyle");
|
|
const styleWidget = openaiNode.widgets.find(w => w.name === "style");
|
|
|
|
// Helper function to toggle widget enabled state (exact same pattern, but handles COMBO)
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
// For COMBO widgets, check if value is "enable"
|
|
const enabled = useWidget.value === "enable" || useWidget.value === "Enable";
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
// Handle dropdown widgets
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = openaiNode.htmlElements?.widgetsContainer || openaiNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
openaiNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up all toggle handlers
|
|
if (useBackgroundWidget && backgroundWidget) {
|
|
toggleWidgetState(useBackgroundWidget, backgroundWidget, "background");
|
|
}
|
|
|
|
if (useStyleWidget && styleWidget) {
|
|
toggleWidgetState(useStyleWidget, styleWidget, "style");
|
|
}
|
|
}
|
|
|
|
function pixverseProviderSettingsToggleHandler(pixverseNode) {
|
|
// Find all "use" parameter widgets for Pixverse Provider Settings
|
|
const useEffectWidget = pixverseNode.widgets.find(w => w.name === "useEffect");
|
|
const effectWidget = pixverseNode.widgets.find(w => w.name === "effect");
|
|
const useCameraMovementWidget = pixverseNode.widgets.find(w => w.name === "useCameraMovement");
|
|
const cameraMovementWidget = pixverseNode.widgets.find(w => w.name === "cameraMovement");
|
|
const useStyleWidget = pixverseNode.widgets.find(w => w.name === "useStyle");
|
|
const styleWidget = pixverseNode.widgets.find(w => w.name === "style");
|
|
const useMotionModeWidget = pixverseNode.widgets.find(w => w.name === "useMotionMode");
|
|
const motionModeWidget = pixverseNode.widgets.find(w => w.name === "motionMode");
|
|
const useSoundEffectSwitchWidget = pixverseNode.widgets.find(w => w.name === "useSoundEffectSwitch");
|
|
const soundEffectSwitchWidget = pixverseNode.widgets.find(w => w.name === "soundEffectSwitch");
|
|
const useSoundEffectContentWidget = pixverseNode.widgets.find(w => w.name === "useSoundEffectContent");
|
|
const soundEffectContentWidget = pixverseNode.widgets.find(w => w.name === "soundEffectContent");
|
|
const useAudioWidget = pixverseNode.widgets.find(w => w.name === "useAudio");
|
|
const audioWidget = pixverseNode.widgets.find(w => w.name === "audio");
|
|
const useMultiClipWidget = pixverseNode.widgets.find(w => w.name === "useMultiClip");
|
|
const multiClipWidget = pixverseNode.widgets.find(w => w.name === "multiClip");
|
|
const useThinkingWidget = pixverseNode.widgets.find(w => w.name === "useThinking");
|
|
const thinkingWidget = pixverseNode.widgets.find(w => w.name === "thinking");
|
|
|
|
// Helper function to toggle widget enabled state (exact same pattern)
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
// Handle dropdown widgets
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = pixverseNode.htmlElements?.widgetsContainer || pixverseNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pixverseNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up all toggle handlers
|
|
if (useEffectWidget && effectWidget) {
|
|
toggleWidgetState(useEffectWidget, effectWidget, "effect");
|
|
}
|
|
|
|
if (useCameraMovementWidget && cameraMovementWidget) {
|
|
toggleWidgetState(useCameraMovementWidget, cameraMovementWidget, "cameraMovement");
|
|
}
|
|
|
|
if (useStyleWidget && styleWidget) {
|
|
toggleWidgetState(useStyleWidget, styleWidget, "style");
|
|
}
|
|
|
|
if (useMotionModeWidget && motionModeWidget) {
|
|
toggleWidgetState(useMotionModeWidget, motionModeWidget, "motionMode");
|
|
}
|
|
|
|
if (useSoundEffectSwitchWidget && soundEffectSwitchWidget) {
|
|
toggleWidgetState(useSoundEffectSwitchWidget, soundEffectSwitchWidget, "soundEffectSwitch");
|
|
}
|
|
|
|
if (useSoundEffectContentWidget && soundEffectContentWidget) {
|
|
toggleWidgetState(useSoundEffectContentWidget, soundEffectContentWidget, "soundEffectContent");
|
|
}
|
|
|
|
if (useAudioWidget && audioWidget) {
|
|
toggleWidgetState(useAudioWidget, audioWidget, "audio");
|
|
}
|
|
|
|
if (useMultiClipWidget && multiClipWidget) {
|
|
toggleWidgetState(useMultiClipWidget, multiClipWidget, "multiClip");
|
|
}
|
|
|
|
if (useThinkingWidget && thinkingWidget) {
|
|
toggleWidgetState(useThinkingWidget, thinkingWidget, "thinking");
|
|
}
|
|
}
|
|
|
|
function lightricksProviderSettingsToggleHandler(lightricksNode) {
|
|
const useStartTimeWidget = lightricksNode.widgets.find(w => w.name === "useStartTime");
|
|
const startTimeWidget = lightricksNode.widgets.find(w => w.name === "startTime");
|
|
const useDurationWidget = lightricksNode.widgets.find(w => w.name === "useDuration");
|
|
const durationWidget = lightricksNode.widgets.find(w => w.name === "duration");
|
|
const useModeWidget = lightricksNode.widgets.find(w => w.name === "useMode");
|
|
const modeWidget = lightricksNode.widgets.find(w => w.name === "mode");
|
|
const useGenerateAudioWidget = lightricksNode.widgets.find(w => w.name === "useGenerateAudio");
|
|
const generateAudioWidget = lightricksNode.widgets.find(w => w.name === "generateAudio");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = lightricksNode.htmlElements?.widgetsContainer || lightricksNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lightricksNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
if (useStartTimeWidget && startTimeWidget) {
|
|
toggleWidgetState(useStartTimeWidget, startTimeWidget, "startTime");
|
|
}
|
|
|
|
if (useDurationWidget && durationWidget) {
|
|
toggleWidgetState(useDurationWidget, durationWidget, "duration");
|
|
}
|
|
|
|
if (useModeWidget && modeWidget) {
|
|
toggleWidgetState(useModeWidget, modeWidget, "mode");
|
|
}
|
|
|
|
if (useGenerateAudioWidget && generateAudioWidget) {
|
|
toggleWidgetState(useGenerateAudioWidget, generateAudioWidget, "generateAudio");
|
|
}
|
|
}
|
|
|
|
function imageInferenceToggleHandler(imageInferenceNode) {
|
|
// Find all "use" parameter widgets for Image Inference
|
|
const useStepsWidget = imageInferenceNode.widgets.find(w => w.name === "useSteps");
|
|
const stepsWidget = imageInferenceNode.widgets.find(w => w.name === "steps");
|
|
const useSeedWidget = imageInferenceNode.widgets.find(w => w.name === "useSeed");
|
|
const seedWidget = imageInferenceNode.widgets.find(w => w.name === "seed");
|
|
const useCFGScaleWidget = imageInferenceNode.widgets.find(w => w.name === "useCFGScale");
|
|
const cfgScaleWidget = imageInferenceNode.widgets.find(w => w.name === "cfgScale");
|
|
const useSchedulerWidget = imageInferenceNode.widgets.find(w => w.name === "useScheduler");
|
|
const schedulerWidget = imageInferenceNode.widgets.find(w => w.name === "scheduler");
|
|
const useClipSkipWidget = imageInferenceNode.widgets.find(w => w.name === "useClipSkip");
|
|
const clipSkipWidget = imageInferenceNode.widgets.find(w => w.name === "clipSkip");
|
|
const maskMarginWidget = imageInferenceNode.widgets.find(w => w.name === "Mask Margin");
|
|
const maskMarginValueWidget = imageInferenceNode.widgets.find(w => w.name === "maskMargin");
|
|
const useResolutionWidget = imageInferenceNode.widgets.find(w => w.name === "useResolution");
|
|
const resolutionWidget = imageInferenceNode.widgets.find(w => w.name === "resolution");
|
|
const useUpscaleFactorWidget = imageInferenceNode.widgets.find(w => w.name === "useUpscaleFactor");
|
|
const upscaleFactorWidget = imageInferenceNode.widgets.find(w => w.name === "upscaleFactor");
|
|
const dimensionsWidget = imageInferenceNode.widgets.find(w => w.name === "dimensions");
|
|
const widthWidget = imageInferenceNode.widgets.find(w => w.name === "width");
|
|
const heightWidget = imageInferenceNode.widgets.find(w => w.name === "height");
|
|
|
|
// Helper function to toggle widget enabled state (exact same pattern as videoInferenceDimensionsHandler)
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
// Disable/enable widgets using inputEl if available (exact same pattern)
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
// Also set widget property
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = imageInferenceNode.htmlElements?.widgetsContainer || imageInferenceNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
imageInferenceNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback (exact same pattern as useCustomDimensions)
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up all toggle handlers
|
|
if (useStepsWidget && stepsWidget) {
|
|
toggleWidgetState(useStepsWidget, stepsWidget, "steps");
|
|
}
|
|
|
|
if (useSeedWidget && seedWidget) {
|
|
toggleWidgetState(useSeedWidget, seedWidget, "seed");
|
|
}
|
|
|
|
if (useCFGScaleWidget && cfgScaleWidget) {
|
|
toggleWidgetState(useCFGScaleWidget, cfgScaleWidget, "cfgScale");
|
|
}
|
|
|
|
if (useSchedulerWidget && schedulerWidget) {
|
|
toggleWidgetState(useSchedulerWidget, schedulerWidget, "scheduler");
|
|
}
|
|
|
|
if (useClipSkipWidget && clipSkipWidget) {
|
|
toggleWidgetState(useClipSkipWidget, clipSkipWidget, "clipSkip");
|
|
}
|
|
|
|
// Handle Mask Margin (BOOLEAN widget)
|
|
if (maskMarginWidget && maskMarginValueWidget) {
|
|
toggleWidgetState(maskMarginWidget, maskMarginValueWidget, "maskMargin");
|
|
}
|
|
|
|
// Handle Resolution
|
|
if (useResolutionWidget && resolutionWidget) {
|
|
toggleWidgetState(useResolutionWidget, resolutionWidget, "resolution");
|
|
}
|
|
|
|
if (useUpscaleFactorWidget && upscaleFactorWidget) {
|
|
toggleWidgetState(useUpscaleFactorWidget, upscaleFactorWidget, "upscaleFactor");
|
|
}
|
|
|
|
// Handle Dimensions - disable width/height when dimensions is "None"
|
|
if (dimensionsWidget && widthWidget && heightWidget) {
|
|
function toggleDimensionsState() {
|
|
const dimensionsValue = dimensionsWidget.value;
|
|
const enabled = dimensionsValue !== "None";
|
|
|
|
// Toggle width widget
|
|
if (widthWidget.inputEl) {
|
|
widthWidget.inputEl.disabled = !enabled;
|
|
widthWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
widthWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
widthWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
widthWidget.disabled = !enabled;
|
|
|
|
// Toggle height widget
|
|
if (heightWidget.inputEl) {
|
|
heightWidget.inputEl.disabled = !enabled;
|
|
heightWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
heightWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
heightWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
heightWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!widthWidget.inputEl || !heightWidget.inputEl) {
|
|
const nodeElement = imageInferenceNode.htmlElements?.widgetsContainer || imageInferenceNode.htmlElements;
|
|
if (nodeElement) {
|
|
const widthInput = nodeElement.querySelector(`input[name="width"]`);
|
|
const heightInput = nodeElement.querySelector(`input[name="height"]`);
|
|
if (widthInput) {
|
|
widthInput.disabled = !enabled;
|
|
widthInput.style.opacity = enabled ? "1" : "0.5";
|
|
widthInput.style.cursor = enabled ? "text" : "not-allowed";
|
|
widthInput.readOnly = !enabled;
|
|
}
|
|
if (heightInput) {
|
|
heightInput.disabled = !enabled;
|
|
heightInput.style.opacity = enabled ? "1" : "0.5";
|
|
heightInput.style.cursor = enabled ? "text" : "not-allowed";
|
|
heightInput.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
|
|
imageInferenceNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(dimensionsWidget, () => {
|
|
setTimeout(toggleDimensionsState, 50);
|
|
});
|
|
|
|
setTimeout(toggleDimensionsState, 100);
|
|
}
|
|
}
|
|
|
|
function videoInferenceDimensionsHandler(videoInferenceNode) {
|
|
// Find "use" parameter widgets for Video Inference
|
|
const useDurationWidget = videoInferenceNode.widgets.find(w => w.name === "useDuration");
|
|
const durationWidget = videoInferenceNode.widgets.find(w => w.name === "duration");
|
|
const useFpsWidget = videoInferenceNode.widgets.find(w => w.name === "useFps");
|
|
const fpsWidget = videoInferenceNode.widgets.find(w => w.name === "fps");
|
|
const useSeedWidget = videoInferenceNode.widgets.find(w => w.name === "useSeed");
|
|
const seedWidget = videoInferenceNode.widgets.find(w => w.name === "seed");
|
|
const useStepsWidget = videoInferenceNode.widgets.find(w => w.name === "useSteps");
|
|
const stepsWidget = videoInferenceNode.widgets.find(w => w.name === "steps");
|
|
const useBatchSizeWidget = videoInferenceNode.widgets.find(w => w.name === "useBatchSize");
|
|
const batchSizeWidget = videoInferenceNode.widgets.find(w => w.name === "batchSize");
|
|
const useSchedulersWidget = videoInferenceNode.widgets.find(w => w.name === "useSchedulers");
|
|
const schedulerWidget = videoInferenceNode.widgets.find(w => w.name === "scheduler");
|
|
const useCFGScaleWidget = videoInferenceNode.widgets.find(w => w.name === "useCFGScale");
|
|
const cfgScaleWidget = videoInferenceNode.widgets.find(w => w.name === "cfgScale");
|
|
const useTtlWidget = videoInferenceNode.widgets.find(w => w.name === "useTtl");
|
|
const ttlWidget = videoInferenceNode.widgets.find(w => w.name === "ttl");
|
|
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
// Disable/enable widgets using inputEl if available
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
// Also set widget property
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = videoInferenceNode.htmlElements?.widgetsContainer || videoInferenceNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
videoInferenceNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up all toggle handlers for "use" parameters
|
|
if (useDurationWidget && durationWidget) {
|
|
toggleWidgetState(useDurationWidget, durationWidget, "duration");
|
|
}
|
|
|
|
if (useFpsWidget && fpsWidget) {
|
|
toggleWidgetState(useFpsWidget, fpsWidget, "fps");
|
|
}
|
|
|
|
if (useSeedWidget && seedWidget) {
|
|
toggleWidgetState(useSeedWidget, seedWidget, "seed");
|
|
}
|
|
|
|
if (useStepsWidget && stepsWidget) {
|
|
toggleWidgetState(useStepsWidget, stepsWidget, "steps");
|
|
}
|
|
|
|
if (useBatchSizeWidget && batchSizeWidget) {
|
|
toggleWidgetState(useBatchSizeWidget, batchSizeWidget, "batchSize");
|
|
}
|
|
|
|
if (useSchedulersWidget && schedulerWidget) {
|
|
toggleWidgetState(useSchedulersWidget, schedulerWidget, "scheduler");
|
|
}
|
|
|
|
if (useCFGScaleWidget && cfgScaleWidget) {
|
|
toggleWidgetState(useCFGScaleWidget, cfgScaleWidget, "cfgScale");
|
|
}
|
|
|
|
if (useTtlWidget && ttlWidget) {
|
|
toggleWidgetState(useTtlWidget, ttlWidget, "ttl");
|
|
}
|
|
}
|
|
|
|
function videoModelSearchFilterHandler(videoModelSearchNode) {
|
|
const modelArchWidget = videoModelSearchNode.widgets.find(w => w.name === "Model Architecture");
|
|
const videoListWidget = videoModelSearchNode.widgets.find(w => w.name === "VideoList");
|
|
const widthWidget = videoModelSearchNode.widgets.find(w => w.name === "Width");
|
|
const heightWidget = videoModelSearchNode.widgets.find(w => w.name === "Height");
|
|
const useCustomDimensionsWidget = videoModelSearchNode.widgets.find(w => w.name === "useCustomDimensions");
|
|
const useResolutionWidget = videoModelSearchNode.widgets.find(w => w.name === "useResolution");
|
|
const resolutionWidget = videoModelSearchNode.widgets.find(w => w.name === "resolution");
|
|
|
|
if (!modelArchWidget || !videoListWidget) return;
|
|
|
|
const VIDEO_MODELS = {
|
|
"KlingAI": [
|
|
"klingai:1@2 (KlingAI V1.0 Pro)", "klingai:1@1 (KlingAI V1 Standard)",
|
|
"klingai:2@2 (KlingAI V1.5 Pro)", "klingai:2@1 (KlingAI V1.5 Standard)",
|
|
"klingai:3@1 (KlingAI V1.6 Standard)", "klingai:3@2 (KlingAI V1.6 Pro)",
|
|
"klingai:4@3 (KlingAI V2.1 Master)", "klingai:5@1 (KlingAI V2.1 Standard (I2V))",
|
|
"klingai:5@2 (KlingAI V2.1 Pro (I2V))", "klingai:5@3 (KlingAI V2.0 Master)",
|
|
"klingai:6@1 (KlingAI 2.5 Turbo Pro)",
|
|
"klingai:7@1 (KlingAI Lip-Sync)",
|
|
"klingai:kling@o1 (Kling VIDEO O1)",
|
|
"klingai:kling-video@2.6-pro (Kling VIDEO 2.6 Pro)",
|
|
"klingai:kling-video@3-pro (Kling VIDEO 3.0 Pro)",
|
|
"klingai:kling-video@3-standard (Kling VIDEO 3.0 Standard)",
|
|
"klingai:kling-video@3.0-turbo (Kling VIDEO 3.0 Turbo)",
|
|
"klingai:kling-video@3-4k (Kling VIDEO 3.0 4K)",
|
|
"klingai:kling-video@o3-pro (Kling VIDEO O3 Pro)",
|
|
"klingai:kling-video@o3-standard (Kling VIDEO O3 Standard)",
|
|
"klingai:kling-video@o3-4k (Kling VIDEO O3 4K)",
|
|
"klingai:avatar@2.0-standard (KlingAI Avatar 2.0 Standard)",
|
|
"klingai:avatar@2.0-pro (KlingAI Avatar 2.0 Pro)",
|
|
],
|
|
"Google": [
|
|
"google:2@0 (Veo 2.0)", "google:3@0 (Veo 3.0)", "google:3@1 (Veo 3.0 Fast)",
|
|
"google:3@2 (Veo 3.1)", "google:3@3 (Veo 3.1 Fast)",
|
|
"google:veo@3.1-lite (Veo 3.1 Lite)",
|
|
"google:gemini@omni-flash (Gemini Omni Flash)",
|
|
],
|
|
"Bytedance": [
|
|
"bytedance:2@1 (Seedance 1.0 Pro)", "bytedance:1@1 (Seedance 1.0 Lite)",
|
|
"bytedance:5@1 (OmniHuman 1)", "bytedance:5@2 (OmniHuman 1.5)",
|
|
"bytedance:seedance@1.5-pro (Seedance 1.5 Pro)",
|
|
"bytedance:seedance@2.0-fast (Seedance 2.0 Fast)",
|
|
"bytedance:seedance@2.0 (Seedance 2.0)",
|
|
"bytedance:seedance@2.0-mini (Seedance 2.0 Mini)",
|
|
],
|
|
"MiniMax": [
|
|
"minimax:1@1 (MiniMax 01 Base)", "minimax:2@1 (MiniMax 01 Director)",
|
|
"minimax:2@3 (MiniMax I2V 01 Live)", "minimax:3@1 (MiniMax 02 Hailuo)",
|
|
"minimax:4@1 (MiniMax Hailuo 2.3)", "minimax:4@2 (MiniMax Hailuo 2.3 Fast)",
|
|
],
|
|
"PixVerse": [
|
|
"pixverse:1@1 (PixVerse v3.5)", "pixverse:1@2 (PixVerse v4)",
|
|
"pixverse:1@3 (PixVerse v4.5)", "pixverse:1@5-fast (PixVerse v5 Fast)", "pixverse:1@6 (PixVerse v5.5)", "pixverse:1@7 (PixVerse v5.6)", "pixverse:1@8 (PixVerse v6)", "pixverse:lipsync@1 (PixVerse LipSync)", "pixverse:modify@0 (PixVerse Modify)",
|
|
],
|
|
"Vidu": [
|
|
"vidu:1@0 (Vidu Q1 Classic)", "vidu:1@1 (Vidu Q1)",
|
|
"vidu:1@5 (Vidu 1.5)", "vidu:2@0 (Vidu 2.0)",
|
|
"vidu:4@1 (Vidu Q3)",
|
|
"vidu:4@2 (Vidu Q3 Turbo)",
|
|
],
|
|
"Alibaba": [
|
|
"runware:200@1 (Wan 2.1 1.3B)", "runware:200@2 (Wan 2.1 14B)",
|
|
"runware:200@6 (Wan 2.2)",
|
|
"runware:200@8 (Wan 2.2 A14B Animate)",
|
|
"alibaba:wan@2.6 (Wan 2.6)",
|
|
"alibaba:wan@2.6-flash (Wan 2.6 Flash)",
|
|
"alibaba:wan@2.7 (Wan 2.7)",
|
|
"alibaba:happyhorse@1.0 (Alibaba Happy Horse 1.0)",
|
|
"alibaba:happyhorse@1.1 (Alibaba Happy Horse 1.1)",
|
|
],
|
|
"OpenAI": [
|
|
"openai:3@1 (OpenAI Sora 3.1)", "openai:3@0 (OpenAI Sora 3.0)",
|
|
],
|
|
"Lightricks": [
|
|
"lightricks:2@0 (LTX Fast)", "lightricks:2@1 (LTX Pro)",
|
|
"lightricks:3@1 (LTX-2 Retake)", "lightricks:ltx@2 (LTX-2)",
|
|
"lightricks:ltx@2.3 (LTX 2.3)", "lightricks:ltx@2.3-fast (LTX 2.3 Fast)",
|
|
"lightricks:ltx@2.3-open (LTX-2.3 Open)",
|
|
],
|
|
"Ovi": [
|
|
"runware:190@1 (Ovi)",
|
|
],
|
|
"Runway": [
|
|
"runway:aleph@2.0 (Runway Aleph 2.0)",
|
|
"runway:2@1 (Runway Aleph)",
|
|
"runway:1@1 (Runway Gen-4 Turbo)",
|
|
"runway:1@2 (Runway Gen-4.5)",
|
|
],
|
|
"Luma": [
|
|
"lumaai:1@1 (Luma Ray 1.6)",
|
|
"lumaai:2@1 (Luma Ray 2)",
|
|
"lumaai:2@2 (Luma Ray 2 Flash)",
|
|
"luma:ray@3.2 (Luma Ray 3.2)",
|
|
],
|
|
"Sync": [
|
|
"sync:lipsync-2@1 (Sync LipSync 2)",
|
|
"sync:lipsync-2-pro@1 (Sync LipSync 2 Pro)",
|
|
"sync:react-1@1 (Sync React-1)",
|
|
"sync:3@0 (Sync 3)",
|
|
],
|
|
"Bria": [
|
|
"bria:60@1 (Bria Video Eraser)",
|
|
],
|
|
"Creatify": [
|
|
"creatify:aurora@fast (Creatify Aurora Avatar Model API (720p))",
|
|
"creatify:aurora@0 (Creatify Aurora Avatar Model API (720p))",
|
|
],
|
|
"HeyGen": [
|
|
"heygen:avatar@4 (HeyGen Avatar IV)",
|
|
"heygen:video-agent@0 (HeyGen Video Agent)",
|
|
"heygen:avatar@5 (HeyGen Avatar V)",
|
|
],
|
|
"Hunyuan": [
|
|
"runware:hunyuanvideo@1.5 (HunyuanVideo-1.5)",
|
|
],
|
|
"Kandinsky": [
|
|
"runware:210@1 (Kandinsky 5.0 Lite)",
|
|
],
|
|
"xAI": [
|
|
"xai:grok-imagine@video-1.5 (Grok Imagine Video 1.5)",
|
|
"xai:grok-imagine@video-1.5-preview (Grok Imagine Video 1.5 Preview)",
|
|
"xai:grok-imagine@video (Grok Imagine Video)",
|
|
],
|
|
"VEED": [
|
|
"veed:fabric@1.0 (VEED Fabric 1.0)",
|
|
],
|
|
"Pruna": [
|
|
"prunaai:p-video@0 (P-Video)",
|
|
"prunaai:p-video@avatar (P-Video Avatar)",
|
|
"prunaai:p-video@animate (P-Video Animate)",
|
|
"prunaai:p-video@replace (P-Video Replace)",
|
|
],
|
|
"SkyReels": [
|
|
"skywork:skyreels@v4 (SkyReels V4)",
|
|
],
|
|
};
|
|
|
|
const MODEL_DIMENSIONS = {
|
|
"klingai:1@2": {"width": 1280, "height": 720},
|
|
"klingai:1@1": {"width": 1280, "height": 720},
|
|
"klingai:2@2": {"width": 1920, "height": 1080},
|
|
"klingai:2@1": {"width": 1280, "height": 720},
|
|
"klingai:3@1": {"width": 1280, "height": 720},
|
|
"klingai:3@2": {"width": 1920, "height": 1080},
|
|
"klingai:4@3": {"width": 1280, "height": 720},
|
|
"klingai:5@1": {"width": 1280, "height": 720},
|
|
"klingai:5@2": {"width": 1920, "height": 1080},
|
|
"klingai:5@3": {"width": 1920, "height": 1080},
|
|
"klingai:6@1": {"width": 1920, "height": 1080},
|
|
"klingai:7@1": {"width": 0, "height": 0},
|
|
"klingai:kling@o1": {"width": 1440, "height": 1440},
|
|
"klingai:kling-video@2.6-pro": {"width": 1920, "height": 1080},
|
|
"klingai:kling-video@3-pro": {"width": 1920, "height": 1080},
|
|
"klingai:kling-video@3-standard": {"width": 1920, "height": 1080},
|
|
"klingai:kling-video@3.0-turbo": {"width": 1920, "height": 1080},
|
|
"klingai:kling-video@3-4k": {"width": 3840, "height": 2160},
|
|
"klingai:kling-video@o3-pro": {"width": 1920, "height": 1080},
|
|
"klingai:kling-video@o3-standard": {"width": 1920, "height": 1080},
|
|
"klingai:kling-video@o3-4k": {"width": 3840, "height": 2160},
|
|
"klingai:avatar@2.0-standard": {"width": 0, "height": 0},
|
|
"klingai:avatar@2.0-pro": {"width": 0, "height": 0},
|
|
"google:2@0": {"width": 1280, "height": 720},
|
|
"google:3@0": {"width": 1280, "height": 720},
|
|
"google:3@1": {"width": 1280, "height": 720},
|
|
"google:3@2": {"width": 1280, "height": 720},
|
|
"google:3@3": {"width": 1280, "height": 720},
|
|
"google:veo@3.1-lite": {"width": 1280, "height": 720},
|
|
"google:gemini@omni-flash": {"width": 1280, "height": 720},
|
|
"bytedance:2@1": {"width": 864, "height": 480},
|
|
"bytedance:1@1": {"width": 864, "height": 480},
|
|
"bytedance:5@1": {"width": 1024, "height": 1024},
|
|
"bytedance:5@2": {"width": 1024, "height": 1024},
|
|
"bytedance:seedance@1.5-pro": {"width": 864, "height": 496},
|
|
"bytedance:seedance@2.0-fast": {"width": 864, "height": 496},
|
|
"bytedance:seedance@2.0": {"width": 864, "height": 496},
|
|
"bytedance:seedance@2.0-mini": {"width": 864, "height": 496},
|
|
"minimax:1@1": {"width": 1366, "height": 768},
|
|
"minimax:2@1": {"width": 1366, "height": 768},
|
|
"minimax:2@3": {"width": 1366, "height": 768},
|
|
"minimax:3@1": {"width": 1366, "height": 768},
|
|
"minimax:4@1": {"width": 1366, "height": 768},
|
|
"minimax:4@2": {"width": 1366, "height": 768},
|
|
"pixverse:1@1": {"width": 640, "height": 360},
|
|
"pixverse:1@2": {"width": 640, "height": 360},
|
|
"pixverse:1@3": {"width": 640, "height": 360},
|
|
"pixverse:1@5-fast": {"width": 640, "height": 360},
|
|
"pixverse:1@6": {"width": 640, "height": 360},
|
|
"pixverse:1@7": {"width": 640, "height": 360},
|
|
"pixverse:1@8": {"width": 640, "height": 360},
|
|
"pixverse:lipsync@1": {"width": 640, "height": 360},
|
|
"pixverse:modify@0": {"width": 640, "height": 360},
|
|
"vidu:1@0": {"width": 1920, "height": 1080},
|
|
"vidu:1@1": {"width": 1920, "height": 1080},
|
|
"vidu:1@5": {"width": 1920, "height": 1080},
|
|
"vidu:2@0": {"width": 1920, "height": 1080},
|
|
"vidu:4@1": {"width": 1920, "height": 1080},
|
|
"vidu:4@2": {"width": 1920, "height": 1080},
|
|
"runware:200@1": {"width": 853, "height": 480},
|
|
"runware:200@2": {"width": 853, "height": 480},
|
|
"runware:200@6": {"width": 1280, "height": 720},
|
|
"runware:200@8": {"width": 1104, "height": 832},
|
|
"alibaba:wan@2.6": {"width": 1280, "height": 720},
|
|
"alibaba:wan@2.6-flash": {"width": 1280, "height": 720},
|
|
"alibaba:wan@2.7": {"width": 1280, "height": 720},
|
|
"alibaba:happyhorse@1.0": {"width": 1280, "height": 720},
|
|
"alibaba:happyhorse@1.1": {"width": 1280, "height": 720},
|
|
"openai:3@1": {"width": 1280, "height": 720},
|
|
"openai:3@0": {"width": 1280, "height": 720},
|
|
"lightricks:2@0": {"width": 1920, "height": 1080},
|
|
"lightricks:2@1": {"width": 1920, "height": 1080},
|
|
"lightricks:3@1": {"width": 0, "height": 0},
|
|
"lightricks:ltx@2": {"width": 1024, "height": 1024},
|
|
"lightricks:ltx@2.3": {"width": 1920, "height": 1080},
|
|
"lightricks:ltx@2.3-fast": {"width": 1920, "height": 1080},
|
|
"lightricks:ltx@2.3-open": {"width": 1024, "height": 1024},
|
|
"runware:190@1": {"width": 0, "height": 0},
|
|
"runway:aleph@2.0": {"width": 0, "height": 0},
|
|
"runway:2@1": {"width": 1280, "height": 720},
|
|
"runway:1@1": {"width": 1280, "height": 720},
|
|
"runway:1@2": {"width": 1280, "height": 720},
|
|
"lumaai:1@1": {"width": 1080, "height": 720},
|
|
"lumaai:2@1": {"width": 1080, "height": 720},
|
|
"lumaai:2@2": {"width": 1080, "height": 720},
|
|
"luma:ray@3.2": {"width": 1280, "height": 720},
|
|
"sync:lipsync-2@1": {"width": 0, "height": 0},
|
|
"sync:lipsync-2-pro@1": {"width": 0, "height": 0},
|
|
"sync:react-1@1": {"width": 0, "height": 0},
|
|
"sync:3@0": {"width": 1280, "height": 720},
|
|
"bria:60@1": {"width": 1280, "height": 720},
|
|
"creatify:aurora@fast": {"width": 1280, "height": 720},
|
|
"creatify:aurora@0": {"width": 1280, "height": 720},
|
|
"runware:hunyuanvideo@1.5": {"width": 848, "height": 480},
|
|
"runware:210@1": {"width": 512, "height": 512},
|
|
"xai:grok-imagine@video-1.5": {"width": 480, "height": 480},
|
|
"xai:grok-imagine@video-1.5-preview": {"width": 480, "height": 480},
|
|
"xai:grok-imagine@video": {"width": 480, "height": 480},
|
|
"veed:fabric@1.0": {"width": 1280, "height": 720},
|
|
"prunaai:p-video@0": {"width": 1280, "height": 720},
|
|
"prunaai:p-video@avatar": {"width": 1280, "height": 720},
|
|
"prunaai:p-video@animate": {"width": 1280, "height": 720},
|
|
"prunaai:p-video@replace": {"width": 1280, "height": 720},
|
|
"heygen:avatar@4": {"width": 1280, "height": 720},
|
|
"heygen:video-agent@0": {"width": 1280, "height": 720},
|
|
"heygen:avatar@5": {"width": 1280, "height": 720},
|
|
"skywork:skyreels@v4": {"width": 1280, "height": 720},
|
|
};
|
|
|
|
const MODEL_RESOLUTIONS = {
|
|
"klingai:1@2": "720p",
|
|
"klingai:1@1": "720p",
|
|
"klingai:2@2": "1080p",
|
|
"klingai:2@1": "720p",
|
|
"klingai:3@1": "720p",
|
|
"klingai:3@2": "1080p",
|
|
"klingai:4@3": "720p",
|
|
"klingai:5@1": "720p",
|
|
"klingai:5@2": "1080p",
|
|
"klingai:5@3": "1080p",
|
|
"klingai:6@1": "1080p",
|
|
"klingai:7@1": null, // No resolution support
|
|
"klingai:kling@o1": null, // No standard resolution
|
|
"klingai:kling-video@2.6-pro": "1080p",
|
|
"klingai:kling-video@3-pro": "1080p",
|
|
"klingai:kling-video@3-standard": "1080p",
|
|
"klingai:kling-video@3.0-turbo": "1080p",
|
|
"klingai:kling-video@3-4k": null, // No 4K option in current resolution dropdown
|
|
"klingai:kling-video@o3-pro": "1080p",
|
|
"klingai:kling-video@o3-standard": "1080p",
|
|
"klingai:kling-video@o3-4k": null, // No 4K option in current resolution dropdown
|
|
"klingai:avatar@2.0-standard": null, // No resolution support
|
|
"klingai:avatar@2.0-pro": null, // No resolution support
|
|
"google:2@0": "720p",
|
|
"google:3@0": "720p",
|
|
"google:3@1": "720p",
|
|
"google:3@2": "720p",
|
|
"google:3@3": "720p",
|
|
"google:veo@3.1-lite": "720p",
|
|
"google:gemini@omni-flash": "720p",
|
|
"bytedance:2@1": "480p",
|
|
"bytedance:1@1": "480p",
|
|
"bytedance:5@1": null, // No resolution support
|
|
"bytedance:5@2": null, // No resolution support
|
|
"bytedance:seedance@1.5-pro": "480p",
|
|
"bytedance:seedance@2.0-fast": "480p",
|
|
"bytedance:seedance@2.0": "480p",
|
|
"bytedance:seedance@2.0-mini": "480p",
|
|
"minimax:1@1": "768p",
|
|
"minimax:2@1": "768p",
|
|
"minimax:2@3": "768p",
|
|
"minimax:3@1": "768p",
|
|
"minimax:4@1": "768p",
|
|
"minimax:4@2": "768p",
|
|
"pixverse:1@1": "360p",
|
|
"pixverse:1@2": "360p",
|
|
"pixverse:1@3": "360p",
|
|
"pixverse:1@5-fast": "360p",
|
|
"pixverse:1@6": "360p",
|
|
"pixverse:1@7": "360p",
|
|
"pixverse:1@8": "360p",
|
|
"pixverse:lipsync@1": "360p",
|
|
"pixverse:modify@0": "360p",
|
|
"vidu:1@0": "1080p",
|
|
"vidu:1@1": "1080p",
|
|
"vidu:1@5": "1080p",
|
|
"vidu:2@0": "1080p",
|
|
"vidu:4@1": "1080p",
|
|
"vidu:4@2": "1080p",
|
|
"runware:200@1": "480p",
|
|
"runware:200@2": "480p",
|
|
"runware:200@6": "720p",
|
|
"runware:200@8": "720p",
|
|
"alibaba:wan@2.6": "720p",
|
|
"alibaba:wan@2.6-flash": "720p",
|
|
"alibaba:wan@2.7": "720p",
|
|
"alibaba:happyhorse@1.0": "720p",
|
|
"alibaba:happyhorse@1.1": "720p",
|
|
"openai:3@1": "720p",
|
|
"openai:3@0": "720p",
|
|
"lightricks:2@0": "1080p",
|
|
"lightricks:2@1": "1080p",
|
|
"lightricks:3@1": null, // No resolution support
|
|
"lightricks:ltx@2": null, // No resolution support (fixed 1024x1024)
|
|
"lightricks:ltx@2.3": "1080p",
|
|
"lightricks:ltx@2.3-fast": "1080p",
|
|
"lightricks:ltx@2.3-open": null, // No resolution support (fixed 1024x1024)
|
|
"runware:190@1": null, // No resolution support
|
|
"runway:aleph@2.0": null, // Output ratio matches input video
|
|
"runway:2@1": "720p",
|
|
"runway:1@1": "720p",
|
|
"runway:1@2": "720p",
|
|
"lumaai:1@1": "720p",
|
|
"lumaai:2@1": "720p",
|
|
"lumaai:2@2": "720p",
|
|
"luma:ray@3.2": "720p",
|
|
"sync:lipsync-2@1": "720p",
|
|
"sync:lipsync-2-pro@1": "720p",
|
|
"sync:react-1@1": "720p",
|
|
"sync:3@0": "720p",
|
|
"bria:60@1": "720p",
|
|
"creatify:aurora@fast": "720p",
|
|
"creatify:aurora@0": "720p",
|
|
"runware:hunyuanvideo@1.5": "480p",
|
|
"runware:210@1": null, // No resolution support (fixed 512x512)
|
|
"xai:grok-imagine@video-1.5": "480p",
|
|
"xai:grok-imagine@video-1.5-preview": "480p",
|
|
"xai:grok-imagine@video": "480p",
|
|
"veed:fabric@1.0": "720p",
|
|
"prunaai:p-video@0": "720p",
|
|
"prunaai:p-video@avatar": "720p",
|
|
"prunaai:p-video@animate": "720p",
|
|
"prunaai:p-video@replace": "720p",
|
|
"heygen:avatar@4": "720p",
|
|
"heygen:video-agent@0": "720p",
|
|
"heygen:avatar@5": "720p",
|
|
"skywork:skyreels@v4": "720p",
|
|
};
|
|
|
|
const DEFAULT_DIMENSIONS = {"width": 1024, "height": 576};
|
|
|
|
function setWidthHeightEnabled(enabled) {
|
|
if (!widthWidget || !heightWidget) return;
|
|
[widthWidget, heightWidget].forEach(widget => {
|
|
widget.disabled = !enabled;
|
|
if (widget.inputEl) {
|
|
widget.inputEl.disabled = !enabled;
|
|
widget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
widget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
widget.inputEl.readOnly = !enabled;
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateDimensions() {
|
|
if (!widthWidget || !heightWidget || !videoListWidget) return;
|
|
|
|
const selectedModel = videoListWidget.value;
|
|
if (!selectedModel) return;
|
|
|
|
const useCustomDimensionsValue = useCustomDimensionsWidget ? useCustomDimensionsWidget.value : "Model Default";
|
|
|
|
// Handle "Disabled" option - disable widgets and set to 0 (but Python will use None in dict)
|
|
if (useCustomDimensionsValue === "Disabled") {
|
|
setWidthHeightEnabled(false);
|
|
if (widthWidget.callback) widthWidget.callback(0, "customSetOperation");
|
|
widthWidget.value = 0;
|
|
if (heightWidget.callback) heightWidget.callback(0, "customSetOperation");
|
|
heightWidget.value = 0;
|
|
videoModelSearchNode.setDirtyCanvas(true);
|
|
return;
|
|
}
|
|
|
|
// Handle "Model Default" option - disable widgets and use model defaults
|
|
if (useCustomDimensionsValue === "Model Default") {
|
|
setWidthHeightEnabled(false);
|
|
} else if (useCustomDimensionsValue === "Custom") {
|
|
// Handle "Custom" option - enable widgets
|
|
setWidthHeightEnabled(true);
|
|
}
|
|
|
|
const modelCode = selectedModel.split(" (")[0];
|
|
const dims = MODEL_DIMENSIONS[modelCode] || DEFAULT_DIMENSIONS;
|
|
|
|
// Only update dimensions if "Model Default" is selected (widgets are disabled but we show the values)
|
|
if (useCustomDimensionsValue === "Model Default") {
|
|
if (dims.width === 0 && dims.height === 0) {
|
|
// Set to None when dimensions are 0,0
|
|
if (widthWidget.callback) widthWidget.callback(null, "customSetOperation");
|
|
if (heightWidget.callback) heightWidget.callback(null, "customSetOperation");
|
|
videoModelSearchNode.setDirtyCanvas(true);
|
|
} else if (dims.width !== 0 && dims.height !== 0) {
|
|
if (widthWidget.callback) widthWidget.callback(dims.width, "customSetOperation");
|
|
if (heightWidget.callback) heightWidget.callback(dims.height, "customSetOperation");
|
|
videoModelSearchNode.setDirtyCanvas(true);
|
|
}
|
|
}
|
|
// For "Custom" mode, don't update - let user set their own values
|
|
// For "Disabled" mode, already handled above (set to None and disabled)
|
|
|
|
// Update resolution based on selected model
|
|
if (resolutionWidget && useResolutionWidget) {
|
|
const modelCode = selectedModel.split(" (")[0];
|
|
const modelResolution = MODEL_RESOLUTIONS[modelCode];
|
|
|
|
// If model supports resolution
|
|
if (modelResolution !== null && modelResolution !== undefined) {
|
|
// Enable useResolution checkbox
|
|
if (useResolutionWidget.inputEl) {
|
|
useResolutionWidget.inputEl.disabled = false;
|
|
useResolutionWidget.inputEl.style.opacity = "1";
|
|
}
|
|
useResolutionWidget.disabled = false;
|
|
|
|
// Only update resolution value if useResolution is enabled
|
|
if (useResolutionWidget.value === true) {
|
|
// Set resolution value to model's default
|
|
if (resolutionWidget.callback) resolutionWidget.callback(modelResolution, "customSetOperation");
|
|
resolutionWidget.value = modelResolution;
|
|
}
|
|
} else {
|
|
// Model doesn't support resolution, disable useResolution checkbox and resolution dropdown
|
|
if (useResolutionWidget.callback) useResolutionWidget.callback(false, "customSetOperation");
|
|
useResolutionWidget.value = false;
|
|
|
|
// Disable useResolution checkbox
|
|
if (useResolutionWidget.inputEl) {
|
|
useResolutionWidget.inputEl.disabled = true;
|
|
useResolutionWidget.inputEl.style.opacity = "0.5";
|
|
}
|
|
useResolutionWidget.disabled = true;
|
|
|
|
// Disable resolution dropdown
|
|
if (resolutionWidget.inputEl) {
|
|
resolutionWidget.inputEl.disabled = true;
|
|
resolutionWidget.inputEl.style.opacity = "0.5";
|
|
resolutionWidget.inputEl.style.cursor = "not-allowed";
|
|
}
|
|
resolutionWidget.disabled = true;
|
|
}
|
|
videoModelSearchNode.setDirtyCanvas(true);
|
|
}
|
|
}
|
|
|
|
function filterModelList() {
|
|
const selectedArch = modelArchWidget.value;
|
|
const selectedArchNormalized = selectedArch === "Wan" ? "Alibaba" : selectedArch;
|
|
let filteredModels = [];
|
|
|
|
if (selectedArchNormalized === "All") {
|
|
Object.values(VIDEO_MODELS).forEach(models => filteredModels.push(...models));
|
|
} else if (VIDEO_MODELS[selectedArchNormalized]) {
|
|
filteredModels = VIDEO_MODELS[selectedArchNormalized];
|
|
}
|
|
|
|
if (filteredModels.length > 0) {
|
|
const currentValue = videoListWidget.value;
|
|
videoListWidget.options.values = filteredModels;
|
|
|
|
if (!filteredModels.includes(currentValue)) {
|
|
videoListWidget.value = filteredModels[0];
|
|
}
|
|
|
|
updateDimensions();
|
|
videoModelSearchNode.setDirtyCanvas(true);
|
|
}
|
|
}
|
|
|
|
appendWidgetCB(modelArchWidget, filterModelList);
|
|
if (videoListWidget) {
|
|
appendWidgetCB(videoListWidget, updateDimensions);
|
|
}
|
|
if (useCustomDimensionsWidget) {
|
|
appendWidgetCB(useCustomDimensionsWidget, () => {
|
|
updateDimensions();
|
|
});
|
|
}
|
|
|
|
// Handle useResolution toggle
|
|
if (useResolutionWidget && resolutionWidget) {
|
|
function toggleResolutionState() {
|
|
// Check if current model supports resolution
|
|
const selectedModel = videoListWidget ? videoListWidget.value : null;
|
|
if (!selectedModel) return;
|
|
|
|
const modelCode = selectedModel.split(" (")[0];
|
|
const modelResolution = MODEL_RESOLUTIONS[modelCode];
|
|
|
|
// Only enable resolution if model supports it and useResolution is enabled
|
|
const enabled = useResolutionWidget.value === true && modelResolution !== null && modelResolution !== undefined;
|
|
|
|
if (resolutionWidget.inputEl) {
|
|
resolutionWidget.inputEl.disabled = !enabled;
|
|
resolutionWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
resolutionWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
}
|
|
|
|
resolutionWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find input via DOM if inputEl is not available
|
|
if (!resolutionWidget.inputEl) {
|
|
const nodeElement = videoModelSearchNode.htmlElements?.widgetsContainer || videoModelSearchNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`select[name="resolution"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
|
|
videoModelSearchNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useResolutionWidget, () => {
|
|
setTimeout(toggleResolutionState, 50);
|
|
});
|
|
|
|
// Also update when model changes
|
|
if (videoListWidget) {
|
|
appendWidgetCB(videoListWidget, () => {
|
|
setTimeout(toggleResolutionState, 50);
|
|
});
|
|
}
|
|
|
|
setTimeout(toggleResolutionState, 100);
|
|
}
|
|
|
|
filterModelList();
|
|
updateDimensions();
|
|
}
|
|
|
|
function textModelSearchFilterHandler(textModelSearchNode) {
|
|
const modelProviderWidget = textModelSearchNode.widgets.find(w => w.name === "Model Provider");
|
|
const textListWidget = textModelSearchNode.widgets.find(w => w.name === "TextList");
|
|
|
|
if (!modelProviderWidget || !textListWidget) return;
|
|
|
|
const TEXT_MODELS = {
|
|
"MiniMax": [
|
|
"minimax:m2.7@0 (MiniMax-M2.7)",
|
|
"minimax:m2.7@highspeed (MiniMax-M2.7 Highspeed)",
|
|
"minimax:m2.5@0 (MiniMax-M2.5)",
|
|
],
|
|
"OpenAI": [
|
|
"openai:gpt@5.4 (GPT-5.4)",
|
|
"openai:gpt@5.4-pro (GPT-5.4 Pro)",
|
|
"openai:gpt@5.4-mini (GPT-5.4 Mini)",
|
|
"openai:gpt@5.4-nano (GPT-5.4 Nano)",
|
|
],
|
|
"Anthropic": [
|
|
"anthropic:claude@opus-4.7 (Claude Opus 4.7)",
|
|
"anthropic:claude@sonnet-4.6 (Claude Sonnet 4.6)",
|
|
"anthropic:claude@haiku-4.5 (Claude Haiku 4.5)",
|
|
],
|
|
"Google": [
|
|
"google:gemini@3-flash (Gemini 3 Flash)",
|
|
],
|
|
"MoonshotAI": [
|
|
"moonshotai:kimi@k2.6 (Kimi K2.6)",
|
|
],
|
|
"Zai": [
|
|
"zai-glm-5-1 (ZAI GLM 5.1)",
|
|
],
|
|
};
|
|
|
|
function filterModelList() {
|
|
const selectedProvider = modelProviderWidget.value;
|
|
let filteredModels = [];
|
|
|
|
if (selectedProvider === "All") {
|
|
Object.values(TEXT_MODELS).forEach(models => filteredModels.push(...models));
|
|
} else if (TEXT_MODELS[selectedProvider]) {
|
|
filteredModels = TEXT_MODELS[selectedProvider];
|
|
}
|
|
|
|
if (filteredModels.length > 0) {
|
|
const currentValue = textListWidget.value;
|
|
textListWidget.options.values = filteredModels;
|
|
|
|
if (!filteredModels.includes(currentValue)) {
|
|
textListWidget.value = filteredModels[0];
|
|
}
|
|
|
|
textModelSearchNode.setDirtyCanvas(true);
|
|
}
|
|
}
|
|
|
|
appendWidgetCB(modelProviderWidget, filterModelList);
|
|
filterModelList();
|
|
}
|
|
|
|
function threeDModelSearchFilterHandler(threeDModelSearchNode) {
|
|
const modelArchWidget = threeDModelSearchNode.widgets.find(w => w.name === "Model Architecture");
|
|
const threeDListWidget = threeDModelSearchNode.widgets.find(w => w.name === "ThreeDList");
|
|
|
|
if (!modelArchWidget || !threeDListWidget) return;
|
|
|
|
const THREED_MODELS = {
|
|
"Tencent": [
|
|
"tencent:hunyuan-3d@3.1-pro (Tencent Hunyuan 3D 3.1 Pro)",
|
|
"tencent:hunyuan-3d@3.1-rapid (Tencent Hunyuan 3D 3.1 Rapid)",
|
|
],
|
|
"Meta": [
|
|
"meta:sam@3d (Meta SAM 3D)",
|
|
],
|
|
"Microsoft": [
|
|
"microsoft:trellis-2@4b (TRELLIS.2)",
|
|
],
|
|
"Tripo": [
|
|
"tripo:v3.1@0 (Tripo 3D v3.1)",
|
|
],
|
|
"Hyper3D": [
|
|
"hyper3d:rodin@gen-1 (Rodin Gen-1)",
|
|
"hyper3d:rodin@gen-2 (Rodin Gen-2)",
|
|
],
|
|
"Meshy": [
|
|
"meshy:meshy@6 (Meshy 6)",
|
|
],
|
|
};
|
|
|
|
function filterModelList() {
|
|
const selectedArch = modelArchWidget.value;
|
|
let filteredModels = [];
|
|
|
|
if (selectedArch === "All") {
|
|
Object.values(THREED_MODELS).forEach(models => filteredModels.push(...models));
|
|
} else if (THREED_MODELS[selectedArch]) {
|
|
filteredModels = THREED_MODELS[selectedArch];
|
|
}
|
|
|
|
if (filteredModels.length > 0) {
|
|
const currentValue = threeDListWidget.value;
|
|
threeDListWidget.options.values = filteredModels;
|
|
|
|
if (!filteredModels.includes(currentValue)) {
|
|
threeDListWidget.value = filteredModels[0];
|
|
}
|
|
|
|
threeDModelSearchNode.setDirtyCanvas(true);
|
|
}
|
|
}
|
|
|
|
appendWidgetCB(modelArchWidget, filterModelList);
|
|
filterModelList();
|
|
}
|
|
|
|
function audioModelSearchFilterHandler(audioModelSearchNode) {
|
|
const modelProviderWidget = audioModelSearchNode.widgets.find(w => w.name === "Model Provider");
|
|
const audioListWidget = audioModelSearchNode.widgets.find(w => w.name === "AudioList");
|
|
|
|
if (!modelProviderWidget || !audioListWidget) return;
|
|
|
|
const AUDIO_MODELS = {
|
|
"ElevenLabs": [
|
|
"elevenlabs:1@1 (ElevenLabs Multilingual v2)",
|
|
"elevenlabs:2@1 (ElevenLabs Multilingual v2 Turbo)",
|
|
"elevenlabs:3@1 (ElevenLabs Monolingual v1)",
|
|
],
|
|
"KlingAI": [
|
|
"klingai:8@1 (KlingAI Audio)",
|
|
],
|
|
"Mirelo": [
|
|
"mirelo:1@1 (Mirelo SFX 1.5)",
|
|
],
|
|
"Ace": [
|
|
"runware:ace-step@0 (ACE Step v1 3.5B)",
|
|
"runware:ace-step@v1.5-base (ACE-Step v1.5 Base)",
|
|
"runware:ace-step@v1.5-turbo (ACE-Step v1.5 Turbo)",
|
|
"runware:ace-step@v1.5-xl-base (ACE-Step v1.5 XL Base)",
|
|
"runware:ace-step@v1.5-xl-turbo (ACE-Step v1.5 XL Turbo)",
|
|
"runware:ace-step@v1.5-xl-sft (ACE-Step v1.5 XL SFT)",
|
|
],
|
|
"Alibaba": [
|
|
"alibaba:qwen@3-tts-1.7b-voicedesign (Qwen3 TTS 1.7B Voice Design)",
|
|
"alibaba:qwen@3-tts-1.7b-customvoice (Qwen3 TTS 1.7B Custom Voice)",
|
|
"alibaba:qwen@3-tts-1.7b-base (Qwen3 TTS 1.7B Base)",
|
|
],
|
|
"Bytedance": [
|
|
"bytedance:seed-audio@1.0 (Seed Audio 1.0)",
|
|
],
|
|
"Dia": [
|
|
"runware:dia@v1.0 (Dia 1.6B)",
|
|
"runware:dia2@2b (Dia2 2B)",
|
|
],
|
|
"xAI": [
|
|
"xai:voice@tts (xAI TTS)",
|
|
],
|
|
"MiniMax": [
|
|
"minimax:speech@2.8 (MiniMax Speech 2.8)",
|
|
"minimax:music@cover (MiniMax Music Cover)",
|
|
"minimax:music@2.6 (MiniMax Music 2.6)",
|
|
],
|
|
"Inworld": [
|
|
"inworld:tts@2 (Inworld Realtime TTS 2)",
|
|
"inworld:tts@1.5-mini (Inworld TTS-1.5 Mini)",
|
|
"inworld:tts@1.5-max (Inworld TTS-1.5 Max)",
|
|
],
|
|
"Google": [
|
|
"google:gemini@3.1-flash-tts (Gemini 3.1 Flash TTS)",
|
|
],
|
|
"Fish": [
|
|
"fishaudio:s2.1@pro (Fish Audio S2.1 Pro)",
|
|
],
|
|
};
|
|
|
|
function filterModelList() {
|
|
const selectedProvider = modelProviderWidget.value;
|
|
let filteredModels = [];
|
|
|
|
if (selectedProvider === "All") {
|
|
Object.values(AUDIO_MODELS).forEach(models => filteredModels.push(...models));
|
|
} else if (AUDIO_MODELS[selectedProvider]) {
|
|
filteredModels = AUDIO_MODELS[selectedProvider];
|
|
}
|
|
|
|
if (filteredModels.length > 0) {
|
|
const currentValue = audioListWidget.value;
|
|
audioListWidget.options.values = filteredModels;
|
|
|
|
if (!filteredModels.includes(currentValue)) {
|
|
audioListWidget.value = filteredModels[0];
|
|
}
|
|
|
|
audioModelSearchNode.setDirtyCanvas(true);
|
|
}
|
|
}
|
|
|
|
appendWidgetCB(modelProviderWidget, filterModelList);
|
|
filterModelList();
|
|
}
|
|
|
|
function vectorizeModelSearchFilterHandler(vectorizeNode) {
|
|
const modelArchWidget = vectorizeNode.widgets.find(w => w.name === "Model Architecture");
|
|
const vectorListWidget = vectorizeNode.widgets.find(w => w.name === "Vector Model List");
|
|
|
|
if (!modelArchWidget || !vectorListWidget) return;
|
|
|
|
const VECTORIZE_MODELS = {
|
|
"Recraft": [
|
|
"recraft:1@1 (Recraft 1)",
|
|
"recraft:v4-pro@vector (Recraft V4 Pro Vector)",
|
|
"recraft:v4@vector (Recraft V4 Vector)",
|
|
],
|
|
"Picsart": [
|
|
"picsart:1@1 (Picsart 1)",
|
|
],
|
|
};
|
|
|
|
function filterModelList() {
|
|
const selectedArch = modelArchWidget.value;
|
|
let filteredModels = [];
|
|
|
|
if (selectedArch === "All") {
|
|
Object.values(VECTORIZE_MODELS).forEach(models => filteredModels.push(...models));
|
|
} else if (VECTORIZE_MODELS[selectedArch]) {
|
|
filteredModels = VECTORIZE_MODELS[selectedArch];
|
|
}
|
|
|
|
if (filteredModels.length > 0) {
|
|
const currentValue = vectorListWidget.value;
|
|
vectorListWidget.options.values = filteredModels;
|
|
|
|
if (!filteredModels.includes(currentValue)) {
|
|
vectorListWidget.value = filteredModels[0];
|
|
}
|
|
|
|
vectorizeNode.setDirtyCanvas(true);
|
|
}
|
|
}
|
|
|
|
appendWidgetCB(modelArchWidget, filterModelList);
|
|
filterModelList();
|
|
}
|
|
|
|
function vectorizeToggleHandler(vectorizeNode) {
|
|
const usePositivePromptWidget = vectorizeNode.widgets.find(w => w.name === "Use positivePrompt");
|
|
const positivePromptWidget = vectorizeNode.widgets.find(w => w.name === "positivePrompt");
|
|
const dimensionsWidget = vectorizeNode.widgets.find(w => w.name === "dimensions");
|
|
const widthWidget = vectorizeNode.widgets.find(w => w.name === "width");
|
|
const heightWidget = vectorizeNode.widgets.find(w => w.name === "height");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function applyState() {
|
|
const enabled = useWidget.value === true;
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
}
|
|
}
|
|
applyState();
|
|
appendWidgetCB(useWidget, applyState);
|
|
}
|
|
|
|
if (usePositivePromptWidget && positivePromptWidget) {
|
|
toggleWidgetState(usePositivePromptWidget, positivePromptWidget, "positivePrompt");
|
|
}
|
|
|
|
// Disable width/height when dimensions is "None" (same as image inference)
|
|
if (dimensionsWidget && widthWidget && heightWidget) {
|
|
function toggleDimensionsState() {
|
|
const dimensionsValue = dimensionsWidget.value;
|
|
const enabled = dimensionsValue !== "None";
|
|
|
|
if (widthWidget.inputEl) {
|
|
widthWidget.inputEl.disabled = !enabled;
|
|
widthWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
widthWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
widthWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
widthWidget.disabled = !enabled;
|
|
|
|
if (heightWidget.inputEl) {
|
|
heightWidget.inputEl.disabled = !enabled;
|
|
heightWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
heightWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
heightWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
heightWidget.disabled = !enabled;
|
|
|
|
vectorizeNode.setDirtyCanvas(true);
|
|
}
|
|
appendWidgetCB(dimensionsWidget, () => {
|
|
setTimeout(toggleDimensionsState, 50);
|
|
});
|
|
setTimeout(toggleDimensionsState, 100);
|
|
}
|
|
}
|
|
|
|
function klingProviderSettingsToggleHandler(klingNode) {
|
|
// Find all "use" parameter widgets for KlingAI Provider Settings (EXACT same pattern as imageInferenceToggleHandler)
|
|
const useCameraControlWidget = klingNode.widgets.find(w => w.name === "useCameraControl");
|
|
const cameraControlWidget = klingNode.widgets.find(w => w.name === "cameraControl");
|
|
const useSoundVolumeWidget = klingNode.widgets.find(w => w.name === "useSoundVolume");
|
|
const soundVolumeWidget = klingNode.widgets.find(w => w.name === "soundVolume");
|
|
const useOriginalAudioVolumeWidget = klingNode.widgets.find(w => w.name === "useOriginalAudioVolume");
|
|
const originalAudioVolumeWidget = klingNode.widgets.find(w => w.name === "originalAudioVolume");
|
|
const useSoundEffectPromptWidget = klingNode.widgets.find(w => w.name === "useSoundEffectPrompt");
|
|
const soundEffectPromptWidget = klingNode.widgets.find(w => w.name === "soundEffectPrompt");
|
|
const useBgmPromptWidget = klingNode.widgets.find(w => w.name === "useBgmPrompt");
|
|
const bgmPromptWidget = klingNode.widgets.find(w => w.name === "bgmPrompt");
|
|
const useAsmrModeWidget = klingNode.widgets.find(w => w.name === "useAsmrMode");
|
|
const asmrModeWidget = klingNode.widgets.find(w => w.name === "asmrMode");
|
|
const useKeepOriginalSoundWidget = klingNode.widgets.find(w => w.name === "useKeepOriginalSound");
|
|
const keepOriginalSoundWidget = klingNode.widgets.find(w => w.name === "keepOriginalSound");
|
|
const useSoundWidget = klingNode.widgets.find(w => w.name === "useSound");
|
|
const soundWidget = klingNode.widgets.find(w => w.name === "sound");
|
|
const useCharacterOrientationWidget = klingNode.widgets.find(w => w.name === "useCharacterOrientation");
|
|
const characterOrientationWidget = klingNode.widgets.find(w => w.name === "characterOrientation");
|
|
const useMultipromptWidget = klingNode.widgets.find(w => w.name === "useMultiprompt");
|
|
|
|
// Helper function to toggle widget enabled state (EXACT same pattern as imageInferenceToggleHandler)
|
|
// Callers guard with if (useX && xWidget) before invoking
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
// Disable/enable widgets using inputEl if available (exact same pattern)
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
// Also set widget property
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = klingNode.htmlElements?.widgetsContainer || klingNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
klingNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback (exact same pattern as imageInferenceToggleHandler)
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state (exact same pattern)
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up all toggle handlers (exact same pattern as imageInferenceToggleHandler)
|
|
if (useCameraControlWidget && cameraControlWidget) {
|
|
toggleWidgetState(useCameraControlWidget, cameraControlWidget, "cameraControl");
|
|
}
|
|
|
|
if (useSoundVolumeWidget && soundVolumeWidget) {
|
|
toggleWidgetState(useSoundVolumeWidget, soundVolumeWidget, "soundVolume");
|
|
}
|
|
|
|
if (useOriginalAudioVolumeWidget && originalAudioVolumeWidget) {
|
|
toggleWidgetState(useOriginalAudioVolumeWidget, originalAudioVolumeWidget, "originalAudioVolume");
|
|
}
|
|
|
|
if (useSoundEffectPromptWidget && soundEffectPromptWidget) {
|
|
toggleWidgetState(useSoundEffectPromptWidget, soundEffectPromptWidget, "soundEffectPrompt");
|
|
}
|
|
|
|
if (useBgmPromptWidget && bgmPromptWidget) {
|
|
toggleWidgetState(useBgmPromptWidget, bgmPromptWidget, "bgmPrompt");
|
|
}
|
|
|
|
if (useAsmrModeWidget && asmrModeWidget) {
|
|
toggleWidgetState(useAsmrModeWidget, asmrModeWidget, "asmrMode");
|
|
}
|
|
|
|
if (useKeepOriginalSoundWidget && keepOriginalSoundWidget) {
|
|
toggleWidgetState(useKeepOriginalSoundWidget, keepOriginalSoundWidget, "keepOriginalSound");
|
|
}
|
|
|
|
if (useSoundWidget && soundWidget) {
|
|
toggleWidgetState(useSoundWidget, soundWidget, "sound");
|
|
}
|
|
|
|
if (useCharacterOrientationWidget && characterOrientationWidget) {
|
|
toggleWidgetState(useCharacterOrientationWidget, characterOrientationWidget, "characterOrientation");
|
|
}
|
|
|
|
// Toggle MultiPrompt Segment input slots when useMultiprompt changes
|
|
if (useMultipromptWidget) {
|
|
function toggleMultipromptInputs() {
|
|
const enabled = useMultipromptWidget.value === true;
|
|
klingNode.inputs?.forEach(inp => {
|
|
if (inp?.name?.startsWith("MultiPrompt Segment")) {
|
|
inp.disabled = !enabled;
|
|
if (inp.domElement) {
|
|
inp.domElement.style.opacity = enabled ? "1" : "0.4";
|
|
inp.domElement.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
});
|
|
klingNode.setDirtyCanvas(true);
|
|
}
|
|
appendWidgetCB(useMultipromptWidget, () => setTimeout(toggleMultipromptInputs, 50));
|
|
setTimeout(toggleMultipromptInputs, 100);
|
|
}
|
|
}
|
|
|
|
function alibabaProviderSettingsToggleHandler(alibabaNode) {
|
|
// Find all "use" parameter widgets for Alibaba Provider Settings
|
|
const usePromptEnhancerWidget = alibabaNode.widgets.find(w => w.name === "usePromptEnhancer");
|
|
const promptEnhancerWidget = alibabaNode.widgets.find(w => w.name === "promptEnhancer");
|
|
const usePromptExtendWidget = alibabaNode.widgets.find(w => w.name === "usePromptExtend");
|
|
const promptExtendWidget = alibabaNode.widgets.find(w => w.name === "promptExtend");
|
|
const useAudioWidget = alibabaNode.widgets.find(w => w.name === "useAudio");
|
|
const audioWidget = alibabaNode.widgets.find(w => w.name === "audio");
|
|
const useShotTypeWidget = alibabaNode.widgets.find(w => w.name === "useShotType");
|
|
const shotTypeWidget = alibabaNode.widgets.find(w => w.name === "shotType");
|
|
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = alibabaNode.htmlElements?.widgetsContainer || alibabaNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
alibabaNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Special handler for shotType - depends on both usePromptExtend AND promptExtend being true
|
|
function toggleShotTypeEnabled() {
|
|
if (!useShotTypeWidget || !shotTypeWidget || !usePromptExtendWidget || !promptExtendWidget) return;
|
|
|
|
const usePromptExtendEnabled = usePromptExtendWidget.value === true;
|
|
const promptExtendValue = promptExtendWidget.value === true;
|
|
const useShotTypeEnabled = useShotTypeWidget.value === true;
|
|
|
|
// shotType is enabled only if: useShotType is enabled AND usePromptExtend is enabled AND promptExtend is true
|
|
const enabled = useShotTypeEnabled && usePromptExtendEnabled && promptExtendValue;
|
|
|
|
if (shotTypeWidget.inputEl) {
|
|
shotTypeWidget.inputEl.disabled = !enabled;
|
|
shotTypeWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
shotTypeWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
shotTypeWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
shotTypeWidget.disabled = !enabled;
|
|
|
|
if (!shotTypeWidget.inputEl) {
|
|
const nodeElement = alibabaNode.htmlElements?.widgetsContainer || alibabaNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="shotType"], select[name="shotType"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
alibabaNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up toggle handlers
|
|
if (usePromptEnhancerWidget && promptEnhancerWidget) {
|
|
toggleWidgetState(usePromptEnhancerWidget, promptEnhancerWidget, "promptEnhancer");
|
|
}
|
|
|
|
if (usePromptExtendWidget && promptExtendWidget) {
|
|
toggleWidgetState(usePromptExtendWidget, promptExtendWidget, "promptExtend");
|
|
|
|
// Also listen to promptExtend value changes to update shotType
|
|
appendWidgetCB(promptExtendWidget, () => {
|
|
setTimeout(toggleShotTypeEnabled, 50);
|
|
});
|
|
}
|
|
|
|
if (useAudioWidget && audioWidget) {
|
|
toggleWidgetState(useAudioWidget, audioWidget, "audio");
|
|
}
|
|
|
|
if (useShotTypeWidget && shotTypeWidget) {
|
|
// Listen to useShotType changes
|
|
appendWidgetCB(useShotTypeWidget, () => {
|
|
setTimeout(toggleShotTypeEnabled, 50);
|
|
});
|
|
|
|
// Also listen to usePromptExtend changes
|
|
if (usePromptExtendWidget) {
|
|
appendWidgetCB(usePromptExtendWidget, () => {
|
|
setTimeout(toggleShotTypeEnabled, 50);
|
|
});
|
|
}
|
|
|
|
// Initial state
|
|
setTimeout(toggleShotTypeEnabled, 100);
|
|
}
|
|
}
|
|
|
|
function mireloProviderSettingsToggleHandler(mireloNode) {
|
|
// Find all "use" parameter widgets for Mirelo Provider Settings
|
|
const useStartOffsetWidget = mireloNode.widgets.find(w => w.name === "useStartOffset");
|
|
const startOffsetWidget = mireloNode.widgets.find(w => w.name === "startOffset");
|
|
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = mireloNode.htmlElements?.widgetsContainer || mireloNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mireloNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handler
|
|
if (useStartOffsetWidget && startOffsetWidget) {
|
|
toggleWidgetState(useStartOffsetWidget, startOffsetWidget, "startOffset");
|
|
}
|
|
}
|
|
|
|
function lumaProviderSettingsToggleHandler(lumaNode) {
|
|
// Find all "use" parameter widgets for Luma Provider Settings
|
|
const useLoopWidget = lumaNode.widgets.find(w => w.name === "useLoop");
|
|
const loopWidget = lumaNode.widgets.find(w => w.name === "loop");
|
|
const useConcept1Widget = lumaNode.widgets.find(w => w.name === "useConcept1");
|
|
const concept1Widget = lumaNode.widgets.find(w => w.name === "concept1");
|
|
const useConcept2Widget = lumaNode.widgets.find(w => w.name === "useConcept2");
|
|
const concept2Widget = lumaNode.widgets.find(w => w.name === "concept2");
|
|
const useConcept3Widget = lumaNode.widgets.find(w => w.name === "useConcept3");
|
|
const concept3Widget = lumaNode.widgets.find(w => w.name === "concept3");
|
|
const useConcept4Widget = lumaNode.widgets.find(w => w.name === "useConcept4");
|
|
const concept4Widget = lumaNode.widgets.find(w => w.name === "concept4");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = lumaNode.htmlElements?.widgetsContainer || lumaNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lumaNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
if (useLoopWidget && loopWidget) {
|
|
toggleWidgetState(useLoopWidget, loopWidget, "loop");
|
|
}
|
|
|
|
if (useConcept1Widget && concept1Widget) {
|
|
toggleWidgetState(useConcept1Widget, concept1Widget, "concept1");
|
|
}
|
|
|
|
if (useConcept2Widget && concept2Widget) {
|
|
toggleWidgetState(useConcept2Widget, concept2Widget, "concept2");
|
|
}
|
|
|
|
if (useConcept3Widget && concept3Widget) {
|
|
toggleWidgetState(useConcept3Widget, concept3Widget, "concept3");
|
|
}
|
|
|
|
if (useConcept4Widget && concept4Widget) {
|
|
toggleWidgetState(useConcept4Widget, concept4Widget, "concept4");
|
|
}
|
|
}
|
|
|
|
function briaProviderSettingsToggleHandler(briaNode) {
|
|
// Find all "use" parameter widgets for Bria Provider Settings
|
|
const useMediumWidget = briaNode.widgets.find(w => w.name === "useMedium");
|
|
const mediumWidget = briaNode.widgets.find(w => w.name === "medium");
|
|
const usePromptEnhancementWidget = briaNode.widgets.find(w => w.name === "usePromptEnhancement");
|
|
const promptEnhancementWidget = briaNode.widgets.find(w => w.name === "promptEnhancement");
|
|
const useEnhanceImageWidget = briaNode.widgets.find(w => w.name === "useEnhanceImage");
|
|
const enhanceImageWidget = briaNode.widgets.find(w => w.name === "enhanceImage");
|
|
const usePromptContentModerationWidget = briaNode.widgets.find(w => w.name === "usePromptContentModeration");
|
|
const promptContentModerationWidget = briaNode.widgets.find(w => w.name === "promptContentModeration");
|
|
const useContentModerationWidget = briaNode.widgets.find(w => w.name === "useContentModeration");
|
|
const contentModerationWidget = briaNode.widgets.find(w => w.name === "contentModeration");
|
|
const useIpSignalWidget = briaNode.widgets.find(w => w.name === "useIpSignal");
|
|
const ipSignalWidget = briaNode.widgets.find(w => w.name === "ipSignal");
|
|
const usePreserveAlphaWidget = briaNode.widgets.find(w => w.name === "usePreserveAlpha");
|
|
const preserveAlphaWidget = briaNode.widgets.find(w => w.name === "preserveAlpha");
|
|
const useModeWidget = briaNode.widgets.find(w => w.name === "useMode");
|
|
const modeWidget = briaNode.widgets.find(w => w.name === "mode");
|
|
const useEnhanceReferenceImagesWidget = briaNode.widgets.find(w => w.name === "useEnhanceReferenceImages");
|
|
const enhanceReferenceImagesWidget = briaNode.widgets.find(w => w.name === "enhanceReferenceImages");
|
|
const useRefinePromptWidget = briaNode.widgets.find(w => w.name === "useRefinePrompt");
|
|
const refinePromptWidget = briaNode.widgets.find(w => w.name === "refinePrompt");
|
|
const useOriginalQualityWidget = briaNode.widgets.find(w => w.name === "useOriginalQuality");
|
|
const originalQualityWidget = briaNode.widgets.find(w => w.name === "originalQuality");
|
|
const useForceBackgroundDetectionWidget = briaNode.widgets.find(w => w.name === "useForceBackgroundDetection");
|
|
const forceBackgroundDetectionWidget = briaNode.widgets.find(w => w.name === "forceBackgroundDetection");
|
|
const useAutoTrimWidget = briaNode.widgets.find(w => w.name === "useAutoTrim");
|
|
const autoTrimWidget = briaNode.widgets.find(w => w.name === "autoTrim");
|
|
const usePreserveAudioWidget = briaNode.widgets.find(w => w.name === "usePreserveAudio");
|
|
const preserveAudioWidget = briaNode.widgets.find(w => w.name === "preserveAudio");
|
|
const useSeasonWidget = briaNode.widgets.find(w => w.name === "useSeason");
|
|
const seasonWidget = briaNode.widgets.find(w => w.name === "season");
|
|
const useEditWidget = briaNode.widgets.find(w => w.name === "useEdit");
|
|
const editWidget = briaNode.widgets.find(w => w.name === "edit");
|
|
const useColorWidget = briaNode.widgets.find(w => w.name === "useColor");
|
|
const colorWidget = briaNode.widgets.find(w => w.name === "color");
|
|
const useLightDirectionWidget = briaNode.widgets.find(w => w.name === "useLightDirection");
|
|
const lightDirectionWidget = briaNode.widgets.find(w => w.name === "lightDirection");
|
|
const useLightTypeWidget = briaNode.widgets.find(w => w.name === "useLightType");
|
|
const lightTypeWidget = briaNode.widgets.find(w => w.name === "lightType");
|
|
|
|
// Helper function to toggle widget enabled state (exact same pattern)
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
// Disable/enable widgets using inputEl if available (exact same pattern)
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
// Handle dropdown widgets (for medium and mode)
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
// Also set widget property
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = briaNode.htmlElements?.widgetsContainer || briaNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
briaNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback (exact same pattern)
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up all toggle handlers
|
|
if (useMediumWidget && mediumWidget) {
|
|
toggleWidgetState(useMediumWidget, mediumWidget, "medium");
|
|
}
|
|
|
|
if (usePromptEnhancementWidget && promptEnhancementWidget) {
|
|
toggleWidgetState(usePromptEnhancementWidget, promptEnhancementWidget, "promptEnhancement");
|
|
}
|
|
|
|
if (useEnhanceImageWidget && enhanceImageWidget) {
|
|
toggleWidgetState(useEnhanceImageWidget, enhanceImageWidget, "enhanceImage");
|
|
}
|
|
|
|
if (usePromptContentModerationWidget && promptContentModerationWidget) {
|
|
toggleWidgetState(usePromptContentModerationWidget, promptContentModerationWidget, "promptContentModeration");
|
|
}
|
|
|
|
if (useContentModerationWidget && contentModerationWidget) {
|
|
toggleWidgetState(useContentModerationWidget, contentModerationWidget, "contentModeration");
|
|
}
|
|
|
|
if (useIpSignalWidget && ipSignalWidget) {
|
|
toggleWidgetState(useIpSignalWidget, ipSignalWidget, "ipSignal");
|
|
}
|
|
|
|
if (usePreserveAlphaWidget && preserveAlphaWidget) {
|
|
toggleWidgetState(usePreserveAlphaWidget, preserveAlphaWidget, "preserveAlpha");
|
|
}
|
|
|
|
if (useModeWidget && modeWidget) {
|
|
toggleWidgetState(useModeWidget, modeWidget, "mode");
|
|
}
|
|
|
|
if (useEnhanceReferenceImagesWidget && enhanceReferenceImagesWidget) {
|
|
toggleWidgetState(useEnhanceReferenceImagesWidget, enhanceReferenceImagesWidget, "enhanceReferenceImages");
|
|
}
|
|
|
|
if (useRefinePromptWidget && refinePromptWidget) {
|
|
toggleWidgetState(useRefinePromptWidget, refinePromptWidget, "refinePrompt");
|
|
}
|
|
|
|
if (useOriginalQualityWidget && originalQualityWidget) {
|
|
toggleWidgetState(useOriginalQualityWidget, originalQualityWidget, "originalQuality");
|
|
}
|
|
|
|
if (useForceBackgroundDetectionWidget && forceBackgroundDetectionWidget) {
|
|
toggleWidgetState(useForceBackgroundDetectionWidget, forceBackgroundDetectionWidget, "forceBackgroundDetection");
|
|
}
|
|
|
|
if (useAutoTrimWidget && autoTrimWidget) {
|
|
toggleWidgetState(useAutoTrimWidget, autoTrimWidget, "autoTrim");
|
|
}
|
|
|
|
if (usePreserveAudioWidget && preserveAudioWidget) {
|
|
toggleWidgetState(usePreserveAudioWidget, preserveAudioWidget, "preserveAudio");
|
|
}
|
|
|
|
if (useSeasonWidget && seasonWidget) {
|
|
toggleWidgetState(useSeasonWidget, seasonWidget, "season");
|
|
}
|
|
|
|
if (useEditWidget && editWidget) {
|
|
toggleWidgetState(useEditWidget, editWidget, "edit");
|
|
}
|
|
|
|
if (useColorWidget && colorWidget) {
|
|
toggleWidgetState(useColorWidget, colorWidget, "color");
|
|
}
|
|
|
|
if (useLightDirectionWidget && lightDirectionWidget) {
|
|
toggleWidgetState(useLightDirectionWidget, lightDirectionWidget, "lightDirection");
|
|
}
|
|
|
|
if (useLightTypeWidget && lightTypeWidget) {
|
|
toggleWidgetState(useLightTypeWidget, lightTypeWidget, "lightType");
|
|
}
|
|
}
|
|
|
|
function audioInputToggleHandler(audioInputNode) {
|
|
// Find "use" parameter widget and "id" widget for Audio Input
|
|
const useIdWidget = audioInputNode.widgets.find(w => w.name === "useId");
|
|
const idWidget = audioInputNode.widgets.find(w => w.name === "id");
|
|
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
// Disable/enable widgets using inputEl if available
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
// Also set widget property
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = audioInputNode.htmlElements?.widgetsContainer || audioInputNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
audioInputNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handler for "useId" parameter
|
|
if (useIdWidget && idWidget) {
|
|
toggleWidgetState(useIdWidget, idWidget, "id");
|
|
}
|
|
}
|
|
|
|
function speechInputToggleHandler(speechInputNode) {
|
|
// Find "use" parameter widget and "id" widget for Speech Input
|
|
const useIdWidget = speechInputNode.widgets.find(w => w.name === "useId");
|
|
const idWidget = speechInputNode.widgets.find(w => w.name === "id");
|
|
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
// Disable/enable widgets using inputEl if available
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
// Also set widget property
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = speechInputNode.htmlElements?.widgetsContainer || speechInputNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
speechInputNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handler for "useId" parameter
|
|
if (useIdWidget && idWidget) {
|
|
toggleWidgetState(useIdWidget, idWidget, "id");
|
|
}
|
|
}
|
|
|
|
function briaProviderMaskToggleHandler(maskNode) {
|
|
// Helper function to toggle widget enabled state for multiple widgets
|
|
function toggleWidgetState(useWidget, paramWidgets, paramNames) {
|
|
if (!useWidget || !paramWidgets || paramWidgets.length === 0) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
paramWidgets.forEach((paramWidget, idx) => {
|
|
if (!paramWidget) return;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
// Handle dropdown widgets (for Type fields)
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl && paramNames[idx]) {
|
|
const nodeElement = maskNode.htmlElements?.widgetsContainer || maskNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramNames[idx]}"], textarea[name="${paramNames[idx]}"], select[name="${paramNames[idx]}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
maskNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handlers for foreground, prompt, frameIndex
|
|
const useForegroundWidget = maskNode.widgets.find(w => w.name === "useForeground");
|
|
const foregroundWidget = maskNode.widgets.find(w => w.name === "foreground");
|
|
if (useForegroundWidget && foregroundWidget) {
|
|
toggleWidgetState(useForegroundWidget, [foregroundWidget], ["foreground"]);
|
|
}
|
|
|
|
const usePromptWidget = maskNode.widgets.find(w => w.name === "usePrompt");
|
|
const promptWidget = maskNode.widgets.find(w => w.name === "prompt");
|
|
if (usePromptWidget && promptWidget) {
|
|
toggleWidgetState(usePromptWidget, [promptWidget], ["prompt"]);
|
|
}
|
|
|
|
const useFrameIndexWidget = maskNode.widgets.find(w => w.name === "useFrameIndex");
|
|
const frameIndexWidget = maskNode.widgets.find(w => w.name === "frameIndex");
|
|
if (useFrameIndexWidget && frameIndexWidget) {
|
|
toggleWidgetState(useFrameIndexWidget, [frameIndexWidget], ["frameIndex"]);
|
|
}
|
|
|
|
// Set up toggle handlers for all 6 key points
|
|
for (let i = 1; i <= 6; i++) {
|
|
const useWidget = maskNode.widgets.find(w => w.name === `use_${i}`);
|
|
const xWidget = maskNode.widgets.find(w => w.name === `X${i}`);
|
|
const yWidget = maskNode.widgets.find(w => w.name === `Y${i}`);
|
|
const typeWidget = maskNode.widgets.find(w => w.name === `Type${i}`);
|
|
|
|
if (useWidget && xWidget && yWidget && typeWidget) {
|
|
toggleWidgetState(useWidget, [xWidget, yWidget, typeWidget], [`X${i}`, `Y${i}`, `Type${i}`]);
|
|
}
|
|
}
|
|
}
|
|
|
|
function wanAnimateAdvancedFeatureSettingsToggleHandler(wanAnimateNode) {
|
|
// Find widgets
|
|
const useModeWidget = wanAnimateNode.widgets.find(w => w.name === "useMode");
|
|
const modeWidget = wanAnimateNode.widgets.find(w => w.name === "mode");
|
|
const useRetargetPoseWidget = wanAnimateNode.widgets.find(w => w.name === "useRetargetPose");
|
|
const retargetPoseWidget = wanAnimateNode.widgets.find(w => w.name === "retargetPose");
|
|
const usePrevSegCondFramesWidget = wanAnimateNode.widgets.find(w => w.name === "usePrevSegCondFrames");
|
|
const prevSegCondFramesWidget = wanAnimateNode.widgets.find(w => w.name === "prevSegCondFrames");
|
|
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
// Handle dropdown widgets (for mode field)
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl && paramName) {
|
|
const nodeElement = wanAnimateNode.htmlElements?.widgetsContainer || wanAnimateNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wanAnimateNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handler for mode
|
|
if (useModeWidget && modeWidget) {
|
|
toggleWidgetState(useModeWidget, modeWidget, "mode");
|
|
}
|
|
|
|
// Set up toggle handler for retargetPose (with mode dependency)
|
|
if (useRetargetPoseWidget && retargetPoseWidget) {
|
|
function toggleRetargetPoseEnabled() {
|
|
const useRetargetPoseEnabled = useRetargetPoseWidget.value === true;
|
|
const modeValue = modeWidget ? modeWidget.value : "animate";
|
|
// retargetPose is only supported for animate mode
|
|
const enabled = useRetargetPoseEnabled && modeValue === "animate";
|
|
|
|
if (retargetPoseWidget.inputEl) {
|
|
retargetPoseWidget.inputEl.disabled = !enabled;
|
|
retargetPoseWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
retargetPoseWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
retargetPoseWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
retargetPoseWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM
|
|
if (!retargetPoseWidget.inputEl) {
|
|
const nodeElement = wanAnimateNode.htmlElements?.widgetsContainer || wanAnimateNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="retargetPose"], textarea[name="retargetPose"], select[name="retargetPose"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
|
|
wanAnimateNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback for useRetargetPose toggle
|
|
appendWidgetCB(useRetargetPoseWidget, () => {
|
|
setTimeout(toggleRetargetPoseEnabled, 50);
|
|
});
|
|
|
|
// Set up callback for mode change (to disable retargetPose when mode is "replace")
|
|
if (modeWidget) {
|
|
appendWidgetCB(modeWidget, () => {
|
|
setTimeout(toggleRetargetPoseEnabled, 50);
|
|
});
|
|
}
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleRetargetPoseEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handler for prevSegCondFrames
|
|
if (usePrevSegCondFramesWidget && prevSegCondFramesWidget) {
|
|
toggleWidgetState(usePrevSegCondFramesWidget, prevSegCondFramesWidget, "prevSegCondFrames");
|
|
}
|
|
}
|
|
|
|
function videoAdvancedFeatureInputsToggleHandler(advancedFeatureNode) {
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl && paramName) {
|
|
const nodeElement = advancedFeatureNode.htmlElements?.widgetsContainer || advancedFeatureNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
|
|
advancedFeatureNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handlers for each parameter
|
|
const useVideoCFGScaleWidget = advancedFeatureNode.widgets.find(w => w.name === "useVideoCFGScale");
|
|
const videoCFGScaleWidget = advancedFeatureNode.widgets.find(w => w.name === "videoCFGScale");
|
|
if (useVideoCFGScaleWidget && videoCFGScaleWidget) {
|
|
toggleWidgetState(useVideoCFGScaleWidget, videoCFGScaleWidget, "videoCFGScale");
|
|
}
|
|
|
|
const useAudioCFGScaleWidget = advancedFeatureNode.widgets.find(w => w.name === "useAudioCFGScale");
|
|
const audioCFGScaleWidget = advancedFeatureNode.widgets.find(w => w.name === "audioCFGScale");
|
|
if (useAudioCFGScaleWidget && audioCFGScaleWidget) {
|
|
toggleWidgetState(useAudioCFGScaleWidget, audioCFGScaleWidget, "audioCFGScale");
|
|
}
|
|
|
|
const useVideoNegativePromptWidget = advancedFeatureNode.widgets.find(w => w.name === "useVideoNegativePrompt");
|
|
const videoNegativePromptWidget = advancedFeatureNode.widgets.find(w => w.name === "videoNegativePrompt");
|
|
if (useVideoNegativePromptWidget && videoNegativePromptWidget) {
|
|
toggleWidgetState(useVideoNegativePromptWidget, videoNegativePromptWidget, "videoNegativePrompt");
|
|
}
|
|
|
|
const useAudioNegativePromptWidget = advancedFeatureNode.widgets.find(w => w.name === "useAudioNegativePrompt");
|
|
const audioNegativePromptWidget = advancedFeatureNode.widgets.find(w => w.name === "audioNegativePrompt");
|
|
if (useAudioNegativePromptWidget && audioNegativePromptWidget) {
|
|
toggleWidgetState(useAudioNegativePromptWidget, audioNegativePromptWidget, "audioNegativePrompt");
|
|
}
|
|
|
|
const useSlgLayerWidget = advancedFeatureNode.widgets.find(w => w.name === "useSlgLayer");
|
|
const slgLayerWidget = advancedFeatureNode.widgets.find(w => w.name === "slgLayer");
|
|
if (useSlgLayerWidget && slgLayerWidget) {
|
|
toggleWidgetState(useSlgLayerWidget, slgLayerWidget, "slgLayer");
|
|
}
|
|
}
|
|
|
|
function imageInferenceAdvancedFeaturesToggleHandler(advancedFeaturesNode) {
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
if (!paramWidget.inputEl && paramName) {
|
|
const nodeElement = advancedFeaturesNode.htmlElements?.widgetsContainer || advancedFeaturesNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
}
|
|
}
|
|
}
|
|
advancedFeaturesNode.setDirtyCanvas(true);
|
|
}
|
|
appendWidgetCB(useWidget, () => setTimeout(toggleEnabled, 50));
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
const useLayerDiffuseWidget = advancedFeaturesNode.widgets.find(w => w.name === "useLayerDiffuse");
|
|
const layerDiffuseWidget = advancedFeaturesNode.widgets.find(w => w.name === "layerDiffuse");
|
|
if (useLayerDiffuseWidget && layerDiffuseWidget) toggleWidgetState(useLayerDiffuseWidget, layerDiffuseWidget, "layerDiffuse");
|
|
const useHiresFixWidget = advancedFeaturesNode.widgets.find(w => w.name === "useHiresFix");
|
|
const hiresFixWidget = advancedFeaturesNode.widgets.find(w => w.name === "hiresFix");
|
|
if (useHiresFixWidget && hiresFixWidget) toggleWidgetState(useHiresFixWidget, hiresFixWidget, "hiresFix");
|
|
}
|
|
|
|
function watermarkAdvancedFeatureToggleHandler(watermarkNode) {
|
|
if (!watermarkNode?.widgets) return;
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl && paramName) {
|
|
const nodeElement = watermarkNode.htmlElements?.widgetsContainer || watermarkNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
|
|
watermarkNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
const pairs = [
|
|
["useText", "text"],
|
|
["useImage", "image"],
|
|
["useDisplayPosition", "displayPosition"],
|
|
["useTiled", "tiled"],
|
|
["useOpacity", "opacity"],
|
|
["useFontColor", "fontColor"],
|
|
["useBgColor", "bgColor"],
|
|
];
|
|
|
|
for (const [useName, paramName] of pairs) {
|
|
const useWidget = watermarkNode.widgets.find(w => w.name === useName);
|
|
const paramWidget = watermarkNode.widgets.find(w => w.name === paramName);
|
|
if (useWidget && paramWidget) {
|
|
toggleWidgetState(useWidget, paramWidget, paramName);
|
|
}
|
|
}
|
|
}
|
|
|
|
function videoInferenceSpeechInputToggleHandler(speechInputNode) {
|
|
if (!speechInputNode?.widgets) return;
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl && paramName) {
|
|
const nodeElement = speechInputNode.htmlElements?.widgetsContainer || speechInputNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
|
|
speechInputNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
const pairs = [
|
|
["useVoice", "voice"],
|
|
["useText", "text"],
|
|
["useSpeed", "speed"],
|
|
["usePitch", "pitch"],
|
|
["useLanguage", "language"],
|
|
];
|
|
|
|
for (const [useName, paramName] of pairs) {
|
|
const useWidget = speechInputNode.widgets.find(w => w.name === useName);
|
|
const paramWidget = speechInputNode.widgets.find(w => w.name === paramName);
|
|
if (useWidget && paramWidget) {
|
|
toggleWidgetState(useWidget, paramWidget, paramName);
|
|
}
|
|
}
|
|
}
|
|
|
|
function regionalPromptingRegionsToggleHandler(regionsNode) {
|
|
if (!regionsNode?.widgets) return;
|
|
|
|
function toggleWidgetState(useWidget, paramWidgets, paramNames) {
|
|
if (!useWidget || !paramWidgets || paramWidgets.length === 0) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
for (let i = 0; i < paramWidgets.length; i++) {
|
|
const paramWidget = paramWidgets[i];
|
|
const paramName = paramNames[i];
|
|
|
|
if (!paramWidget) continue;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl && paramName) {
|
|
const nodeElement = regionsNode.htmlElements?.widgetsContainer || regionsNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
regionsNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
for (let idx = 1; idx <= 4; idx++) {
|
|
const useWidget = regionsNode.widgets.find(w => w.name === `useRegion${idx}`);
|
|
const promptWidget = regionsNode.widgets.find(w => w.name === `region${idx}Prompt`);
|
|
const x0Widget = regionsNode.widgets.find(w => w.name === `region${idx}_x0`);
|
|
const y0Widget = regionsNode.widgets.find(w => w.name === `region${idx}_y0`);
|
|
const x1Widget = regionsNode.widgets.find(w => w.name === `region${idx}_x1`);
|
|
const y1Widget = regionsNode.widgets.find(w => w.name === `region${idx}_y1`);
|
|
|
|
const paramWidgets = [promptWidget, x0Widget, y0Widget, x1Widget, y1Widget];
|
|
const paramNames = [
|
|
`region${idx}Prompt`,
|
|
`region${idx}_x0`,
|
|
`region${idx}_y0`,
|
|
`region${idx}_x1`,
|
|
`region${idx}_y1`,
|
|
];
|
|
|
|
if (useWidget) {
|
|
toggleWidgetState(useWidget, paramWidgets, paramNames);
|
|
}
|
|
}
|
|
}
|
|
|
|
function audioInferenceReferenceVoiceToggleHandler(referenceVoiceNode) {
|
|
if (!referenceVoiceNode?.widgets) return;
|
|
if (referenceVoiceNode._audioInferenceReferenceVoiceToggleHandlerRegistered) return;
|
|
referenceVoiceNode._audioInferenceReferenceVoiceToggleHandlerRegistered = true;
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function applyState() {
|
|
const enabled = useWidget.value === true;
|
|
toggleWidgetEnabled(paramWidget, enabled, referenceVoiceNode);
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
referenceVoiceNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => setTimeout(applyState, 50));
|
|
setTimeout(applyState, 100);
|
|
}
|
|
|
|
for (let i = 1; i <= 4; i++) {
|
|
const useReferenceVoiceWidget = referenceVoiceNode.widgets.find((w) => w && w.name === `useReferenceVoice${i}`);
|
|
const audioWidget = referenceVoiceNode.widgets.find((w) => w && w.name === `audio${i}`);
|
|
const textWidget = referenceVoiceNode.widgets.find((w) => w && w.name === `text${i}`);
|
|
|
|
if (useReferenceVoiceWidget && audioWidget) {
|
|
toggleWidgetState(useReferenceVoiceWidget, audioWidget, `audio${i}`);
|
|
}
|
|
if (useReferenceVoiceWidget && textWidget) {
|
|
toggleWidgetState(useReferenceVoiceWidget, textWidget, `text${i}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
function audioInferenceInputsToggleHandler(audioInputsNode) {
|
|
if (!audioInputsNode?.widgets) return;
|
|
|
|
// Find widgets
|
|
const useAudioWidget = audioInputsNode.widgets.find(w => w && w.name === "useAudio");
|
|
const audioWidget = audioInputsNode.widgets.find(w => w && w.name === "Audio");
|
|
const useVideoWidget = audioInputsNode.widgets.find(w => w && w.name === "useVideo");
|
|
const videoWidget = audioInputsNode.widgets.find(w => w && w.name === "Video");
|
|
const useVideosWidget = audioInputsNode.widgets.find(w => w && w.name === "useVideos");
|
|
const useAudiosWidget = audioInputsNode.widgets.find(w => w && w.name === "useAudios");
|
|
const useReferenceAudiosWidget = audioInputsNode.widgets.find(w => w && w.name === "useReferenceAudios");
|
|
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM if inputEl is not available
|
|
if (!paramWidget.inputEl && paramName) {
|
|
const nodeElement = audioInputsNode.htmlElements?.widgetsContainer || audioInputsNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
|
|
audioInputsNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handler for single audio
|
|
if (useAudioWidget && audioWidget) {
|
|
toggleWidgetState(useAudioWidget, audioWidget, "Audio");
|
|
}
|
|
|
|
// Set up toggle handler for single video
|
|
if (useVideoWidget && videoWidget) {
|
|
toggleWidgetState(useVideoWidget, videoWidget, "Video");
|
|
}
|
|
|
|
// Set up toggle handlers for multiple audios (Audio1 … AudioN; N from widgets, fallback to AUDIO_INFERENCE_INPUTS_MAX_AUDIOS)
|
|
if (useAudiosWidget) {
|
|
function getAudioInferenceAudioSlotCount() {
|
|
let max = 0;
|
|
for (const w of audioInputsNode.widgets) {
|
|
if (!w?.name) continue;
|
|
const m = /^Audio(\d+)$/.exec(w.name);
|
|
if (m) max = Math.max(max, parseInt(m[1], 10));
|
|
}
|
|
return max > 0 ? max : AUDIO_INFERENCE_INPUTS_MAX_AUDIOS;
|
|
}
|
|
|
|
function toggleAudiosEnabled() {
|
|
const enabled = useAudiosWidget.value === true;
|
|
const slotCount = getAudioInferenceAudioSlotCount();
|
|
|
|
for (let i = 1; i <= slotCount; i++) {
|
|
const audioSlotWidget = audioInputsNode.widgets.find(w => w && w.name === `Audio${i}`);
|
|
if (audioSlotWidget) {
|
|
if (audioSlotWidget.inputEl) {
|
|
audioSlotWidget.inputEl.disabled = !enabled;
|
|
audioSlotWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
audioSlotWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
audioSlotWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
audioSlotWidget.disabled = !enabled;
|
|
|
|
if (!audioSlotWidget.inputEl) {
|
|
const nodeElement = audioInputsNode.htmlElements?.widgetsContainer || audioInputsNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="Audio${i}"], textarea[name="Audio${i}"], select[name="Audio${i}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
audioInputsNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useAudiosWidget, () => {
|
|
setTimeout(toggleAudiosEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleAudiosEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handlers for multiple videos (Video1 … VideoN; N from widgets, fallback to AUDIO_INFERENCE_INPUTS_MAX_VIDEOS)
|
|
if (useVideosWidget) {
|
|
function getAudioInferenceVideoSlotCount() {
|
|
let max = 0;
|
|
for (const w of audioInputsNode.widgets) {
|
|
if (!w?.name) continue;
|
|
const m = /^Video(\d+)$/.exec(w.name);
|
|
if (m) max = Math.max(max, parseInt(m[1], 10));
|
|
}
|
|
return max > 0 ? max : AUDIO_INFERENCE_INPUTS_MAX_VIDEOS;
|
|
}
|
|
|
|
function toggleVideosEnabled() {
|
|
const enabled = useVideosWidget.value === true;
|
|
const slotCount = getAudioInferenceVideoSlotCount();
|
|
|
|
for (let i = 1; i <= slotCount; i++) {
|
|
const videoWidget = audioInputsNode.widgets.find(w => w && w.name === `Video${i}`);
|
|
if (videoWidget) {
|
|
if (videoWidget.inputEl) {
|
|
videoWidget.inputEl.disabled = !enabled;
|
|
videoWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
videoWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
videoWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
videoWidget.disabled = !enabled;
|
|
|
|
// Fallback: try to find inputs via DOM
|
|
if (!videoWidget.inputEl) {
|
|
const nodeElement = audioInputsNode.htmlElements?.widgetsContainer || audioInputsNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="Video${i}"], textarea[name="Video${i}"], select[name="Video${i}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
audioInputsNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
// Set up callback
|
|
appendWidgetCB(useVideosWidget, () => {
|
|
setTimeout(toggleVideosEnabled, 50);
|
|
});
|
|
|
|
// Initial call to set initial state
|
|
setTimeout(toggleVideosEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handlers for reference audios (Reference Audio 1 … N; N from widgets, fallback to 4)
|
|
if (useReferenceAudiosWidget) {
|
|
function getAudioInferenceReferenceAudioSlotCount() {
|
|
let max = 0;
|
|
for (const w of audioInputsNode.widgets) {
|
|
if (!w?.name) continue;
|
|
const m = /^Reference Audio (\d+)$/.exec(w.name);
|
|
if (m) max = Math.max(max, parseInt(m[1], 10));
|
|
}
|
|
return max > 0 ? max : 4;
|
|
}
|
|
|
|
function toggleReferenceAudiosEnabled() {
|
|
const enabled = useReferenceAudiosWidget.value === true;
|
|
const slotCount = getAudioInferenceReferenceAudioSlotCount();
|
|
|
|
for (let i = 1; i <= slotCount; i++) {
|
|
const refAudioWidget = audioInputsNode.widgets.find(w => w && w.name === `Reference Audio ${i}`);
|
|
if (refAudioWidget) {
|
|
if (refAudioWidget.inputEl) {
|
|
refAudioWidget.inputEl.disabled = !enabled;
|
|
refAudioWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
refAudioWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
refAudioWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
refAudioWidget.disabled = !enabled;
|
|
|
|
if (!refAudioWidget.inputEl) {
|
|
const nodeElement = audioInputsNode.htmlElements?.widgetsContainer || audioInputsNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="Reference Audio ${i}"], textarea[name="Reference Audio ${i}"], select[name="Reference Audio ${i}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
audioInputsNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useReferenceAudiosWidget, () => {
|
|
setTimeout(toggleReferenceAudiosEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleReferenceAudiosEnabled, 100);
|
|
}
|
|
}
|
|
|
|
function audioInferenceSpeechVoicesToggleHandler(voicesNode) {
|
|
if (!voicesNode?.widgets) return;
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = voicesNode.htmlElements?.widgetsContainer || voicesNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
voicesNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
for (let i = 1; i <= 4; i++) {
|
|
const useVoiceWidget = voicesNode.widgets.find((w) => w && w.name === `useVoice${i}`);
|
|
const speakerWidget = voicesNode.widgets.find((w) => w && w.name === `speaker${i}`);
|
|
const voiceWidget = voicesNode.widgets.find((w) => w && w.name === `voice${i}`);
|
|
|
|
if (useVoiceWidget && speakerWidget) {
|
|
toggleWidgetState(useVoiceWidget, speakerWidget, `speaker${i}`);
|
|
}
|
|
if (useVoiceWidget && voiceWidget) {
|
|
toggleWidgetState(useVoiceWidget, voiceWidget, `voice${i}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
function videoInputsFrameToggleHandler(frameImagesNode) {
|
|
if (!frameImagesNode?.widgets) return;
|
|
if (frameImagesNode._videoInputsFrameToggleHandlerRegistered) return;
|
|
frameImagesNode._videoInputsFrameToggleHandlerRegistered = true;
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
// FLOAT timestamp widgets: avoid '' on disabled slots (ComfyUI validation error)
|
|
if (!enabled && paramName && paramName.startsWith("timestamp")) {
|
|
if (paramWidget.value === "" || paramWidget.value == null) {
|
|
paramWidget.value = 0.0;
|
|
}
|
|
}
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl && paramName) {
|
|
const nodeElement = frameImagesNode.htmlElements?.widgetsContainer || frameImagesNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
frameImagesNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
function initializeHandler() {
|
|
if (!frameImagesNode.widgets || frameImagesNode.widgets.length === 0) {
|
|
setTimeout(initializeHandler, 100);
|
|
return;
|
|
}
|
|
|
|
for (let i = 1; i <= 4; i++) {
|
|
const useFrameWidget = frameImagesNode.widgets.find((w) => w && w.name === `useFrame${i}`);
|
|
const frameWidget = frameImagesNode.widgets.find((w) => w && w.name === `frame${i} position`);
|
|
const useTimestampWidget = frameImagesNode.widgets.find((w) => w && w.name === `useTimestamp${i}`);
|
|
const timestampWidget = frameImagesNode.widgets.find((w) => w && w.name === `timestamp${i}`);
|
|
|
|
if (useFrameWidget && frameWidget) {
|
|
toggleWidgetState(useFrameWidget, frameWidget, `frame${i} position`);
|
|
}
|
|
if (useTimestampWidget && timestampWidget) {
|
|
toggleWidgetState(useTimestampWidget, timestampWidget, `timestamp${i}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
initializeHandler();
|
|
}
|
|
|
|
function referenceVideosToggleHandler(referenceVideosNode) {
|
|
if (!referenceVideosNode?.widgets) return;
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
if (paramWidget.options && paramWidget.options.element) {
|
|
paramWidget.options.element.disabled = !enabled;
|
|
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl && paramName) {
|
|
const nodeElement = referenceVideosNode.htmlElements?.widgetsContainer || referenceVideosNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
referenceVideosNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
for (let i = 1; i <= 4; i++) {
|
|
const useVideoWidget = referenceVideosNode.widgets.find((w) => w && w.name === `useVideo${i}`);
|
|
const videoWidget = referenceVideosNode.widgets.find((w) => w && w.name === `Video${i}`);
|
|
const tagWidget = referenceVideosNode.widgets.find((w) => w && w.name === `Tag${i}`);
|
|
const typeWidget = referenceVideosNode.widgets.find((w) => w && w.name === `Type${i}`);
|
|
|
|
if (useVideoWidget && videoWidget) {
|
|
toggleWidgetState(useVideoWidget, videoWidget, `Video${i}`);
|
|
}
|
|
if (useVideoWidget && tagWidget) {
|
|
toggleWidgetState(useVideoWidget, tagWidget, `Tag${i}`);
|
|
}
|
|
if (useVideoWidget && typeWidget) {
|
|
toggleWidgetState(useVideoWidget, typeWidget, `Type${i}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
export {
|
|
notifyUser,
|
|
promptEnhanceHandler,
|
|
syncDimensionsNodeHandler,
|
|
searchNodeHandler,
|
|
mediaUUIDHandler,
|
|
save3DFilepathHandler,
|
|
captionNodeHandler,
|
|
saveTextHandler,
|
|
videoTranscriptionHandler,
|
|
videoOutputsHandler,
|
|
handleCustomErrors,
|
|
APIKeyHandler,
|
|
videoInferenceDimensionsHandler,
|
|
videoModelSearchFilterHandler,
|
|
threeDModelSearchFilterHandler,
|
|
audioModelSearchFilterHandler,
|
|
textModelSearchFilterHandler,
|
|
vectorizeModelSearchFilterHandler,
|
|
vectorizeToggleHandler,
|
|
useParameterToggleHandler,
|
|
imageInferenceToggleHandler,
|
|
imageInferenceAdvancedFeaturesToggleHandler,
|
|
watermarkAdvancedFeatureToggleHandler,
|
|
videoInferenceSpeechInputToggleHandler,
|
|
regionalPromptingRegionsToggleHandler,
|
|
upscalerToggleHandler,
|
|
imageUpscalerSettingsToggleHandler,
|
|
videoUpscalerToggleHandler,
|
|
audioInferenceToggleHandler,
|
|
audioInferenceSpeechToggleHandler,
|
|
audioSettingsToggleHandler,
|
|
textInferenceSettingsToggleHandler,
|
|
videoSettingsToggleHandler,
|
|
videoInferenceSettingsTtsToggleHandler,
|
|
videoInferenceSettingsActiveSpeakerDetectionToggleHandler,
|
|
videoInferenceSettingsActiveSpeakerBoundingBoxesToggleHandler,
|
|
videoInferenceSettingsSegmentsToggleHandler,
|
|
videoInferenceSettingsControlToggleHandler,
|
|
acceleratorOptionsToggleHandler,
|
|
bytedanceProviderSettingsToggleHandler,
|
|
xaiProviderSettingsToggleHandler,
|
|
viduProviderSettingsToggleHandler,
|
|
sourcefulProviderSettingsToggleHandler,
|
|
sourcefulProviderSettingsFontsToggleHandler,
|
|
threeDInferenceToggleHandler,
|
|
threeDInferenceSettingsToggleHandler,
|
|
threeDInferenceSettingsLatToggleHandler,
|
|
threeDInferenceSettingsMeshClusterToggleHandler,
|
|
threeDInferenceSettingsDracoCompressionToggleHandler,
|
|
ultralyticsProviderSettingsToggleHandler,
|
|
openaiProviderSettingsToggleHandler,
|
|
lightricksProviderSettingsToggleHandler,
|
|
klingProviderSettingsToggleHandler,
|
|
lumaProviderSettingsToggleHandler,
|
|
briaProviderSettingsToggleHandler,
|
|
pixverseProviderSettingsToggleHandler,
|
|
alibabaProviderSettingsToggleHandler,
|
|
mireloProviderSettingsToggleHandler,
|
|
googleProviderSettingsToggleHandler,
|
|
syncProviderSettingsToggleHandler,
|
|
syncSegmentToggleHandler,
|
|
settingsToggleHandler,
|
|
outpaintSettingsToggleHandler,
|
|
safetyInputsToggleHandler,
|
|
imageInferenceSettingsColorPaletteToggleHandler,
|
|
imageInferenceSettingsMoodboardsToggleHandler,
|
|
imageInferenceSettingsStructuredPromptToggleHandler,
|
|
imageInferenceSettingsPromptEnhanceToggleHandler,
|
|
imageInferenceSettingsScoringRubricToggleHandler,
|
|
audioInputToggleHandler,
|
|
speechInputToggleHandler,
|
|
briaProviderMaskToggleHandler,
|
|
wanAnimateAdvancedFeatureSettingsToggleHandler,
|
|
videoAdvancedFeatureInputsToggleHandler,
|
|
audioInferenceInputsToggleHandler,
|
|
audioInferenceReferenceVoiceToggleHandler,
|
|
audioInferenceSpeechVoicesToggleHandler,
|
|
videoInputsFrameToggleHandler,
|
|
referenceVideosToggleHandler,
|
|
};
|
|
|
|
function googleProviderSettingsToggleHandler(googleNode) {
|
|
// Find all "use" parameter widgets for Google Provider Settings
|
|
const useGenerateAudioWidget = googleNode.widgets.find(w => w && w.name === "useGenerateAudio");
|
|
const generateAudioWidget = googleNode.widgets.find(w => w && w.name === "generateAudio");
|
|
const useEnhancePromptWidget = googleNode.widgets.find(w => w && w.name === "useEnhancePrompt");
|
|
const enhancePromptWidget = googleNode.widgets.find(w => w && w.name === "enhancePrompt");
|
|
const useSearchWidget = googleNode.widgets.find(w => w && w.name === "useSearch");
|
|
const searchWidget = googleNode.widgets.find(w => w && w.name === "search");
|
|
const useResizeModeWidget = googleNode.widgets.find(w => w && w.name === "useResizeMode");
|
|
const resizeModeWidget = googleNode.widgets.find(w => w && w.name === "resizeMode");
|
|
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = googleNode.htmlElements?.widgetsContainer || googleNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
googleNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handlers
|
|
if (useGenerateAudioWidget && generateAudioWidget) {
|
|
toggleWidgetState(useGenerateAudioWidget, generateAudioWidget, "generateAudio");
|
|
}
|
|
if (useEnhancePromptWidget && enhancePromptWidget) {
|
|
toggleWidgetState(useEnhancePromptWidget, enhancePromptWidget, "enhancePrompt");
|
|
}
|
|
if (useSearchWidget && searchWidget) {
|
|
toggleWidgetState(useSearchWidget, searchWidget, "search");
|
|
}
|
|
if (useResizeModeWidget && resizeModeWidget) {
|
|
toggleWidgetState(useResizeModeWidget, resizeModeWidget, "resizeMode");
|
|
}
|
|
}
|
|
|
|
function settingsToggleHandler(settingsNode) {
|
|
// Find all "use" parameter widgets for Settings
|
|
const useTemperatureWidget = settingsNode.widgets.find(w => w.name === "useTemperature");
|
|
const temperatureWidget = settingsNode.widgets.find(w => w.name === "temperature");
|
|
const useSystemPromptWidget = settingsNode.widgets.find(w => w.name === "useSystemPrompt");
|
|
const systemPromptWidget = settingsNode.widgets.find(w => w.name === "systemPrompt");
|
|
const useTopPWidget = settingsNode.widgets.find(w => w.name === "useTopP");
|
|
const topPWidget = settingsNode.widgets.find(w => w.name === "topP");
|
|
const useLayersWidget = settingsNode.widgets.find(w => w.name === "useLayers");
|
|
const layersWidget = settingsNode.widgets.find(w => w.name === "layers");
|
|
const useTrueCFGScaleWidget = settingsNode.widgets.find(w => w.name === "useTrueCFGScale");
|
|
const trueCFGScaleWidget = settingsNode.widgets.find(w => w.name === "trueCFGScale");
|
|
const useQualityWidget = settingsNode.widgets.find(w => w.name === "useQuality");
|
|
const qualityWidget = settingsNode.widgets.find(w => w.name === "quality");
|
|
const useBackgroundWidget = settingsNode.widgets.find(w => w.name === "useBackground");
|
|
const backgroundWidget = settingsNode.widgets.find(w => w.name === "background");
|
|
const useStyleWidget = settingsNode.widgets.find(w => w.name === "useStyle");
|
|
const styleWidget = settingsNode.widgets.find(w => w.name === "style");
|
|
const useSearchWidget = settingsNode.widgets.find(w => w.name === "useSearch");
|
|
const searchWidget = settingsNode.widgets.find(w => w.name === "search");
|
|
const usePromptExtendWidget = settingsNode.widgets.find(w => w.name === "usePromptExtend");
|
|
const promptExtendWidget = settingsNode.widgets.find(w => w.name === "promptExtend");
|
|
const useEditRegionsWidget = settingsNode.widgets.find(w => w.name === "useEditRegions");
|
|
const editRegionsWidget = settingsNode.widgets.find(w => w.name === "editRegions");
|
|
const useThinkingWidget = settingsNode.widgets.find(w => w.name === "useThinking");
|
|
const thinkingWidget = settingsNode.widgets.find(w => w.name === "thinking");
|
|
const useThinkingLevelWidget = settingsNode.widgets.find(w => w.name === "useThinkingLevel");
|
|
const thinkingLevelWidget = settingsNode.widgets.find(w => w.name === "thinkingLevel");
|
|
const useSequentialWidget = settingsNode.widgets.find(w => w.name === "useSequential");
|
|
const sequentialWidget = settingsNode.widgets.find(w => w.name === "sequential");
|
|
const useRenderingSpeedWidget = settingsNode.widgets.find(w => w.name === "useRenderingSpeed");
|
|
const renderingSpeedWidget = settingsNode.widgets.find(w => w.name === "renderingSpeed");
|
|
const useMagicPromptWidget = settingsNode.widgets.find(w => w.name === "useMagicPrompt");
|
|
const magicPromptWidget = settingsNode.widgets.find(w => w.name === "magicPrompt");
|
|
const useAutoCropWidget = settingsNode.widgets.find(w => w.name === "useAutoCrop");
|
|
const autoCropWidget = settingsNode.widgets.find(w => w.name === "autoCrop");
|
|
const useDilatePixelsWidget = settingsNode.widgets.find(w => w.name === "useDilatePixels");
|
|
const dilatePixelsWidget = settingsNode.widgets.find(w => w.name === "dilatePixels");
|
|
const useCreativityWidget = settingsNode.widgets.find(w => w.name === "useCreativity");
|
|
const creativityWidget = settingsNode.widgets.find(w => w.name === "creativity");
|
|
const useBackgroundModeWidget = settingsNode.widgets.find(w => w.name === "useBackgroundMode");
|
|
const backgroundModeWidget = settingsNode.widgets.find(w => w.name === "backgroundMode");
|
|
const useBackgroundColorWidget = settingsNode.widgets.find(w => w.name === "useBackgroundColor");
|
|
const backgroundColorWidget = settingsNode.widgets.find(w => w.name === "backgroundColor");
|
|
const useEnhancePromptWidget = settingsNode.widgets.find(w => w.name === "useEnhancePrompt");
|
|
const enhancePromptWidget = settingsNode.widgets.find(w => w.name === "enhancePrompt");
|
|
const useScoringPromptWidget = settingsNode.widgets.find(w => w.name === "useScoringPrompt");
|
|
const scoringPromptWidget = settingsNode.widgets.find(w => w.name === "scoringPrompt");
|
|
const useCopyrightDetectionWidget = settingsNode.widgets.find(w => w.name === "useCopyrightDetection");
|
|
const copyrightDetectionWidget = settingsNode.widgets.find(w => w.name === "copyrightDetection");
|
|
const usePreserveInputSizeWidget = settingsNode.widgets.find(w => w.name === "usePreserveInputSize");
|
|
const preserveInputSizeWidget = settingsNode.widgets.find(w => w.name === "preserveInputSize");
|
|
const useTurboWidget = settingsNode.widgets.find(w => w.name === "useTurbo");
|
|
const turboWidget = settingsNode.widgets.find(w => w.name === "turbo");
|
|
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = settingsNode.htmlElements?.widgetsContainer || settingsNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
settingsNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handlers
|
|
if (useTemperatureWidget && temperatureWidget) {
|
|
toggleWidgetState(useTemperatureWidget, temperatureWidget, "temperature");
|
|
}
|
|
if (useSystemPromptWidget && systemPromptWidget) {
|
|
toggleWidgetState(useSystemPromptWidget, systemPromptWidget, "systemPrompt");
|
|
}
|
|
if (useTopPWidget && topPWidget) {
|
|
toggleWidgetState(useTopPWidget, topPWidget, "topP");
|
|
}
|
|
if (useLayersWidget && layersWidget) {
|
|
toggleWidgetState(useLayersWidget, layersWidget, "layers");
|
|
}
|
|
if (useTrueCFGScaleWidget && trueCFGScaleWidget) {
|
|
toggleWidgetState(useTrueCFGScaleWidget, trueCFGScaleWidget, "trueCFGScale");
|
|
}
|
|
if (useQualityWidget && qualityWidget) {
|
|
toggleWidgetState(useQualityWidget, qualityWidget, "quality");
|
|
}
|
|
if (useBackgroundWidget && backgroundWidget) {
|
|
toggleWidgetState(useBackgroundWidget, backgroundWidget, "background");
|
|
}
|
|
if (useStyleWidget && styleWidget) {
|
|
toggleWidgetState(useStyleWidget, styleWidget, "style");
|
|
}
|
|
if (useSearchWidget && searchWidget) {
|
|
toggleWidgetState(useSearchWidget, searchWidget, "search");
|
|
}
|
|
if (usePromptExtendWidget && promptExtendWidget) {
|
|
toggleWidgetState(usePromptExtendWidget, promptExtendWidget, "promptExtend");
|
|
}
|
|
if (useEditRegionsWidget && editRegionsWidget) {
|
|
toggleWidgetState(useEditRegionsWidget, editRegionsWidget, "editRegions");
|
|
}
|
|
if (useThinkingWidget && thinkingWidget) {
|
|
toggleWidgetState(useThinkingWidget, thinkingWidget, "thinking");
|
|
}
|
|
if (useThinkingLevelWidget && thinkingLevelWidget) {
|
|
toggleWidgetState(useThinkingLevelWidget, thinkingLevelWidget, "thinkingLevel");
|
|
}
|
|
if (useSequentialWidget && sequentialWidget) {
|
|
toggleWidgetState(useSequentialWidget, sequentialWidget, "sequential");
|
|
}
|
|
if (useRenderingSpeedWidget && renderingSpeedWidget) {
|
|
toggleWidgetState(useRenderingSpeedWidget, renderingSpeedWidget, "renderingSpeed");
|
|
}
|
|
if (useMagicPromptWidget && magicPromptWidget) {
|
|
toggleWidgetState(useMagicPromptWidget, magicPromptWidget, "magicPrompt");
|
|
}
|
|
if (useAutoCropWidget && autoCropWidget) {
|
|
toggleWidgetState(useAutoCropWidget, autoCropWidget, "autoCrop");
|
|
}
|
|
if (useDilatePixelsWidget && dilatePixelsWidget) {
|
|
toggleWidgetState(useDilatePixelsWidget, dilatePixelsWidget, "dilatePixels");
|
|
}
|
|
if (useCreativityWidget && creativityWidget) {
|
|
toggleWidgetState(useCreativityWidget, creativityWidget, "creativity");
|
|
}
|
|
if (useBackgroundModeWidget && backgroundModeWidget) {
|
|
toggleWidgetState(useBackgroundModeWidget, backgroundModeWidget, "backgroundMode");
|
|
}
|
|
if (useBackgroundColorWidget && backgroundColorWidget) {
|
|
toggleWidgetState(useBackgroundColorWidget, backgroundColorWidget, "backgroundColor");
|
|
}
|
|
if (useEnhancePromptWidget && enhancePromptWidget) {
|
|
toggleWidgetState(useEnhancePromptWidget, enhancePromptWidget, "enhancePrompt");
|
|
}
|
|
if (useScoringPromptWidget && scoringPromptWidget) {
|
|
toggleWidgetState(useScoringPromptWidget, scoringPromptWidget, "scoringPrompt");
|
|
}
|
|
if (useCopyrightDetectionWidget && copyrightDetectionWidget) {
|
|
toggleWidgetState(useCopyrightDetectionWidget, copyrightDetectionWidget, "copyrightDetection");
|
|
}
|
|
if (usePreserveInputSizeWidget && preserveInputSizeWidget) {
|
|
toggleWidgetState(usePreserveInputSizeWidget, preserveInputSizeWidget, "preserveInputSize");
|
|
}
|
|
if (useTurboWidget && turboWidget) {
|
|
toggleWidgetState(useTurboWidget, turboWidget, "turbo");
|
|
}
|
|
}
|
|
|
|
function outpaintSettingsToggleHandler(settingsNode) {
|
|
if (!settingsNode?.widgets) return;
|
|
|
|
const useTopWidget = settingsNode.widgets.find(w => w && w.name === "useTop");
|
|
const topWidget = settingsNode.widgets.find(w => w && w.name === "Top");
|
|
const useRightWidget = settingsNode.widgets.find(w => w && w.name === "useRight");
|
|
const rightWidget = settingsNode.widgets.find(w => w && w.name === "Right");
|
|
const useBottomWidget = settingsNode.widgets.find(w => w && w.name === "useBottom");
|
|
const bottomWidget = settingsNode.widgets.find(w => w && w.name === "Bottom");
|
|
const useLeftWidget = settingsNode.widgets.find(w => w && w.name === "useLeft");
|
|
const leftWidget = settingsNode.widgets.find(w => w && w.name === "Left");
|
|
const useBlurWidget = settingsNode.widgets.find(w => w && w.name === "useBlur");
|
|
const blurWidget = settingsNode.widgets.find(w => w && w.name === "Blur");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = settingsNode.htmlElements?.widgetsContainer || settingsNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
settingsNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
if (useTopWidget && topWidget) toggleWidgetState(useTopWidget, topWidget, "Top");
|
|
if (useRightWidget && rightWidget) toggleWidgetState(useRightWidget, rightWidget, "Right");
|
|
if (useBottomWidget && bottomWidget) toggleWidgetState(useBottomWidget, bottomWidget, "Bottom");
|
|
if (useLeftWidget && leftWidget) toggleWidgetState(useLeftWidget, leftWidget, "Left");
|
|
if (useBlurWidget && blurWidget) toggleWidgetState(useBlurWidget, blurWidget, "Blur");
|
|
}
|
|
|
|
function safetyInputsToggleHandler(safetyNode) {
|
|
const useModeWidget = safetyNode.widgets.find(w => w.name === "useMode");
|
|
const modeWidget = safetyNode.widgets.find(w => w.name === "mode");
|
|
const useToleranceWidget = safetyNode.widgets.find(w => w.name === "useTolerance");
|
|
const toleranceWidget = safetyNode.widgets.find(w => w.name === "tolerance");
|
|
const useCheckInputsWidget = safetyNode.widgets.find(w => w.name === "useCheckInputs");
|
|
const checkInputsWidget = safetyNode.widgets.find(w => w.name === "checkInputs");
|
|
const useCheckContentWidget = safetyNode.widgets.find(w => w.name === "useCheckContent");
|
|
const checkContentWidget = safetyNode.widgets.find(w => w.name === "checkContent");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = safetyNode.htmlElements?.widgetsContainer || safetyNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
safetyNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
if (useModeWidget && modeWidget) {
|
|
toggleWidgetState(useModeWidget, modeWidget, "mode");
|
|
}
|
|
if (useToleranceWidget && toleranceWidget) {
|
|
toggleWidgetState(useToleranceWidget, toleranceWidget, "tolerance");
|
|
}
|
|
if (useCheckInputsWidget && checkInputsWidget) {
|
|
toggleWidgetState(useCheckInputsWidget, checkInputsWidget, "checkInputs");
|
|
}
|
|
if (useCheckContentWidget && checkContentWidget) {
|
|
toggleWidgetState(useCheckContentWidget, checkContentWidget, "checkContent");
|
|
}
|
|
}
|
|
|
|
function imageInferenceSettingsColorPaletteToggleHandler(paletteNode) {
|
|
function applyParamState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
const enabled = useWidget.value === true;
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = paletteNode.htmlElements?.widgetsContainer || paletteNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(
|
|
`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`
|
|
);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function bindSlot(i) {
|
|
const useW = paletteNode.widgets.find((w) => w.name === `use_${i}`);
|
|
const hexW = paletteNode.widgets.find((w) => w.name === `hex_${i}`);
|
|
const ratioW = paletteNode.widgets.find((w) => w.name === `ratio_${i}`);
|
|
if (!useW || !hexW || !ratioW) return;
|
|
|
|
function toggleSlot() {
|
|
applyParamState(useW, hexW, `hex_${i}`);
|
|
applyParamState(useW, ratioW, `ratio_${i}`);
|
|
paletteNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useW, () => {
|
|
setTimeout(toggleSlot, 50);
|
|
});
|
|
setTimeout(toggleSlot, 100);
|
|
}
|
|
|
|
for (let i = 1; i <= 8; i++) {
|
|
bindSlot(i);
|
|
}
|
|
}
|
|
|
|
function imageInferenceSettingsPromptEnhanceToggleHandler(node) {
|
|
if (!node?.widgets) return;
|
|
|
|
const useTemperatureWidget = node.widgets.find((w) => w && w.name === "useTemperature");
|
|
const temperatureWidget = node.widgets.find((w) => w && w.name === "temperature");
|
|
const useTopPWidget = node.widgets.find((w) => w && w.name === "useTopP");
|
|
const topPWidget = node.widgets.find((w) => w && w.name === "topP");
|
|
const useEnabledWidget = node.widgets.find((w) => w && w.name === "useEnabled");
|
|
const enabledWidget = node.widgets.find((w) => w && w.name === "enabled");
|
|
|
|
function toggleWidgetState(useWidget, paramWidget) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function toggleEnabled() {
|
|
toggleWidgetEnabled(paramWidget, useWidget.value === true, node);
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
appendWidgetCB(useWidget, () => setTimeout(toggleEnabled, 50));
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
if (useTemperatureWidget && temperatureWidget) {
|
|
toggleWidgetState(useTemperatureWidget, temperatureWidget);
|
|
}
|
|
if (useTopPWidget && topPWidget) {
|
|
toggleWidgetState(useTopPWidget, topPWidget);
|
|
}
|
|
if (useEnabledWidget && enabledWidget) {
|
|
toggleWidgetState(useEnabledWidget, enabledWidget);
|
|
}
|
|
}
|
|
|
|
function imageInferenceSettingsMoodboardsToggleHandler(moodboardsNode) {
|
|
if (!moodboardsNode?.widgets) return;
|
|
|
|
const useStrengthWidget = moodboardsNode.widgets.find((w) => w && w.name === "useStrength");
|
|
const strengthWidget = moodboardsNode.widgets.find((w) => w && w.name === "strength");
|
|
if (!useStrengthWidget || !strengthWidget) return;
|
|
|
|
function toggleStrengthState() {
|
|
const enabled = useStrengthWidget.value === true;
|
|
toggleWidgetEnabled(strengthWidget, enabled, moodboardsNode);
|
|
moodboardsNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useStrengthWidget, () => {
|
|
setTimeout(toggleStrengthState, 50);
|
|
});
|
|
setTimeout(toggleStrengthState, 100);
|
|
}
|
|
|
|
function imageInferenceSettingsScoringRubricToggleHandler(rubricNode) {
|
|
if (!rubricNode?.widgets) return;
|
|
if (rubricNode._imageInferenceSettingsScoringRubricToggleHandlerRegistered) return;
|
|
rubricNode._imageInferenceSettingsScoringRubricToggleHandlerRegistered = true;
|
|
|
|
function toggleWidgetState(useWidget, paramWidgets, paramNames) {
|
|
if (!useWidget) return;
|
|
const widgets = Array.isArray(paramWidgets) ? paramWidgets : [paramWidgets];
|
|
const names = Array.isArray(paramNames) ? paramNames : [paramNames];
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
widgets.forEach((paramWidget, index) => {
|
|
if (!paramWidget) return;
|
|
toggleWidgetEnabled(paramWidget, enabled, rubricNode);
|
|
const paramName = names[index];
|
|
if (!paramWidget.inputEl && paramName) {
|
|
const nodeElement = rubricNode.htmlElements?.widgetsContainer || rubricNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(
|
|
`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`
|
|
);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
rubricNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => setTimeout(toggleEnabled, 50));
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
const usePassingScoreWidget = rubricNode.widgets.find((w) => w && w.name === "usePassingScore");
|
|
const passingScoreWidget = rubricNode.widgets.find((w) => w && w.name === "passingScore");
|
|
if (usePassingScoreWidget && passingScoreWidget) {
|
|
toggleWidgetState(usePassingScoreWidget, passingScoreWidget, "passingScore");
|
|
}
|
|
|
|
for (let i = 1; i <= 5; i++) {
|
|
const useScoreGuidanceWidget = rubricNode.widgets.find((w) => w && w.name === `useScoreGuidance${i}`);
|
|
const scoreWidget = rubricNode.widgets.find((w) => w && w.name === `score${i}`);
|
|
const guidanceDescriptionWidget = rubricNode.widgets.find((w) => w && w.name === `guidanceDescription${i}`);
|
|
if (useScoreGuidanceWidget && (scoreWidget || guidanceDescriptionWidget)) {
|
|
toggleWidgetState(
|
|
useScoreGuidanceWidget,
|
|
[scoreWidget, guidanceDescriptionWidget].filter(Boolean),
|
|
[`score${i}`, `guidanceDescription${i}`]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
function imageInferenceSettingsStructuredPromptToggleHandler(node) {
|
|
if (!node?.widgets) return;
|
|
|
|
function applyParamState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
const enabled = useWidget.value === true;
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
paramWidget.disabled = !enabled;
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = node.htmlElements?.widgetsContainer || node.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(
|
|
`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`
|
|
);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
function toggleEnabled() {
|
|
applyParamState(useWidget, paramWidget, paramName);
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
appendWidgetCB(useWidget, () => setTimeout(toggleEnabled, 50));
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
const useStyleDescriptionWidget = node.widgets.find((w) => w && w.name === "useStyleDescription");
|
|
const styleDescriptionWidget = node.widgets.find((w) => w && w.name === "style_description");
|
|
if (useStyleDescriptionWidget && styleDescriptionWidget) {
|
|
toggleWidgetState(useStyleDescriptionWidget, styleDescriptionWidget, "style_description");
|
|
}
|
|
|
|
const useElementsJsonWidget = node.widgets.find((w) => w && w.name === "useElementsJson");
|
|
const elementsJsonWidget = node.widgets.find((w) => w && w.name === "elementsJson");
|
|
const elementSlotRefreshers = [];
|
|
if (useElementsJsonWidget && elementsJsonWidget) {
|
|
toggleWidgetState(useElementsJsonWidget, elementsJsonWidget, "elementsJson");
|
|
}
|
|
|
|
function bindElementSlot(i) {
|
|
const useW = node.widgets.find((w) => w && w.name === `use_element_${i}`);
|
|
const typeW = node.widgets.find((w) => w && w.name === `element_type_${i}`);
|
|
const descW = node.widgets.find((w) => w && w.name === `element_desc_${i}`);
|
|
const textW = node.widgets.find((w) => w && w.name === `element_text_${i}`);
|
|
const bboxW = node.widgets.find((w) => w && w.name === `element_bbox_${i}`);
|
|
const paletteW = node.widgets.find((w) => w && w.name === `element_color_palette_${i}`);
|
|
if (!useW) return;
|
|
|
|
function toggleSlot() {
|
|
const jsonMode = useElementsJsonWidget?.value === true;
|
|
toggleWidgetEnabled(useW, !jsonMode, node);
|
|
const enabled = !jsonMode && useW.value === true;
|
|
[typeW, descW, textW, bboxW, paletteW].forEach((w) => {
|
|
if (w) toggleWidgetEnabled(w, enabled, node);
|
|
});
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
|
|
elementSlotRefreshers.push(toggleSlot);
|
|
appendWidgetCB(useW, () => setTimeout(toggleSlot, 50));
|
|
setTimeout(toggleSlot, 100);
|
|
}
|
|
|
|
for (let i = 1; i <= 8; i++) {
|
|
bindElementSlot(i);
|
|
}
|
|
|
|
if (useElementsJsonWidget) {
|
|
function refreshElementSlotsForJsonMode() {
|
|
elementSlotRefreshers.forEach((refresh) => refresh());
|
|
node.setDirtyCanvas(true);
|
|
}
|
|
appendWidgetCB(useElementsJsonWidget, () => setTimeout(refreshElementSlotsForJsonMode, 50));
|
|
setTimeout(refreshElementSlotsForJsonMode, 100);
|
|
}
|
|
}
|
|
|
|
function syncProviderSettingsToggleHandler(syncNode) {
|
|
// Find all "use" parameter widgets for Sync Provider Settings
|
|
const useEditRegionWidget = syncNode.widgets.find(w => w.name === "useEditRegion");
|
|
const editRegionWidget = syncNode.widgets.find(w => w.name === "editRegion");
|
|
const useEmotionPromptWidget = syncNode.widgets.find(w => w.name === "useEmotionPrompt");
|
|
const emotionPromptWidget = syncNode.widgets.find(w => w.name === "emotionPrompt");
|
|
const useTemperatureWidget = syncNode.widgets.find(w => w.name === "useTemperature");
|
|
const temperatureWidget = syncNode.widgets.find(w => w.name === "temperature");
|
|
const useActiveSpeakerDetectionWidget = syncNode.widgets.find(w => w.name === "useActiveSpeakerDetection");
|
|
const activeSpeakerDetectionWidget = syncNode.widgets.find(w => w.name === "activeSpeakerDetection");
|
|
const useOcclusionDetectionEnabledWidget = syncNode.widgets.find(w => w.name === "useOcclusionDetectionEnabled");
|
|
const occlusionDetectionEnabledWidget = syncNode.widgets.find(w => w.name === "occlusionDetectionEnabled");
|
|
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = syncNode.htmlElements?.widgetsContainer || syncNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
syncNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handlers
|
|
if (useEditRegionWidget && editRegionWidget) {
|
|
toggleWidgetState(useEditRegionWidget, editRegionWidget, "editRegion");
|
|
}
|
|
if (useEmotionPromptWidget && emotionPromptWidget) {
|
|
toggleWidgetState(useEmotionPromptWidget, emotionPromptWidget, "emotionPrompt");
|
|
}
|
|
if (useTemperatureWidget && temperatureWidget) {
|
|
toggleWidgetState(useTemperatureWidget, temperatureWidget, "temperature");
|
|
}
|
|
if (useActiveSpeakerDetectionWidget && activeSpeakerDetectionWidget) {
|
|
toggleWidgetState(useActiveSpeakerDetectionWidget, activeSpeakerDetectionWidget, "activeSpeakerDetection");
|
|
}
|
|
if (useOcclusionDetectionEnabledWidget && occlusionDetectionEnabledWidget) {
|
|
toggleWidgetState(useOcclusionDetectionEnabledWidget, occlusionDetectionEnabledWidget, "occlusionDetectionEnabled");
|
|
}
|
|
}
|
|
|
|
function syncSegmentToggleHandler(syncSegmentNode) {
|
|
// Find all "use" parameter widgets for Sync Segment
|
|
const useAudioStartTimeWidget = syncSegmentNode.widgets.find(w => w.name === "useAudioStartTime");
|
|
const audioStartTimeWidget = syncSegmentNode.widgets.find(w => w.name === "audioStartTime");
|
|
const useAudioEndTimeWidget = syncSegmentNode.widgets.find(w => w.name === "useAudioEndTime");
|
|
const audioEndTimeWidget = syncSegmentNode.widgets.find(w => w.name === "audioEndTime");
|
|
|
|
// Helper function to toggle widget enabled state
|
|
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
|
if (!useWidget || !paramWidget) return;
|
|
|
|
function toggleEnabled() {
|
|
const enabled = useWidget.value === true;
|
|
|
|
if (paramWidget.inputEl) {
|
|
paramWidget.inputEl.disabled = !enabled;
|
|
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
|
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
|
paramWidget.inputEl.readOnly = !enabled;
|
|
}
|
|
|
|
paramWidget.disabled = !enabled;
|
|
|
|
if (!paramWidget.inputEl) {
|
|
const nodeElement = syncSegmentNode.htmlElements?.widgetsContainer || syncSegmentNode.htmlElements;
|
|
if (nodeElement) {
|
|
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
|
if (input) {
|
|
input.disabled = !enabled;
|
|
input.style.opacity = enabled ? "1" : "0.5";
|
|
input.style.cursor = enabled ? "text" : "not-allowed";
|
|
input.readOnly = !enabled;
|
|
if (input.tagName === "SELECT") {
|
|
input.style.pointerEvents = enabled ? "auto" : "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
syncSegmentNode.setDirtyCanvas(true);
|
|
}
|
|
|
|
appendWidgetCB(useWidget, () => {
|
|
setTimeout(toggleEnabled, 50);
|
|
});
|
|
|
|
setTimeout(toggleEnabled, 100);
|
|
}
|
|
|
|
// Set up toggle handlers
|
|
if (useAudioStartTimeWidget && audioStartTimeWidget) {
|
|
toggleWidgetState(useAudioStartTimeWidget, audioStartTimeWidget, "audioStartTime");
|
|
}
|
|
if (useAudioEndTimeWidget && audioEndTimeWidget) {
|
|
toggleWidgetState(useAudioEndTimeWidget, audioEndTimeWidget, "audioEndTime");
|
|
}
|
|
}
|