From 89412ff4b588adf407736eb84e6fb9853b9a033d Mon Sep 17 00:00:00 2001 From: Sirshendu Ganguly Date: Tue, 3 Feb 2026 21:21:09 -0500 Subject: [PATCH] Add Ultralytics, settings.quality and Grok and VEED models --- __init__.py | 2 + clientlibs/main.js | 4 +- clientlibs/types.js | 5 + clientlibs/utils.js | 69 +++++++++ modules/imageInference.py | 8 + .../ultralyticsProviderSettings.py | 142 +++++++++++++++++ modules/settings.py | 12 ++ modules/ultralyticsInputs.py | 143 ++++++++++++++++++ modules/videoModelSearch.py | 18 ++- 9 files changed, 398 insertions(+), 5 deletions(-) create mode 100644 modules/providerSettings/ultralyticsProviderSettings.py create mode 100644 modules/ultralyticsInputs.py diff --git a/__init__.py b/__init__.py index 685778e..c090b0c 100644 --- a/__init__.py +++ b/__init__.py @@ -61,6 +61,7 @@ from .modules.providerSettings.alibabaProviderSettings import RunwareAlibabaProv from .modules.providerSettings.googleProviderSettings import RunwareGoogleProviderSettings from .modules.providerSettings.blackForestProviderSettings import RunwareBlackForestProviderSettings from .modules.providerSettings.xaiProviderSettings import RunwareXAIProviderSettings +from .modules.ultralyticsInputs import RunwareUltralyticsInputs from .modules.providerSettings.syncSegment import RunwareSyncSegment from .modules.providerSettings.syncProviderSettings import RunwareSyncProviderSettings from .modules.vectorize import vectorize @@ -152,6 +153,7 @@ NODE_CLASS_MAPPINGS = { "Runware Google Provider Settings": RunwareGoogleProviderSettings, "Runware BlackForest Labs Provider Settings": RunwareBlackForestProviderSettings, "Runware xAI Provider Settings": RunwareXAIProviderSettings, + "Runware Image Inference Ultralytics": RunwareUltralyticsInputs, "Runware Sync Segment": RunwareSyncSegment, "Runware Sync Provider Settings": RunwareSyncProviderSettings, "Runware Vectorize": vectorize, diff --git a/clientlibs/main.js b/clientlibs/main.js index 7c9a988..f403f4d 100644 --- a/clientlibs/main.js +++ b/clientlibs/main.js @@ -1,6 +1,6 @@ import { app } from "../../scripts/app.js"; import { api } from "../../scripts/api.js"; -import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, useParameterToggleHandler, imageInferenceToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler } from "./utils.js"; +import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, useParameterToggleHandler, imageInferenceToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler } from "./utils.js"; import { RUNWARE_NODE_TYPES, RUNWARE_NODE_PROPS, SEARCH_TERMS } from "./types.js"; const nodeInitList = []; @@ -84,6 +84,8 @@ app.registerExtension({ bytedanceProviderSettingsToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.XAIPROVIDERSETTINGS) { xaiProviderSettingsToggleHandler(node); + } else if(nodeClass === RUNWARE_NODE_TYPES.ULTRALYTICSINPUTS) { + ultralyticsProviderSettingsToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.OPENAIPROVIDERSETTINGS) { openaiProviderSettingsToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.LIGHTRICKSPROVIDERSETTINGS) { diff --git a/clientlibs/types.js b/clientlibs/types.js index 1014df2..a44232d 100644 --- a/clientlibs/types.js +++ b/clientlibs/types.js @@ -107,6 +107,7 @@ const RUNWARE_NODE_TYPES = { ALIBABAPROVIDERSETTINGS: "Runware Alibaba Provider Settings", BLACKFORESTPROVIDERSETTINGS: "Runware BlackForest Labs Provider Settings", XAIPROVIDERSETTINGS: "Runware xAI Provider Settings", + ULTRALYTICSINPUTS: "Runware Image Inference Ultralytics", GOOGLEPROVIDERSETTINGS: "Runware Google Provider Settings", SYNCSEGMENT: "Runware Sync Segment", SYNCPROVIDERSETTINGS: "Runware Sync Provider Settings", @@ -369,6 +370,10 @@ const RUNWARE_NODE_PROPS = { bgColor: DEFAULT_BGCOLOR, colorModeOnly: true, }, + [RUNWARE_NODE_TYPES.ULTRALYTICSINPUTS]: { + bgColor: DEFAULT_BGCOLOR, + colorModeOnly: true, + }, [RUNWARE_NODE_TYPES.GOOGLEPROVIDERSETTINGS]: { bgColor: DEFAULT_BGCOLOR, colorModeOnly: true, diff --git a/clientlibs/utils.js b/clientlibs/utils.js index c593409..f0e931f 100644 --- a/clientlibs/utils.js +++ b/clientlibs/utils.js @@ -1260,6 +1260,69 @@ function bytedanceProviderSettingsToggleHandler(bytedanceNode) { } } +function ultralyticsProviderSettingsToggleHandler(ultralyticsNode) { + const useParamPairs = [ + ["useMaskBlur", "maskBlur"], + ["useMaskPadding", "maskPadding"], + ["useConfidence", "confidence"], + ["usePositivePrompt", "positivePrompt"], + ["useNegativePrompt", "negativePrompt"], + ["useSteps", "steps"], + ["useCFGScale", "CFGScale"], + ["useStrength", "strength"], + ]; + + 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"); @@ -3288,6 +3351,7 @@ export { acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, + ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, @@ -3379,6 +3443,8 @@ function settingsToggleHandler(settingsNode) { 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 useQualityWidget = settingsNode.widgets.find(w => w.name === "useQuality"); + const qualityWidget = settingsNode.widgets.find(w => w.name === "quality"); // Helper function to toggle widget enabled state function toggleWidgetState(useWidget, paramWidget, paramName) { @@ -3432,6 +3498,9 @@ function settingsToggleHandler(settingsNode) { if (useTopPWidget && topPWidget) { toggleWidgetState(useTopPWidget, topPWidget, "topP"); } + if (useQualityWidget && qualityWidget) { + toggleWidgetState(useQualityWidget, qualityWidget, "quality"); + } } function syncProviderSettingsToggleHandler(syncNode) { diff --git a/modules/imageInference.py b/modules/imageInference.py index c322195..4587eb0 100644 --- a/modules/imageInference.py +++ b/modules/imageInference.py @@ -191,6 +191,9 @@ class txt2img: "settings": ("RUNWARESETTINGS", { "tooltip": "Connect Runware Settings node to configure temperature, systemPrompt, and topP parameters.", }), + "ultralytics": ("RUNWAREULTRALYTICSINPUTS", { + "tooltip": "Connect Runware Image Inference Ultralytics node to configure Ultralytics parameters (maskBlur, maskPadding, confidence, prompts, steps, CFGScale, strength).", + }), } } @@ -233,6 +236,7 @@ class txt2img: providerSettings = kwargs.get("providerSettings", None) safetyInputs = kwargs.get("safetyInputs", None) settings = kwargs.get("settings", None) + ultralytics = kwargs.get("ultralytics", None) seedImage = kwargs.get("seedImage", None) seedImageStrength = kwargs.get("strength", 0.8) maskImage = kwargs.get("maskImage", None) @@ -394,6 +398,10 @@ class txt2img: if settings is not None and isinstance(settings, dict) and len(settings) > 0: genConfig[0]["settings"] = settings + # Add ultralytics parameters if provided + if ultralytics is not None and isinstance(ultralytics, dict) and len(ultralytics) > 0: + genConfig[0]["ultralytics"] = ultralytics + if (multiInferenceMode): return (None, genConfig) else: diff --git a/modules/providerSettings/ultralyticsProviderSettings.py b/modules/providerSettings/ultralyticsProviderSettings.py new file mode 100644 index 0000000..5d48622 --- /dev/null +++ b/modules/providerSettings/ultralyticsProviderSettings.py @@ -0,0 +1,142 @@ +""" +Runware Image Inference Ultralytics Node +Provides Ultralytics-specific settings for image generation (providerSettings.ultralytics.*) +""" + +from typing import Dict, Any + + +class RunwareUltralyticsProviderSettings: + """Runware Image Inference Ultralytics - Ultralytics provider settings""" + + @classmethod + def INPUT_TYPES(cls): + return { + "required": {}, + "optional": { + "useMaskBlur": ("BOOLEAN", { + "tooltip": "Enable to include maskBlur parameter.", + "default": False, + }), + "maskBlur": ("INT", { + "default": 5, + "min": 0, + "max": 100, + "tooltip": "Mask feathering amount (0-100).", + }), + "useMaskPadding": ("BOOLEAN", { + "tooltip": "Enable to include maskPadding parameter.", + "default": False, + }), + "maskPadding": ("INT", { + "default": 5, + "min": 0, + "max": 20, + "tooltip": "Padding around face region (0-20).", + }), + "useConfidence": ("BOOLEAN", { + "tooltip": "Enable to include confidence parameter.", + "default": False, + }), + "confidence": ("FLOAT", { + "default": 0.5, + "min": 0.0, + "max": 1.0, + "step": 0.01, + "tooltip": "Detection confidence threshold (0-1).", + }), + "usePositivePrompt": ("BOOLEAN", { + "tooltip": "Enable to include positivePrompt parameter.", + "default": False, + }), + "positivePrompt": ("STRING", { + "default": "", + "multiline": True, + "tooltip": "Prompt for diffusion model.", + }), + "useNegativePrompt": ("BOOLEAN", { + "tooltip": "Enable to include negativePrompt parameter.", + "default": False, + }), + "negativePrompt": ("STRING", { + "default": "", + "multiline": True, + "tooltip": "Negative prompt for model.", + }), + "useSteps": ("BOOLEAN", { + "tooltip": "Enable to include steps parameter.", + "default": False, + }), + "steps": ("INT", { + "default": 20, + "min": 1, + "max": 100, + "tooltip": "Number of diffusion steps (1-100).", + }), + "useCFGScale": ("BOOLEAN", { + "tooltip": "Enable to include CFGScale parameter.", + "default": False, + }), + "CFGScale": ("FLOAT", { + "default": 8.0, + "min": 0.0, + "max": 50.0, + "step": 0.1, + "tooltip": "Classifier-free guidance scale (0-50).", + }), + "useStrength": ("BOOLEAN", { + "tooltip": "Enable to include strength parameter.", + "default": False, + }), + "strength": ("FLOAT", { + "default": 0.3, + "min": 0.0001, + "max": 1.0, + "step": 0.01, + "tooltip": "Denoising strength (0.0001-1).", + }), + } + } + + DESCRIPTION = "Configure Ultralytics-specific settings for Runware Image Inference. providerSettings.ultralytics.*" + RETURN_TYPES = ("RUNWAREPROVIDERSETTINGS",) + RETURN_NAMES = ("providerSettings",) + FUNCTION = "create_provider_settings" + CATEGORY = "Runware/Provider Settings" + + def create_provider_settings(self, **kwargs) -> tuple[Dict[str, Any]]: + """Create Ultralytics provider settings""" + + settings = {} + + if kwargs.get("useMaskBlur", False): + settings["maskBlur"] = kwargs.get("maskBlur", 5) + if kwargs.get("useMaskPadding", False): + settings["maskPadding"] = kwargs.get("maskPadding", 5) + if kwargs.get("useConfidence", False): + settings["confidence"] = kwargs.get("confidence", 0.5) + if kwargs.get("usePositivePrompt", False): + val = kwargs.get("positivePrompt", "") + if val is not None and str(val).strip(): + settings["positivePrompt"] = str(val).strip() + if kwargs.get("useNegativePrompt", False): + val = kwargs.get("negativePrompt", "") + if val is not None and str(val).strip(): + settings["negativePrompt"] = str(val).strip() + if kwargs.get("useSteps", False): + settings["steps"] = kwargs.get("steps", 20) + if kwargs.get("useCFGScale", False): + settings["CFGScale"] = kwargs.get("CFGScale", 8.0) + if kwargs.get("useStrength", False): + settings["strength"] = kwargs.get("strength", 0.3) + + return (settings,) + + +NODE_CLASS_MAPPINGS = { + "RunwareUltralyticsProviderSettings": RunwareUltralyticsProviderSettings, +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "RunwareUltralyticsProviderSettings": "Runware Image Inference Ultralytics", +} diff --git a/modules/settings.py b/modules/settings.py index 854fd8b..7a60edc 100644 --- a/modules/settings.py +++ b/modules/settings.py @@ -66,6 +66,14 @@ class RunwareSettings: "min": 1.0, "step": 0.1, }), + "useQuality": ("BOOLEAN", { + "tooltip": "Enable to include quality parameter in API request", + "default": False, + }), + "quality": (["low", "medium", "high"], { + "default": "medium", + "tooltip": "Quality of the output image. Only used when 'Use Quality' is enabled.", + }), } } @@ -84,6 +92,7 @@ class RunwareSettings: useTopP = kwargs.get("useTopP", False) useLayers = kwargs.get("useLayers", False) useTrueCFGScale = kwargs.get("useTrueCFGScale", False) + useQuality = kwargs.get("useQuality", False) # Get value parameters temperature = kwargs.get("temperature", 1.0) @@ -91,6 +100,7 @@ class RunwareSettings: topP = kwargs.get("topP", 1.0) layers = kwargs.get("layers") trueCFGScale = kwargs.get("trueCFGScale") + quality = kwargs.get("quality", "medium") # Build settings dictionary - only include what is enabled settings: Dict[str, Any] = {} @@ -106,6 +116,8 @@ class RunwareSettings: settings["layers"] = int(layers) if useTrueCFGScale: settings["true_cfg_scale"] = float(trueCFGScale) + if useQuality: + settings["quality"] = quality # Clean up None values settings = {k: v for k, v in settings.items() if v is not None} diff --git a/modules/ultralyticsInputs.py b/modules/ultralyticsInputs.py new file mode 100644 index 0000000..bd7b03f --- /dev/null +++ b/modules/ultralyticsInputs.py @@ -0,0 +1,143 @@ +""" +Runware Image Inference Ultralytics Node +Provides Ultralytics parameters for image inference (ultralytics.*) +Parameters are passed to genConfig["ultralytics"] like settings. +""" + +from typing import Dict, Any + + +class RunwareUltralyticsInputs: + """Runware Image Inference Ultralytics - Ultralytics parameters for image inference""" + + @classmethod + def INPUT_TYPES(cls): + return { + "required": {}, + "optional": { + "useMaskBlur": ("BOOLEAN", { + "tooltip": "Enable to include maskBlur parameter.", + "default": False, + }), + "maskBlur": ("INT", { + "default": 5, + "min": 0, + "max": 100, + "tooltip": "Mask feathering amount (0-100).", + }), + "useMaskPadding": ("BOOLEAN", { + "tooltip": "Enable to include maskPadding parameter.", + "default": False, + }), + "maskPadding": ("INT", { + "default": 5, + "min": 0, + "max": 20, + "tooltip": "Padding around face region (0-20).", + }), + "useConfidence": ("BOOLEAN", { + "tooltip": "Enable to include confidence parameter.", + "default": False, + }), + "confidence": ("FLOAT", { + "default": 0.5, + "min": 0.0, + "max": 1.0, + "step": 0.01, + "tooltip": "Detection confidence threshold (0-1).", + }), + "usePositivePrompt": ("BOOLEAN", { + "tooltip": "Enable to include positivePrompt parameter.", + "default": False, + }), + "positivePrompt": ("STRING", { + "default": "", + "multiline": True, + "tooltip": "Prompt for diffusion model.", + }), + "useNegativePrompt": ("BOOLEAN", { + "tooltip": "Enable to include negativePrompt parameter.", + "default": False, + }), + "negativePrompt": ("STRING", { + "default": "", + "multiline": True, + "tooltip": "Negative prompt for model.", + }), + "useSteps": ("BOOLEAN", { + "tooltip": "Enable to include steps parameter.", + "default": False, + }), + "steps": ("INT", { + "default": 20, + "min": 1, + "max": 100, + "tooltip": "Number of diffusion steps (1-100).", + }), + "useCFGScale": ("BOOLEAN", { + "tooltip": "Enable to include CFGScale parameter.", + "default": False, + }), + "CFGScale": ("FLOAT", { + "default": 8.0, + "min": 0.0, + "max": 50.0, + "step": 0.1, + "tooltip": "Classifier-free guidance scale (0-50).", + }), + "useStrength": ("BOOLEAN", { + "tooltip": "Enable to include strength parameter.", + "default": False, + }), + "strength": ("FLOAT", { + "default": 0.3, + "min": 0.0001, + "max": 1.0, + "step": 0.01, + "tooltip": "Denoising strength (0.0001-1).", + }), + } + } + + DESCRIPTION = "Configure Ultralytics parameters for Runware Image Inference. Passed as genConfig.ultralytics (like settings)." + RETURN_TYPES = ("RUNWAREULTRALYTICSINPUTS",) + RETURN_NAMES = ("Ultralytics",) + FUNCTION = "create_ultralytics_inputs" + CATEGORY = "Runware" + + def create_ultralytics_inputs(self, **kwargs) -> tuple[Dict[str, Any]]: + """Create Ultralytics parameters dict""" + + settings = {} + + if kwargs.get("useMaskBlur", False): + settings["maskBlur"] = kwargs.get("maskBlur", 5) + if kwargs.get("useMaskPadding", False): + settings["maskPadding"] = kwargs.get("maskPadding", 5) + if kwargs.get("useConfidence", False): + settings["confidence"] = kwargs.get("confidence", 0.5) + if kwargs.get("usePositivePrompt", False): + val = kwargs.get("positivePrompt", "") + if val is not None and str(val).strip(): + settings["positivePrompt"] = str(val).strip() + if kwargs.get("useNegativePrompt", False): + val = kwargs.get("negativePrompt", "") + if val is not None and str(val).strip(): + settings["negativePrompt"] = str(val).strip() + if kwargs.get("useSteps", False): + settings["steps"] = kwargs.get("steps", 20) + if kwargs.get("useCFGScale", False): + settings["CFGScale"] = kwargs.get("CFGScale", 8.0) + if kwargs.get("useStrength", False): + settings["strength"] = kwargs.get("strength", 0.3) + + return (settings,) + + +NODE_CLASS_MAPPINGS = { + "RunwareUltralyticsInputs": RunwareUltralyticsInputs, +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "RunwareUltralyticsInputs": "Runware Image Inference Ultralytics", +} diff --git a/modules/videoModelSearch.py b/modules/videoModelSearch.py index 31cacde..7d5a0e7 100644 --- a/modules/videoModelSearch.py +++ b/modules/videoModelSearch.py @@ -102,7 +102,10 @@ class videoModelSearch: "runware:hunyuanvideo@1.5 (HunyuanVideo-1.5)", ], "xAI": [ - "xai:1@1 (xAI Video 480p)", + "xai:grok-imagine@video (Grok Imagine Video)", + ], + "VEED": [ + "veed:fabric@1.0 (VEED Fabric 1.0)", ], } @@ -207,7 +210,10 @@ class videoModelSearch: "runware:hunyuanvideo@1.5": {"width": 848, "height": 480}, # xAI Models - "xai:1@1": {"width": 480, "height": 480}, + "xai:grok-imagine@video": {"width": 480, "height": 480}, + + # VEED Models (preserves input aspect ratio; resolution = shorter side) + "veed:fabric@1.0": {"width": 1280, "height": 720}, } # Model resolutions mapping @@ -311,7 +317,10 @@ class videoModelSearch: "runware:hunyuanvideo@1.5": "480p", # xAI Models - "xai:1@1": "480p", + "xai:grok-imagine@video": "480p", + + # VEED Models (480p or 720p) + "veed:fabric@1.0": "720p", } MODEL_ARCHITECTURES = [ @@ -332,7 +341,8 @@ class videoModelSearch: "Bria", "Creatify", "Hunyuan", - "xAI" + "xAI", + "VEED" ] DEFAULT_DIMENSIONS = {"width": 1024, "height": 576}