Use FLOAT for timestamp fields, handle invalid strings gracefully, update node description, and reset empty timestamp values in the UI when Use Timestamp is disabled.
5798 lines
270 KiB
JavaScript
5798 lines
270 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"],
|
|
// 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 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 (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 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) {
|
|
const useFont1Widget = fontsNode.widgets.find(w => w.name === "useFont1");
|
|
const fontUrl1Widget = fontsNode.widgets.find(w => w.name === "fontUrl1");
|
|
const text1Widget = fontsNode.widgets.find(w => w.name === "text1");
|
|
const useFont2Widget = fontsNode.widgets.find(w => w.name === "useFont2");
|
|
const fontUrl2Widget = fontsNode.widgets.find(w => w.name === "fontUrl2");
|
|
const text2Widget = fontsNode.widgets.find(w => w.name === "text2");
|
|
|
|
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);
|
|
}
|
|
|
|
if (useFont1Widget && fontUrl1Widget && text1Widget) {
|
|
toggleFontGroup(useFont1Widget, fontUrl1Widget, text1Widget, "fontUrl1", "text1");
|
|
}
|
|
if (useFont2Widget && fontUrl2Widget && text2Widget) {
|
|
toggleFontGroup(useFont2Widget, fontUrl2Widget, text2Widget, "fontUrl2", "text2");
|
|
}
|
|
}
|
|
|
|
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 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");
|
|
|
|
// 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");
|
|
}
|
|
}
|
|
|
|
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-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)",
|
|
],
|
|
"Veo": [
|
|
"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)",
|
|
],
|
|
"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)",
|
|
],
|
|
"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)",
|
|
],
|
|
"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)",
|
|
],
|
|
"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)",
|
|
],
|
|
"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 (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)",
|
|
],
|
|
"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-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},
|
|
"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},
|
|
"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},
|
|
"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},
|
|
"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},
|
|
"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": {"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},
|
|
"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-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",
|
|
"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",
|
|
"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",
|
|
"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",
|
|
"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",
|
|
"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": "480p",
|
|
"veed:fabric@1.0": "720p",
|
|
"prunaai:p-video@0": "720p",
|
|
"prunaai:p-video@avatar": "720p",
|
|
"prunaai:p-video@animate": "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 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)",
|
|
],
|
|
"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");
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
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,
|
|
audioModelSearchFilterHandler,
|
|
textModelSearchFilterHandler,
|
|
vectorizeModelSearchFilterHandler,
|
|
vectorizeToggleHandler,
|
|
useParameterToggleHandler,
|
|
imageInferenceToggleHandler,
|
|
imageInferenceAdvancedFeaturesToggleHandler,
|
|
watermarkAdvancedFeatureToggleHandler,
|
|
videoInferenceSpeechInputToggleHandler,
|
|
regionalPromptingRegionsToggleHandler,
|
|
upscalerToggleHandler,
|
|
imageUpscalerSettingsToggleHandler,
|
|
videoUpscalerToggleHandler,
|
|
audioInferenceToggleHandler,
|
|
audioInferenceSpeechToggleHandler,
|
|
audioSettingsToggleHandler,
|
|
textInferenceSettingsToggleHandler,
|
|
videoSettingsToggleHandler,
|
|
videoInferenceSettingsTtsToggleHandler,
|
|
videoInferenceSettingsActiveSpeakerDetectionToggleHandler,
|
|
videoInferenceSettingsActiveSpeakerBoundingBoxesToggleHandler,
|
|
videoInferenceSettingsSegmentsToggleHandler,
|
|
acceleratorOptionsToggleHandler,
|
|
bytedanceProviderSettingsToggleHandler,
|
|
xaiProviderSettingsToggleHandler,
|
|
viduProviderSettingsToggleHandler,
|
|
sourcefulProviderSettingsToggleHandler,
|
|
sourcefulProviderSettingsFontsToggleHandler,
|
|
threeDInferenceToggleHandler,
|
|
threeDInferenceSettingsToggleHandler,
|
|
threeDInferenceSettingsLatToggleHandler,
|
|
threeDInferenceSettingsMeshClusterToggleHandler,
|
|
ultralyticsProviderSettingsToggleHandler,
|
|
openaiProviderSettingsToggleHandler,
|
|
lightricksProviderSettingsToggleHandler,
|
|
klingProviderSettingsToggleHandler,
|
|
lumaProviderSettingsToggleHandler,
|
|
briaProviderSettingsToggleHandler,
|
|
pixverseProviderSettingsToggleHandler,
|
|
alibabaProviderSettingsToggleHandler,
|
|
mireloProviderSettingsToggleHandler,
|
|
googleProviderSettingsToggleHandler,
|
|
syncProviderSettingsToggleHandler,
|
|
syncSegmentToggleHandler,
|
|
settingsToggleHandler,
|
|
outpaintSettingsToggleHandler,
|
|
safetyInputsToggleHandler,
|
|
imageInferenceSettingsColorPaletteToggleHandler,
|
|
imageInferenceSettingsMoodboardsToggleHandler,
|
|
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");
|
|
|
|
// 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");
|
|
}
|
|
}
|
|
|
|
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 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 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");
|
|
}
|
|
}
|