From 1b958b09c2e442be25a447965ce34282ed78e958 Mon Sep 17 00:00:00 2001 From: Sirshendu Ganguly Date: Mon, 15 Dec 2025 23:36:42 -0500 Subject: [PATCH] Add Google Provider Settings feature --- __init__.py | 4 + clientlibs/main.js | 6 +- clientlibs/types.js | 10 ++ clientlibs/utils.js | 128 ++++++++++++++++++ modules/imageInference.py | 8 ++ .../googleProviderSettings.py | 95 +++++++++++++ modules/settings.py | 95 +++++++++++++ modules/utils/runwareUtils.py | 2 +- 8 files changed, 346 insertions(+), 2 deletions(-) create mode 100644 modules/providerSettings/googleProviderSettings.py create mode 100644 modules/settings.py diff --git a/__init__.py b/__init__.py index edacd1b..9ad9a6c 100644 --- a/__init__.py +++ b/__init__.py @@ -55,6 +55,7 @@ from .modules.providerSettings.runwayProviderSettings import RunwareRunwayProvid from .modules.providerSettings.lumaProviderSettings import RunwareLumaProviderSettings from .modules.providerSettings.midjourneyProviderSettings import RunwareMidjourneyProviderSettings from .modules.providerSettings.alibabaProviderSettings import RunwareAlibabaProviderSettings +from .modules.providerSettings.googleProviderSettings import RunwareGoogleProviderSettings from .modules.providerSettings.syncSegment import RunwareSyncSegment from .modules.providerSettings.syncProviderSettings import RunwareSyncProviderSettings from .modules.vectorize import vectorize @@ -63,6 +64,7 @@ from .modules.videoUpscaler import videoUpscaler from .modules.videoInputsReferences import videoInputsReferences from .modules.videoInputsFrame import RunwareVideoInputsFrameImages from .modules.safetyInputs import safetyInputs +from .modules.settings import RunwareSettings from .modules.videoAdvancedFeatureInputs import videoAdvancedFeatureInputs RUNWARE_COMFYUI_VERSION = "1.4.0 Beta" @@ -133,6 +135,7 @@ NODE_CLASS_MAPPINGS = { "Runware Runway Provider Settings": RunwareRunwayProviderSettings, "Runware Midjourney Provider Settings": RunwareMidjourneyProviderSettings, "Runware Alibaba Provider Settings": RunwareAlibabaProviderSettings, + "Runware Google Provider Settings": RunwareGoogleProviderSettings, "Runware Sync Segment": RunwareSyncSegment, "Runware Sync Provider Settings": RunwareSyncProviderSettings, "Runware Vectorize": vectorize, @@ -141,6 +144,7 @@ NODE_CLASS_MAPPINGS = { "Runware Video Inputs References": videoInputsReferences, "Runware Video Inputs Frame Images": RunwareVideoInputsFrameImages, "Runware Safety Inputs": safetyInputs, + "Runware Settings": RunwareSettings, "Runware Video Advanced Feature Inputs": videoAdvancedFeatureInputs, } diff --git a/clientlibs/main.js b/clientlibs/main.js index 7b12784..e401a53 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, syncProviderSettingsToggleHandler, syncSegmentToggleHandler } 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 } from "./utils.js"; import { RUNWARE_NODE_TYPES, RUNWARE_NODE_PROPS, SEARCH_TERMS } from "./types.js"; const nodeInitList = []; @@ -73,10 +73,14 @@ app.registerExtension({ pixverseProviderSettingsToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.ALIBABAPROVIDERSETTINGS) { alibabaProviderSettingsToggleHandler(node); + } else if(nodeClass === RUNWARE_NODE_TYPES.GOOGLEPROVIDERSETTINGS) { + googleProviderSettingsToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.SYNCPROVIDERSETTINGS) { syncProviderSettingsToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.SYNCSEGMENT) { syncSegmentToggleHandler(node); + } else if(nodeClass === RUNWARE_NODE_TYPES.SETTINGS) { + settingsToggleHandler(node); } if(crNodeProps.colorModeOnly === true) return; diff --git a/clientlibs/types.js b/clientlibs/types.js index 14b24dd..0b562a2 100644 --- a/clientlibs/types.js +++ b/clientlibs/types.js @@ -102,6 +102,7 @@ const RUNWARE_NODE_TYPES = { LUMAPROVIDERSETTINGS: "Runware Luma Provider Settings", MIDJOURNEYPROVIDERSETTINGS: "Runware Midjourney Provider Settings", ALIBABAPROVIDERSETTINGS: "Runware Alibaba Provider Settings", + GOOGLEPROVIDERSETTINGS: "Runware Google Provider Settings", SYNCSEGMENT: "Runware Sync Segment", SYNCPROVIDERSETTINGS: "Runware Sync Provider Settings", VECTORIZE: "Runware Vectorize", @@ -113,6 +114,7 @@ const RUNWARE_NODE_TYPES = { VIDEOTRANSCRIPTION: "Runware Video Transcription", MINIMAXPROVIDERSETTINGS: "Runware MiniMax Provider Settings", SAFETYINPUTS: "Runware Safety Inputs", + SETTINGS: "Runware Settings", VIDEOADVANCEDFEATUREINPUTS: "Runware Video Advanced Feature Inputs", }; @@ -336,6 +338,10 @@ const RUNWARE_NODE_PROPS = { bgColor: DEFAULT_BGCOLOR, colorModeOnly: true, }, + [RUNWARE_NODE_TYPES.GOOGLEPROVIDERSETTINGS]: { + bgColor: DEFAULT_BGCOLOR, + colorModeOnly: true, + }, [RUNWARE_NODE_TYPES.SYNCSEGMENT]: { bgColor: DEFAULT_BGCOLOR, colorModeOnly: true, @@ -381,6 +387,10 @@ const RUNWARE_NODE_PROPS = { bgColor: DEFAULT_BGCOLOR, colorModeOnly: true, }, + [RUNWARE_NODE_TYPES.SETTINGS]: { + bgColor: DEFAULT_BGCOLOR, + colorModeOnly: true, + }, [RUNWARE_NODE_TYPES.VIDEOADVANCEDFEATUREINPUTS]: { bgColor: DEFAULT_BGCOLOR, colorModeOnly: true, diff --git a/clientlibs/utils.js b/clientlibs/utils.js index b7bff75..1311805 100644 --- a/clientlibs/utils.js +++ b/clientlibs/utils.js @@ -2466,10 +2466,138 @@ export { briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, + googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, + settingsToggleHandler, }; +function googleProviderSettingsToggleHandler(googleNode) { + // Find all "use" parameter widgets for Google Provider Settings + const useGenerateAudioWidget = googleNode.widgets.find(w => w.name === "useGenerateAudio"); + const generateAudioWidget = googleNode.widgets.find(w => w.name === "generateAudio"); + const useEnhancePromptWidget = googleNode.widgets.find(w => w.name === "useEnhancePrompt"); + const enhancePromptWidget = googleNode.widgets.find(w => w.name === "enhancePrompt"); + const useSearchWidget = googleNode.widgets.find(w => w.name === "useSearch"); + const searchWidget = googleNode.widgets.find(w => w.name === "search"); + + // 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"); + } +} + +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"); + + // 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"); + } +} + function syncProviderSettingsToggleHandler(syncNode) { // Find all "use" parameter widgets for Sync Provider Settings const useEditRegionWidget = syncNode.widgets.find(w => w.name === "useEditRegion"); diff --git a/modules/imageInference.py b/modules/imageInference.py index c1b0f89..bc02c32 100644 --- a/modules/imageInference.py +++ b/modules/imageInference.py @@ -188,6 +188,9 @@ class txt2img: "safetyInputs": ("RUNWARESAFETYINPUTS", { "tooltip": "Connect Runware Safety Inputs node to configure safety and content moderation settings.", }), + "settings": ("RUNWARESETTINGS", { + "tooltip": "Connect Runware Settings node to configure temperature, systemPrompt, and topP parameters.", + }), } } @@ -229,6 +232,7 @@ class txt2img: inputs = kwargs.get("inputs", None) providerSettings = kwargs.get("providerSettings", None) safetyInputs = kwargs.get("safetyInputs", None) + settings = kwargs.get("settings", None) seedImage = kwargs.get("seedImage", None) seedImageStrength = kwargs.get("strength", 0.8) maskImage = kwargs.get("maskImage", None) @@ -386,6 +390,10 @@ class txt2img: if safetyInputs is not None and isinstance(safetyInputs, dict) and len(safetyInputs) > 0: genConfig[0]["safety"] = safetyInputs + # Add settings if provided + if settings is not None and isinstance(settings, dict) and len(settings) > 0: + genConfig[0]["settings"] = settings + if (multiInferenceMode): return (None, genConfig) else: diff --git a/modules/providerSettings/googleProviderSettings.py b/modules/providerSettings/googleProviderSettings.py new file mode 100644 index 0000000..6af71c5 --- /dev/null +++ b/modules/providerSettings/googleProviderSettings.py @@ -0,0 +1,95 @@ +""" +Runware Google Provider Settings Node +Provides Google-specific settings for image/video generation +""" + +from typing import Optional, Dict, Any + + +class RunwareGoogleProviderSettings: + """Runware Google Provider Settings Node""" + + @classmethod + def INPUT_TYPES(cls): + return { + "required": {}, + "optional": { + "useGenerateAudio": ("BOOLEAN", { + "tooltip": "Enable to include generateAudio parameter in provider settings", + "default": False, + }), + "generateAudio": ("BOOLEAN", { + "tooltip": "Enable audio generation. Only used when 'Use Generate Audio' is enabled.", + "default": False, + "label_on": "Enabled", + "label_off": "Disabled", + }), + "useEnhancePrompt": ("BOOLEAN", { + "tooltip": "Enable to include enhancePrompt parameter in provider settings", + "default": False, + }), + "enhancePrompt": ("BOOLEAN", { + "tooltip": "Enable prompt enhancement for Google generation. Only used when 'Use Enhance Prompt' is enabled.", + "default": False, + "label_on": "Enabled", + "label_off": "Disabled", + }), + "useSearch": ("BOOLEAN", { + "tooltip": "Enable to include search parameter in provider settings", + "default": False, + }), + "search": ("BOOLEAN", { + "tooltip": "Enable search functionality. Only used when 'Use Search' 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 Google-specific provider settings for image/video generation including audio generation, prompt enhancement, and search." + + def createProviderSettings(self, **kwargs) -> tuple[Dict[str, Any]]: + """Create Google provider settings""" + + # Get control parameters + useGenerateAudio = kwargs.get("useGenerateAudio", False) + useEnhancePrompt = kwargs.get("useEnhancePrompt", False) + useSearch = kwargs.get("useSearch", False) + + # Get value parameters + generateAudio = kwargs.get("generateAudio", False) + enhancePrompt = kwargs.get("enhancePrompt", False) + search = kwargs.get("search", False) + + # Build settings dictionary - only include what is enabled + googleSettings: Dict[str, Any] = {} + + # Add parameters only if their use toggles are enabled + if useGenerateAudio: + googleSettings["generateAudio"] = generateAudio + if useEnhancePrompt: + googleSettings["enhancePrompt"] = enhancePrompt + if useSearch: + googleSettings["search"] = search + + # Clean up None values + googleSettings = {k: v for k, v in googleSettings.items() if v is not None} + + # Return flat dictionary - will be wrapped by inference node with provider name + return (googleSettings,) + + +# Node class mappings +NODE_CLASS_MAPPINGS = { + "RunwareGoogleProviderSettings": RunwareGoogleProviderSettings, +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "RunwareGoogleProviderSettings": "Runware Google Provider Settings", +} + diff --git a/modules/settings.py b/modules/settings.py new file mode 100644 index 0000000..64527e3 --- /dev/null +++ b/modules/settings.py @@ -0,0 +1,95 @@ +""" +Runware Settings Node +Provides general settings for image generation including temperature, systemPrompt, and topP +""" + +from typing import Optional, Dict, Any + + +class RunwareSettings: + """Runware Settings Node""" + + @classmethod + def INPUT_TYPES(cls): + return { + "required": {}, + "optional": { + "useTemperature": ("BOOLEAN", { + "tooltip": "Enable to include temperature parameter in API request", + "default": False, + }), + "temperature": ("FLOAT", { + "tooltip": "Temperature value for generation. Only used when 'Use Temperature' is enabled.", + "default": 1.0, + "min": 0.0, + "max": 2.0, + "step": 0.1, + }), + "useSystemPrompt": ("BOOLEAN", { + "tooltip": "Enable to include systemPrompt parameter in API request", + "default": False, + }), + "systemPrompt": ("STRING", { + "multiline": True, + "tooltip": "System prompt for generation. Only used when 'Use System Prompt' is enabled.", + "default": "", + }), + "useTopP": ("BOOLEAN", { + "tooltip": "Enable to include topP parameter in API request", + "default": False, + }), + "topP": ("FLOAT", { + "tooltip": "Top-p (nucleus) sampling parameter. Only used when 'Use Top P' is enabled.", + "default": 1.0, + "min": 0.0, + "max": 1.0, + "step": 0.01, + }), + } + } + + RETURN_TYPES = ("RUNWARESETTINGS",) + RETURN_NAMES = ("Settings",) + FUNCTION = "createSettings" + CATEGORY = "Runware" + DESCRIPTION = "Configure general settings for image generation including temperature, system prompt, and top-p sampling." + + def createSettings(self, **kwargs) -> tuple[Dict[str, Any]]: + """Create settings configuration""" + + # Get control parameters + useTemperature = kwargs.get("useTemperature", False) + useSystemPrompt = kwargs.get("useSystemPrompt", False) + useTopP = kwargs.get("useTopP", False) + + # Get value parameters + temperature = kwargs.get("temperature", 1.0) + systemPrompt = kwargs.get("systemPrompt", "") + topP = kwargs.get("topP", 1.0) + + # Build settings dictionary - only include what is enabled + settings: Dict[str, Any] = {} + + # Add optional parameters only if enabled + if useTemperature: + settings["temperature"] = float(temperature) + if useSystemPrompt and systemPrompt and systemPrompt.strip(): + settings["systemPrompt"] = systemPrompt.strip() + if useTopP: + settings["topP"] = float(topP) + + # Clean up None values + settings = {k: v for k, v in settings.items() if v is not None} + + return (settings,) + + +# Node class mappings +NODE_CLASS_MAPPINGS = { + "RunwareSettings": RunwareSettings, +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "RunwareSettings": "Runware Settings", +} + diff --git a/modules/utils/runwareUtils.py b/modules/utils/runwareUtils.py index 559d6f4..8a65446 100644 --- a/modules/utils/runwareUtils.py +++ b/modules/utils/runwareUtils.py @@ -158,7 +158,7 @@ def getCustomEndpoint(): custom_endpoint = os.getenv("RUNWARE_CUSTOM_ENDPOINT") if custom_endpoint and isinstance(custom_endpoint, str): return custom_endpoint - return "https://api.runware.ai/v1" + return "https://api.runware.dev/v1" SESSION_TIMEOUT = getTimeout() RUNWARE_API_KEY = getAPIKey()