diff --git a/__init__.py b/__init__.py index 4cb9bab..4b2474b 100644 --- a/__init__.py +++ b/__init__.py @@ -32,7 +32,7 @@ from .modules.providerSettings.pixverseProviderSettings import RunwarePixversePr from .modules.providerSettings.openaiProviderSettings import RunwareOpenAIProviderSettings from .modules.providerSettings.bytedanceImageProviderSettings import RunwareBytedanceProviderSettings from .modules.providerSettings.briaImageProviderSettings import RunwareBriaProviderSettings -from .modules.providerSettings.briaProviderKeyPoints import RunwareBriaProviderKeyPoints +from .modules.providerSettings.briaProviderMask import RunwareBriaProviderMask from .modules.audioInference import RunwareAudioInference from .modules.audioModelSearch import RunwareAudioModelSearch from .modules.audioSections import RunwareAudioSections @@ -114,7 +114,7 @@ NODE_CLASS_MAPPINGS = { "Runware OpenAI Provider Settings": RunwareOpenAIProviderSettings, "Runware Bytedance Provider Settings": RunwareBytedanceProviderSettings, "Runware Bria Provider Settings": RunwareBriaProviderSettings, - "Runware Bria Provider Key Points": RunwareBriaProviderKeyPoints, + "Runware Bria Provider Mask": RunwareBriaProviderMask, "Runware Audio Inference": RunwareAudioInference, "Runware Audio Model Search": RunwareAudioModelSearch, "Runware Audio Sections": RunwareAudioSections, diff --git a/clientlibs/main.js b/clientlibs/main.js index 19f4a0e..03b81ad 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, videoTranscriptionHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, useParameterToggleHandler, imageInferenceToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderKeyPointsToggleHandler } 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, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler } from "./utils.js"; import { RUNWARE_NODE_TYPES, RUNWARE_NODE_PROPS, SEARCH_TERMS } from "./types.js"; const nodeInitList = []; @@ -85,8 +85,8 @@ app.registerExtension({ audioInputToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.SPEECHINPUT) { speechInputToggleHandler(node); - } else if(nodeClass === RUNWARE_NODE_TYPES.BRIAPROVIDERKEYPOINTS) { - briaProviderKeyPointsToggleHandler(node); + } else if(nodeClass === RUNWARE_NODE_TYPES.BRIAPROVIDERMASK) { + briaProviderMaskToggleHandler(node); } if(crNodeProps.colorModeOnly === true) return; diff --git a/clientlibs/types.js b/clientlibs/types.js index 7711a35..b83c4c2 100644 --- a/clientlibs/types.js +++ b/clientlibs/types.js @@ -86,7 +86,7 @@ const RUNWARE_NODE_TYPES = { OPENAIPROVIDERSETTINGS: "Runware OpenAI Provider Settings", BYTEDANCEPROVIDERSETTINGS: "Runware Bytedance Provider Settings", BRIAPROVIDERSETTINGS: "Runware Bria Provider Settings", - BRIAPROVIDERKEYPOINTS: "Runware Bria Provider Key Points", + BRIAPROVIDERMASK: "Runware Bria Provider Mask", ELEVENLABSPROVIDERSETTINGS: "Runware ElevenLabs Provider Settings", ELEVENLABSPROVIDERSETTINGSSECTIONS: "Runware ElevenLabs Provider Settings Sections", VIDUPROVIDERSETTINGS: "Runware Vidu Provider Settings", @@ -276,7 +276,7 @@ const RUNWARE_NODE_PROPS = { bgColor: DEFAULT_BGCOLOR, colorModeOnly: true, }, - [RUNWARE_NODE_TYPES.BRIAPROVIDERKEYPOINTS]: { + [RUNWARE_NODE_TYPES.BRIAPROVIDERMASK]: { bgColor: DEFAULT_BGCOLOR, colorModeOnly: true, }, diff --git a/clientlibs/utils.js b/clientlibs/utils.js index fbb913e..444c167 100644 --- a/clientlibs/utils.js +++ b/clientlibs/utils.js @@ -2425,12 +2425,8 @@ function briaProviderSettingsToggleHandler(briaNode) { 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 useMaskForegroundWidget = briaNode.widgets.find(w => w.name === "useMaskForeground"); - const maskForegroundWidget = briaNode.widgets.find(w => w.name === "maskForeground"); - const useMaskPromptWidget = briaNode.widgets.find(w => w.name === "useMaskPrompt"); - const maskPromptWidget = briaNode.widgets.find(w => w.name === "maskPrompt"); - const useMaskFrameIndexWidget = briaNode.widgets.find(w => w.name === "useMaskFrameIndex"); - const maskFrameIndexWidget = briaNode.widgets.find(w => w.name === "maskFrameIndex"); + const usePreserveAudioWidget = briaNode.widgets.find(w => w.name === "usePreserveAudio"); + const preserveAudioWidget = briaNode.widgets.find(w => w.name === "preserveAudio"); // Helper function to toggle widget enabled state (exact same pattern) function toggleWidgetState(useWidget, paramWidget, paramName) { @@ -2539,16 +2535,8 @@ function briaProviderSettingsToggleHandler(briaNode) { toggleWidgetState(useAutoTrimWidget, autoTrimWidget, "autoTrim"); } - if (useMaskForegroundWidget && maskForegroundWidget) { - toggleWidgetState(useMaskForegroundWidget, maskForegroundWidget, "maskForeground"); - } - - if (useMaskPromptWidget && maskPromptWidget) { - toggleWidgetState(useMaskPromptWidget, maskPromptWidget, "maskPrompt"); - } - - if (useMaskFrameIndexWidget && maskFrameIndexWidget) { - toggleWidgetState(useMaskFrameIndexWidget, maskFrameIndexWidget, "maskFrameIndex"); + if (usePreserveAudioWidget && preserveAudioWidget) { + toggleWidgetState(usePreserveAudioWidget, preserveAudioWidget, "preserveAudio"); } } @@ -2666,7 +2654,7 @@ function speechInputToggleHandler(speechInputNode) { } } -function briaProviderKeyPointsToggleHandler(keyPointsNode) { +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; @@ -2695,7 +2683,7 @@ function briaProviderKeyPointsToggleHandler(keyPointsNode) { // Fallback: try to find inputs via DOM if inputEl is not available if (!paramWidget.inputEl && paramNames[idx]) { - const nodeElement = keyPointsNode.htmlElements?.widgetsContainer || keyPointsNode.htmlElements; + 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) { @@ -2711,7 +2699,7 @@ function briaProviderKeyPointsToggleHandler(keyPointsNode) { } }); - keyPointsNode.setDirtyCanvas(true); + maskNode.setDirtyCanvas(true); } // Set up callback @@ -2723,12 +2711,31 @@ function briaProviderKeyPointsToggleHandler(keyPointsNode) { 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 = keyPointsNode.widgets.find(w => w.name === `use_${i}`); - const xWidget = keyPointsNode.widgets.find(w => w.name === `X${i}`); - const yWidget = keyPointsNode.widgets.find(w => w.name === `Y${i}`); - const typeWidget = keyPointsNode.widgets.find(w => w.name === `Type${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}`]); @@ -2769,7 +2776,7 @@ export { settingsToggleHandler, audioInputToggleHandler, speechInputToggleHandler, - briaProviderKeyPointsToggleHandler, + briaProviderMaskToggleHandler, }; function googleProviderSettingsToggleHandler(googleNode) { diff --git a/modules/providerSettings/briaImageProviderSettings.py b/modules/providerSettings/briaImageProviderSettings.py index 8728ca3..a90ea01 100644 --- a/modules/providerSettings/briaImageProviderSettings.py +++ b/modules/providerSettings/briaImageProviderSettings.py @@ -130,6 +130,29 @@ class RunwareBriaProviderSettings: "label_on": "Enabled", "label_off": "Disabled", }), + "usePreserveAudio": ("BOOLEAN", { + "tooltip": "Enable to include preserveAudio parameter in API request.", + "default": False, + }), + "preserveAudio": ("BOOLEAN", { + "tooltip": "Whether to keep the original audio track. Only used when 'Use Preserve Audio' is enabled.", + "default": True, + "label_on": "Enabled", + "label_off": "Disabled", + }), + "useAutoTrim": ("BOOLEAN", { + "tooltip": "Enable to include autoTrim parameter in API request.", + "default": False, + }), + "autoTrim": ("BOOLEAN", { + "tooltip": "If true, videos longer than 5 seconds are trimmed to the first 5 seconds. If false, videos longer than 5 seconds are rejected. Only used when 'Use Auto Trim' is enabled.", + "default": False, + "label_on": "Enabled", + "label_off": "Disabled", + }), + "Bria Provider Setting Mask": ("RUNWAREBRIAPROVIDERMASK", { + "tooltip": "Connect Runware Bria Provider Mask node to provide mask configuration for video eraser operations.", + }), } } @@ -155,6 +178,8 @@ class RunwareBriaProviderSettings: useRefinePrompt = kwargs.get("useRefinePrompt", False) useOriginalQuality = kwargs.get("useOriginalQuality", False) useForceBackgroundDetection = kwargs.get("useForceBackgroundDetection", False) + usePreserveAudio = kwargs.get("usePreserveAudio", False) + useAutoTrim = kwargs.get("useAutoTrim", False) # Get actual parameters medium = kwargs.get("medium", "photography") @@ -169,6 +194,9 @@ class RunwareBriaProviderSettings: refinePrompt = kwargs.get("refinePrompt", True) originalQuality = kwargs.get("originalQuality", True) forceBackgroundDetection = kwargs.get("forceBackgroundDetection", False) + preserveAudio = kwargs.get("preserveAudio", True) + autoTrim = kwargs.get("autoTrim", False) + mask = kwargs.get("Bria Provider Setting Mask", None) # Build settings dictionary settings = {} @@ -221,6 +249,18 @@ class RunwareBriaProviderSettings: if useForceBackgroundDetection: settings["forceBackgroundDetection"] = forceBackgroundDetection + # Add preserveAudio only if usePreserveAudio is enabled + if usePreserveAudio: + settings["preserveAudio"] = preserveAudio + + # Add autoTrim only if useAutoTrim is enabled + if useAutoTrim: + settings["autoTrim"] = autoTrim + + # Add mask if provided from Mask node + if mask is not None and isinstance(mask, dict) and len(mask) > 0: + settings["mask"] = mask + # Clean up None values settings = {k: v for k, v in settings.items() if v is not None} diff --git a/modules/providerSettings/briaProviderKeyPoints.py b/modules/providerSettings/briaProviderMask.py similarity index 64% rename from modules/providerSettings/briaProviderKeyPoints.py rename to modules/providerSettings/briaProviderMask.py index 15f2c5d..75ab6ab 100644 --- a/modules/providerSettings/briaProviderKeyPoints.py +++ b/modules/providerSettings/briaProviderMask.py @@ -1,19 +1,47 @@ """ -Runware Bria Provider Key Points Node -Creates key points configuration for Bria mask settings +Runware Bria Provider Mask Node +Creates mask configuration for Bria video eraser settings """ from typing import Optional, Dict, Any, List -class RunwareBriaProviderKeyPoints: - """Runware Bria Provider Key Points Node""" +class RunwareBriaProviderMask: + """Runware Bria Provider Mask Node""" @classmethod def INPUT_TYPES(cls): return { "required": {}, "optional": { + "useForeground": ("BOOLEAN", { + "tooltip": "Enable to include mask.foreground parameter in API request.", + "default": False, + }), + "foreground": ("BOOLEAN", { + "tooltip": "Triggers the foreground mask endpoint. Only used when 'Use Foreground' is enabled.", + "default": True, + "label_on": "Enabled", + "label_off": "Disabled", + }), + "usePrompt": ("BOOLEAN", { + "tooltip": "Enable to include mask.prompt parameter in API request.", + "default": False, + }), + "prompt": ("STRING", { + "tooltip": "Text instruction describing the object to be masked. Only used when 'Use Prompt' is enabled.", + "default": "", + "multiline": True, + }), + "useFrameIndex": ("BOOLEAN", { + "tooltip": "Enable to include mask.frameIndex parameter in API request.", + "default": False, + }), + "frameIndex": ("INT", { + "tooltip": "The frame number to apply key points to. Specifies which frame in the video to use for masking. Only used when 'Use Frame Index' is enabled.", + "default": 0, + "min": 0, + }), "use_1": ("BOOLEAN", { "tooltip": "Enable to include the first key point in the mask configuration.", "default": False, @@ -125,18 +153,42 @@ class RunwareBriaProviderKeyPoints: } } - RETURN_TYPES = ("RUNWAREBRIAPROVIDERKEYPOINTS",) - RETURN_NAMES = ("Key Points",) - FUNCTION = "createKeyPoints" + RETURN_TYPES = ("RUNWAREBRIAPROVIDERMASK",) + RETURN_NAMES = ("Bria Provider Setting Mask",) + FUNCTION = "createMask" CATEGORY = "Runware/Provider Settings" - DESCRIPTION = "Create key points configuration for Bria mask settings. Each key point defines a coordinate (x, y) and type (positive/negative) to guide mask generation." + DESCRIPTION = "Create mask configuration for Bria video eraser settings. Supports foreground mask, text-based masking, and coordinate-based key points for precise object removal." - def createKeyPoints(self, **kwargs) -> tuple[List[Dict[str, Any]]]: - """Create key points array from provided parameters""" + def createMask(self, **kwargs) -> tuple[Dict[str, Any]]: + """Create mask configuration from provided parameters""" + mask: Dict[str, Any] = {} + maskEnabled = False + + # Handle foreground + useForeground = kwargs.get("useForeground", False) + if useForeground: + foreground = kwargs.get("foreground", True) + mask["foreground"] = foreground + maskEnabled = True + + # Handle prompt + usePrompt = kwargs.get("usePrompt", False) + if usePrompt: + prompt = kwargs.get("prompt", "").strip() + if prompt: + mask["prompt"] = prompt + maskEnabled = True + + # Handle frameIndex + useFrameIndex = kwargs.get("useFrameIndex", False) + if useFrameIndex: + frameIndex = kwargs.get("frameIndex", 0) + mask["frameIndex"] = frameIndex + maskEnabled = True + + # Process key points keyPoints: List[Dict[str, Any]] = [] - - # Process up to 6 key points for i in range(1, 7): use_key = kwargs.get(f"use_{i}", False) @@ -147,7 +199,6 @@ class RunwareBriaProviderKeyPoints: point_type = kwargs.get(f"Type{i}", "positive") # Only add key point if both x and y are provided and at least one is non-zero - # This allows users to leave unused key points at 0,0 if x > 0 or y > 0: keyPoints.append({ "x": x, @@ -155,15 +206,23 @@ class RunwareBriaProviderKeyPoints: "type": point_type }) - return (keyPoints,) + # Add keyPoints if any were provided + if len(keyPoints) > 0: + mask["keyPoints"] = keyPoints + maskEnabled = True + + # Only return mask if it has at least one property + if maskEnabled: + return (mask,) + else: + return ({},) # Node class mappings NODE_CLASS_MAPPINGS = { - "RunwareBriaProviderKeyPoints": RunwareBriaProviderKeyPoints, + "RunwareBriaProviderMask": RunwareBriaProviderMask, } NODE_DISPLAY_NAME_MAPPINGS = { - "RunwareBriaProviderKeyPoints": "Runware Bria Provider Key Points", + "RunwareBriaProviderMask": "Runware Bria Provider Mask", } - diff --git a/modules/videoModelSearch.py b/modules/videoModelSearch.py index 16f1092..36f2727 100644 --- a/modules/videoModelSearch.py +++ b/modules/videoModelSearch.py @@ -85,6 +85,9 @@ class videoModelSearch: "sync:lipsync-2-pro@1 (Sync LipSync 2 Pro)", "sync:react-1@1 (Sync React-1)", ], + "Bria": [ + "bria:60@1 (Bria Video Eraser)", + ], } # Model dimensions mapping @@ -170,6 +173,9 @@ class videoModelSearch: "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}, + + # Bria Models + "bria:60@1": {"width": 0, "height": 0}, } # Model resolutions mapping @@ -255,6 +261,9 @@ class videoModelSearch: "sync:lipsync-2@1": "720p", "sync:lipsync-2-pro@1": "720p", "sync:react-1@1": "720p", + + # Bria Models + "bria:60@1": "720p", } MODEL_ARCHITECTURES = [ @@ -271,7 +280,8 @@ class videoModelSearch: "Ovi", "Runway", "Luma", - "Sync" + "Sync", + "Bria" ] DEFAULT_DIMENSIONS = {"width": 1024, "height": 576}