Add resolution parameter support for video models

This commit is contained in:
Sirshendu Ganguly
2025-12-04 20:34:10 -05:00
parent 9e5d8e3d3d
commit 86914d0fee
9 changed files with 394 additions and 4 deletions
+2
View File
@@ -50,6 +50,7 @@ from .modules.providerSettings.klingProviderSettings import RunwareKlingProvider
from .modules.providerSettings.runwayProviderSettings import RunwareRunwayProviderSettings
from .modules.providerSettings.lumaProviderSettings import RunwareLumaProviderSettings
from .modules.providerSettings.midjourneyProviderSettings import RunwareMidjourneyProviderSettings
from .modules.providerSettings.alibabaProviderSettings import RunwareAlibabaProviderSettings
from .modules.vectorize import vectorize
from .modules.videoBgRemoval import videoBgRemoval
from .modules.videoUpscaler import videoUpscaler
@@ -121,6 +122,7 @@ NODE_CLASS_MAPPINGS = {
"Runware KlingAI Provider Settings": RunwareKlingProviderSettings,
"Runware Runway Provider Settings": RunwareRunwayProviderSettings,
"Runware Midjourney Provider Settings": RunwareMidjourneyProviderSettings,
"Runware Alibaba Provider Settings": RunwareAlibabaProviderSettings,
"Runware Vectorize": vectorize,
"Runware Video Background Removal": videoBgRemoval,
"Runware Video Upscaler": videoUpscaler,
+3 -1
View File
@@ -1,6 +1,6 @@
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, videoTranscriptionHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, useParameterToggleHandler, imageInferenceToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler } from "./utils.js";
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, videoTranscriptionHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, useParameterToggleHandler, imageInferenceToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler } from "./utils.js";
import { RUNWARE_NODE_TYPES, RUNWARE_NODE_PROPS, SEARCH_TERMS } from "./types.js";
const nodeInitList = [];
@@ -71,6 +71,8 @@ app.registerExtension({
briaProviderSettingsToggleHandler(node);
} else if(nodeClass === RUNWARE_NODE_TYPES.PIXVERSEPROVIDERSETTINGS) {
pixverseProviderSettingsToggleHandler(node);
} else if(nodeClass === RUNWARE_NODE_TYPES.ALIBABAPROVIDERSETTINGS) {
alibabaProviderSettingsToggleHandler(node);
}
if(crNodeProps.colorModeOnly === true) return;
+5
View File
@@ -99,6 +99,7 @@ const RUNWARE_NODE_TYPES = {
RUNWAYPROVIDERSETTINGS: "Runware Runway Provider Settings",
LUMAPROVIDERSETTINGS: "Runware Luma Provider Settings",
MIDJOURNEYPROVIDERSETTINGS: "Runware Midjourney Provider Settings",
ALIBABAPROVIDERSETTINGS: "Runware Alibaba Provider Settings",
VECTORIZE: "Runware Vectorize",
VIDEOBGREMOVAL: "Runware Video Background Removal",
VIDEOUPSCALER: "Runware Video Upscaler",
@@ -319,6 +320,10 @@ const RUNWARE_NODE_PROPS = {
bgColor: DEFAULT_BGCOLOR,
colorModeOnly: true,
},
[RUNWARE_NODE_TYPES.ALIBABAPROVIDERSETTINGS]: {
bgColor: DEFAULT_BGCOLOR,
colorModeOnly: true,
},
[RUNWARE_NODE_TYPES.VECTORIZE]: {
bgColor: DEFAULT_BGCOLOR,
},
+205
View File
@@ -1662,6 +1662,8 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
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;
@@ -1776,6 +1778,60 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
"lumaai:2@2": {"width": 1080, "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
"google:2@0": "720p",
"google:3@0": "720p",
"google:3@1": "720p",
"google:3@2": "720p",
"google:3@3": "720p",
"bytedance:2@1": "480p",
"bytedance:1@1": "480p",
"bytedance:5@1": null, // No resolution support
"bytedance:5@2": null, // No resolution support
"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@6": "360p",
"pixverse:lipsync@1": "360p",
"vidu:1@0": "1080p",
"vidu:1@1": "1080p",
"vidu:1@5": "1080p",
"vidu:2@0": "1080p",
"runware:200@1": "480p",
"runware:200@2": "480p",
"runware:200@6": "720p",
"openai:3@1": "720p",
"openai:3@0": "720p",
"lightricks:2@0": "1080p",
"lightricks:2@1": "1080p",
"lightricks:3@1": null, // No resolution support
"runware:190@1": null, // No resolution support
"runway:2@1": "720p",
"runway:1@1": "720p",
"lumaai:1@1": "720p",
"lumaai:2@1": "720p",
"lumaai:2@2": "720p",
};
const DEFAULT_DIMENSIONS = {"width": 1024, "height": 576};
function setWidthHeightEnabled(enabled) {
@@ -1836,6 +1892,49 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
}
// 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() {
@@ -1870,6 +1969,58 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
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();
}
@@ -2010,6 +2161,59 @@ function klingProviderSettingsToggleHandler(klingNode) {
}
}
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");
// 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);
}
// Set up toggle handler
if (usePromptEnhancerWidget && promptEnhancerWidget) {
toggleWidgetState(usePromptEnhancerWidget, promptEnhancerWidget, "promptEnhancer");
}
}
function lumaProviderSettingsToggleHandler(lumaNode) {
// Find all "use" parameter widgets for Luma Provider Settings
const useLoopWidget = lumaNode.widgets.find(w => w.name === "useLoop");
@@ -2241,4 +2445,5 @@ export {
lumaProviderSettingsToggleHandler,
briaProviderSettingsToggleHandler,
pixverseProviderSettingsToggleHandler,
alibabaProviderSettingsToggleHandler,
};
@@ -0,0 +1,67 @@
"""
Runware Alibaba Provider Settings Node
Provides Alibaba-specific settings for image/video generation
"""
from typing import Optional, Dict, Any
class RunwareAlibabaProviderSettings:
"""Runware Alibaba Provider Settings Node"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {},
"optional": {
"usePromptEnhancer": ("BOOLEAN", {
"tooltip": "Enable to include promptEnhancer parameter in provider settings",
"default": False,
}),
"promptEnhancer": ("BOOLEAN", {
"tooltip": "Enable prompt enhancement for Alibaba generation. Only used when 'Use Prompt Enhancer' is enabled.",
"default": False,
"label_on": "Enabled",
"label_off": "Disabled",
}),
}
}
RETURN_TYPES = ("RUNWAREPROVIDERSETTINGS",)
RETURN_NAMES = ("Provider Settings",)
FUNCTION = "createProviderSettings"
CATEGORY = "Runware/Provider Settings"
DESCRIPTION = "Configure Alibaba-specific provider settings for image/video generation including prompt enhancement."
def createProviderSettings(self, **kwargs) -> tuple[Dict[str, Any]]:
"""Create Alibaba provider settings"""
# Get control parameters
usePromptEnhancer = kwargs.get("usePromptEnhancer", False)
# Get value parameters
promptEnhancer = kwargs.get("promptEnhancer", False)
# Build settings dictionary - only include what is enabled
alibabaSettings: Dict[str, Any] = {}
# Add promptEnhancer only if usePromptEnhancer is enabled
if usePromptEnhancer:
alibabaSettings["promptEnhancer"] = promptEnhancer
# Clean up None values
alibabaSettings = {k: v for k, v in alibabaSettings.items() if v is not None}
# Return flat dictionary - will be wrapped by inference node with provider name
return (alibabaSettings,)
# Node class mappings
NODE_CLASS_MAPPINGS = {
"RunwareAlibabaProviderSettings": RunwareAlibabaProviderSettings,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"RunwareAlibabaProviderSettings": "Runware Alibaba Provider Settings",
}
+10
View File
@@ -175,10 +175,14 @@ class txt2vid:
model = runwareVideoModel.get("model", "")
width = runwareVideoModel.get("width")
height = runwareVideoModel.get("height")
useResolution = runwareVideoModel.get("useResolution", False)
resolution = runwareVideoModel.get("resolution", None)
else:
model = runwareVideoModel
width = None
height = None
useResolution = False
resolution = None
genConfig = [
{
@@ -190,6 +194,12 @@ class txt2vid:
"includeCost": True,
}
]
# Add resolution if enabled
if useResolution and resolution:
genConfig[0]["resolution"] = resolution
# Add width/height if not using resolution (or if resolution is not provided)
if (
width is not None and height is not None
and width > 0 and height > 0
+101 -2
View File
@@ -158,6 +158,84 @@ class videoModelSearch:
"lumaai:2@2": {"width": 1080, "height": 720},
}
# Model resolutions mapping
MODEL_RESOLUTIONS = {
# KlingAI Models
"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": None, # No resolution support
"klingai:kling@o1": None, # No standard resolution (1440x1440)
# Veo Models
"google:2@0": "720p",
"google:3@0": "720p",
"google:3@1": "720p",
"google:3@2": "720p",
"google:3@3": "720p",
# Bytedance Models
"bytedance:2@1": "480p",
"bytedance:1@1": "480p",
"bytedance:5@1": None, # No resolution support (fixed 1024x1024)
"bytedance:5@2": None, # No resolution support (fixed 1024x1024)
# MiniMax Models (support both 768p and 720p, using 768p as primary)
"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 Models
"pixverse:1@1": "360p",
"pixverse:1@2": "360p",
"pixverse:1@3": "360p",
"pixverse:1@6": "360p",
"pixverse:lipsync@1": "360p",
# Vidu Models
"vidu:1@0": "1080p",
"vidu:1@1": "1080p",
"vidu:1@5": "1080p",
"vidu:2@0": "1080p",
# Wan Models
"runware:200@1": "480p",
"runware:200@2": "480p",
"runware:200@6": "720p",
# OpenAI Models
"openai:3@1": "720p",
"openai:3@0": "720p",
# Lightricks Models
"lightricks:2@0": "1080p",
"lightricks:2@1": "1080p",
"lightricks:3@1": None, # No resolution support
# Ovi Models
"runware:190@1": None, # No resolution support
# Runway Models
"runway:2@1": "720p",
"runway:1@1": "720p",
# Luma Models
"lumaai:1@1": "720p",
"lumaai:2@1": "720p",
"lumaai:2@2": "720p",
}
MODEL_ARCHITECTURES = [
"All",
"KlingAI",
@@ -182,6 +260,7 @@ class videoModelSearch:
defaultModel = "klingai:5@3 (KlingAI V2.0 Master)"
defaultModelCode = defaultModel.split(" (")[0]
defaultDims = cls.MODEL_DIMENSIONS.get(defaultModelCode, cls.DEFAULT_DIMENSIONS)
defaultResolution = cls.MODEL_RESOLUTIONS.get(defaultModelCode, None)
return {
"required": {
@@ -220,6 +299,14 @@ class videoModelSearch:
"step": 1,
"tooltip": "Custom Height For The Selected Model. Defaults To Model's Recommended Height.",
}),
"useResolution": ("BOOLEAN", {
"tooltip": "Enable to include resolution parameter in API request. Disable if your model doesn't support resolution.",
"default": False,
}),
"resolution": (["360p", "480p", "720p", "768p", "1080p"], {
"tooltip": "Select a standard resolution for Video Inference. Only used when 'Use Resolution' is enabled.",
"default": defaultResolution if defaultResolution else "720p",
}),
},
}
@@ -248,6 +335,8 @@ class videoModelSearch:
customWidth = kwargs.get("Width", 0)
customHeight = kwargs.get("Height", 0)
useCustomDimensions = kwargs.get("useCustomDimensions", "Model Default")
useResolution = kwargs.get("useResolution", False)
resolution = kwargs.get("resolution", "720p")
if enableSearchValue:
modelAirCode = searchInput
@@ -256,6 +345,7 @@ class videoModelSearch:
modelAirCode = currentModel.split(" (")[0]
dimensions = self.MODEL_DIMENSIONS.get(modelAirCode, self.DEFAULT_DIMENSIONS)
modelResolution = self.MODEL_RESOLUTIONS.get(modelAirCode, None)
if useCustomDimensions == "Custom":
# Use custom dimensions from Width/Height widgets
@@ -276,9 +366,18 @@ class videoModelSearch:
returnWidth = width
returnHeight = height
return ({
resultDict = {
"model": modelAirCode,
"useCustomDimensions": useCustomDimensions,
"width": width,
"height": height,
}, returnWidth, returnHeight)
}
# Add resolution if enabled and model supports it
if useResolution and modelResolution is not None:
resultDict["resolution"] = resolution
resultDict["useResolution"] = True
else:
resultDict["useResolution"] = False
return (resultDict, returnWidth, returnHeight)
File diff suppressed because one or more lines are too long