diff --git a/__init__.py b/__init__.py index 942fcf9..2ba9aac 100644 --- a/__init__.py +++ b/__init__.py @@ -27,6 +27,7 @@ from .modules.referenceImages import referenceImages from .modules.imageInferenceInputs import imageInferenceInputs from .modules.videoInference import txt2vid from .modules.videoModelSearch import videoModelSearch +from .modules.videoSettings import RunwareVideoSettings from .modules.frameImages import RunwareFrameImages from .modules.providerSettings.pixverseProviderSettings import RunwarePixverseProviderSettings from .modules.providerSettings.openaiProviderSettings import RunwareOpenAIProviderSettings @@ -159,6 +160,7 @@ NODE_CLASS_MAPPINGS = { "Runware Reference Videos": referenceVideos, "Runware Reference Voices": referenceVoices, "Runware Video Inference Inputs": videoInferenceInputs, + "Runware Video Inference Settings": RunwareVideoSettings, "Runware Lightricks Provider Settings": RunwareLightricksProviderSettings, "Runware MiniMax Provider Settings": RunwareMiniMaxProviderSettings, "Runware Luma Provider Settings": RunwareLumaProviderSettings, diff --git a/clientlibs/main.js b/clientlibs/main.js index 44cc6f3..6a8d6a1 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, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, viduProviderSettingsToggleHandler, sourcefulProviderSettingsToggleHandler, sourcefulProviderSettingsFontsToggleHandler, threeDInferenceToggleHandler, threeDInferenceSettingsToggleHandler, threeDInferenceSettingsLatToggleHandler, ultralyticsProviderSettingsToggleHandler, 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, vectorizeModelSearchFilterHandler, vectorizeToggleHandler, useParameterToggleHandler, imageInferenceToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, videoSettingsToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, viduProviderSettingsToggleHandler, sourcefulProviderSettingsToggleHandler, sourcefulProviderSettingsFontsToggleHandler, threeDInferenceToggleHandler, threeDInferenceSettingsToggleHandler, threeDInferenceSettingsLatToggleHandler, 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 = []; @@ -82,6 +82,8 @@ app.registerExtension({ audioInferenceSpeechToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.AUDIOSETTINGS) { audioSettingsToggleHandler(node); + } else if(nodeClass === RUNWARE_NODE_TYPES.VIDEOSETTINGS) { + videoSettingsToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.ACCELERATOROPTIONS) { acceleratorOptionsToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.BYTEDANCEPROVIDERSETTINGS) { @@ -149,6 +151,9 @@ app.registerExtension({ videoModelSearchFilterHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.AUDIOMODELSEARCH) { audioModelSearchFilterHandler(node); + } else if(nodeClass === RUNWARE_NODE_TYPES.VECTORIZE) { + vectorizeModelSearchFilterHandler(node); + vectorizeToggleHandler(node); } for(const nodeWidget of nodeWidgets) { diff --git a/clientlibs/types.js b/clientlibs/types.js index f33d7b0..c31fb86 100644 --- a/clientlibs/types.js +++ b/clientlibs/types.js @@ -101,6 +101,7 @@ const RUNWARE_NODE_TYPES = { REFERENCEVIDEOS: "Runware Reference Videos", REFERENCEVOICES: "Runware Reference Voices", VIDEOINFERENCEINPUTS: "Runware Video Inference Inputs", + VIDEOSETTINGS: "Runware Video Inference Settings", LIGHTRICKSPROVIDERSETTINGS: "Runware Lightricks Provider Settings", KLINGPROVIDERSETTINGS: "Runware KlingAI Provider Settings", KLINGMULTIPROMPTSEGMENT: "Runware Kling MultiPrompt Segment", @@ -427,6 +428,7 @@ const RUNWARE_NODE_PROPS = { }, [RUNWARE_NODE_TYPES.VECTORIZE]: { bgColor: DEFAULT_BGCOLOR, + liveDimensions: true, }, [RUNWARE_NODE_TYPES.VIDEOBGREMOVAL]: { bgColor: DEFAULT_BGCOLOR, @@ -452,6 +454,9 @@ const RUNWARE_NODE_PROPS = { [RUNWARE_NODE_TYPES.AUDIOSETTINGSVOICEMODIFY]: { bgColor: DEFAULT_BGCOLOR, }, + [RUNWARE_NODE_TYPES.VIDEOSETTINGS]: { + bgColor: DEFAULT_BGCOLOR, + }, [RUNWARE_NODE_TYPES.ACCELERATOROPTIONS]: { bgColor: DEFAULT_BGCOLOR, colorModeOnly: true, diff --git a/clientlibs/utils.js b/clientlibs/utils.js index 23b03c3..1a02fea 100644 --- a/clientlibs/utils.js +++ b/clientlibs/utils.js @@ -419,8 +419,9 @@ async function syncDimensionsNodeHandler(node, dimensionsWidget) { appendWidgetCB(dimensionsWidget, function(...args) { const chosenDimension = args[0]; - if(chosenDimension === "Custom") return; + 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"); @@ -1162,6 +1163,37 @@ function audioSettingsToggleHandler(settingsNode) { if (useTurboWidget && turboWidget) toggleWidgetState(useTurboWidget, turboWidget, "turbo"); } +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 usePromptUpsamplingWidget = settingsNode.widgets.find(w => w && w.name === "usePromptUpsampling"); + const promptUpsamplingWidget = settingsNode.widgets.find(w => w && w.name === "promptUpsampling"); + + 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 (usePromptUpsamplingWidget && promptUpsamplingWidget) toggleWidgetState(usePromptUpsamplingWidget, promptUpsamplingWidget, "promptUpsampling"); +} + function audioInferenceSpeechToggleHandler(speechNode) { if (!speechNode?.widgets) return; @@ -2323,6 +2355,9 @@ function videoModelSearchFilterHandler(videoModelSearchNode) { "VEED": [ "veed:fabric@1.0 (VEED Fabric 1.0)", ], + "Pruna": [ + "prunaai:p-video@0 (P-Video)", + ], }; const MODEL_DIMENSIONS = { @@ -2402,6 +2437,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) { "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}, }; const MODEL_RESOLUTIONS = { @@ -2481,6 +2517,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) { "runware:210@1": null, // No resolution support (fixed 512x512) "xai:grok-imagine@video": "480p", "veed:fabric@1.0": "720p", + "prunaai:p-video@0": "720p", }; const DEFAULT_DIMENSIONS = {"width": 1024, "height": 576}; @@ -2728,6 +2765,105 @@ function audioModelSearchFilterHandler(audioModelSearchNode) { 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 Positive Prompt"); + 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"); @@ -3794,6 +3930,8 @@ export { videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, + vectorizeModelSearchFilterHandler, + vectorizeToggleHandler, useParameterToggleHandler, imageInferenceToggleHandler, upscalerToggleHandler, @@ -3801,6 +3939,7 @@ export { audioInferenceToggleHandler, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, + videoSettingsToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, diff --git a/modules/saveImage.py b/modules/saveImage.py index bc139c6..b3ac596 100644 --- a/modules/saveImage.py +++ b/modules/saveImage.py @@ -8,13 +8,25 @@ from PIL import Image from datetime import datetime +def _is_svg_url(url: str) -> bool: + """True if URL points to SVG (e.g. from Runware Vectorize).""" + u = (url or "").split("?")[0].lower() + return u.endswith(".svg") + + def _bytes_to_image_tensor(img_data: bytes): - """Decode image bytes to ComfyUI IMAGE tensor [1, H, W, C] float32 0-1.""" + """Decode image bytes to ComfyUI IMAGE tensor [1, H, W, C] float32 0-1. Fails on SVG (use placeholder for SVG).""" pil = Image.open(io.BytesIO(img_data)).convert("RGB") arr = np.array(pil).astype(np.float32) / 255.0 return torch.from_numpy(arr).unsqueeze(0) +def _placeholder_image_tensor(): + """Return a 1x1 RGB placeholder tensor [1, 1, 1, 3] for non-raster outputs (e.g. SVG from Vectorize).""" + arr = np.ones((1, 1, 3), dtype=np.float32) * 0.5 # grey + return torch.from_numpy(arr).unsqueeze(0) + + class RunwareSaveImage: """Runware Save Image: download from URL(s), save/preview to disk, and forward as IMAGE for chaining.""" @@ -23,7 +35,7 @@ class RunwareSaveImage: return { "required": { "Images": ("STRING", { - "tooltip": "Image URL(s) from Runware Image Inference node. For multiple images, URLs should be comma-separated." + "tooltip": "Image URL(s) from Runware Image Inference or Runware Vectorize node. For multiple images, URLs should be comma-separated. SVG URLs (e.g. from Vectorize) are saved as .svg files; a placeholder tensor is passed for the IMAGE output." }), "filenamePrefix": ("STRING", { "default": "ComfyUI", @@ -69,10 +81,14 @@ class RunwareSaveImage: response.raise_for_status() img_data = response.content - tensors.append(_bytes_to_image_tensor(img_data)) + # SVG (e.g. from Runware Vectorize) cannot be opened by PIL; save as file and use placeholder tensor + if _is_svg_url(image_url): + tensors.append(_placeholder_image_tensor()) + else: + tensors.append(_bytes_to_image_tensor(img_data)) url_without_params = image_url.split("?")[0] - ext = url_without_params.split(".")[-1].lstrip(".") or "png" + ext = url_without_params.split(".")[-1].lstrip(".").lower() or "png" extension = "." + ext if len(image_urls) > 1: filename = f"{filenamePrefix}_{timestamp}_{i+1:03}{extension}" diff --git a/modules/vectorize.py b/modules/vectorize.py index 9b22a28..6dc200a 100644 --- a/modules/vectorize.py +++ b/modules/vectorize.py @@ -1,24 +1,97 @@ +import re + from .utils import runwareUtils as rwUtils class vectorize: """Vectorize node for converting images to vector format""" - - RUNWARE_VECTORIZE_MODELS = { - "recraft:1@1": "recraft:1@1", - "picsart:1@1": "picsart:1@1", + + # Models grouped by architecture (provider), same pattern as video model search + 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)", + ], } - + + MODEL_ARCHITECTURES = [ + "All", + "Recraft", + "Picsart", + ] + + @classmethod + def _getAllModels(cls): + """Get all models from all architectures""" + all_models = [] + for models in cls.VECTORIZE_MODELS.values(): + all_models.extend(models) + return all_models + @classmethod def INPUT_TYPES(cls): + all_models = cls._getAllModels() + default_model = all_models[0] if all_models else "recraft:1@1 (Recraft 1)" return { "required": { - "Image": ("IMAGE", { - "tooltip": "Input image to be vectorized." + "Model Search": ("STRING", { + "tooltip": "Search for a vectorization model by name or AIR code (e.g. recraft, picsart).", }), - "Model": (list(cls.RUNWARE_VECTORIZE_MODELS.keys()), { - "tooltip": "Select the vectorization model to use.", - "default": "recraft:1@1", + "Model Architecture": (cls.MODEL_ARCHITECTURES, { + "tooltip": "Choose model architecture to filter the model list.", + "default": "Recraft", + }), + "Vector Model List": (all_models, { + "tooltip": "Select the vectorization model. Filter by Model Architecture above.", + "default": default_model, + }), + "Use Search Value": ("BOOLEAN", { + "tooltip": "When enabled, the value in Model Search is used as the model AIR code instead of the list selection.", + "default": False, + "label_on": "Enabled", + "label_off": "Disabled", + }), + }, + "optional": { + "Image": ("IMAGE", { + "tooltip": "Optional input image to be vectorized." + }), + "dimensions": ([ + "None", "Square HD (1024x1024)", "Custom" + ], { + "default": "None", + "tooltip": "Output dimensions preset. Select 'None' for model default, or a preset to set width/height. Use 'Custom' with width/height inputs.", + }), + "width": ("INT", { + "tooltip": "Width in pixels. Used when dimensions is not 'None' (or with Custom).", + "default": 1024, + "min": 128, + "max": 6048, + "step": 1, + }), + "height": ("INT", { + "tooltip": "Height in pixels. Used when dimensions is not 'None' (or with Custom).", + "default": 1024, + "min": 128, + "max": 6048, + "step": 1, + }), + "Use positivePrompt": ("BOOLEAN", { + "tooltip": "When enabled, include positivePrompt in the vectorize request.", + "default": False, + "label_on": "Enabled", + "label_off": "Disabled", + }), + "positivePrompt": ("STRING", { + "multiline": True, + "tooltip": "Optional text prompt for vectorization. Only sent when Use Positive Prompt is enabled.", + }), + "providerSettings": ("RUNWAREPROVIDERSETTINGS", { + "tooltip": "Connect a Runware Provider Settings Node to configure provider-specific parameters (e.g. Recraft, Picsart).", }), }, } @@ -29,51 +102,104 @@ class vectorize: RETURN_NAMES = ("IMAGE",) CATEGORY = "Runware" + @classmethod + def VALIDATE_INPUTS(cls, **kwargs): + return True + def vectorizeImage(self, **kwargs): """Vectorize image and return SVG URL""" image = kwargs.get("Image") - modelName = kwargs.get("Model", "recraft:1@1") - - model = self.RUNWARE_VECTORIZE_MODELS.get(modelName, "recraft:1@1") - imageUuid = rwUtils.convertTensor2IMG(image) - - genConfig = self._buildGenConfig(model, imageUuid) - + use_search_value = kwargs.get("Use Search Value", False) + search_input = kwargs.get("Model Search", "") + current_model = kwargs.get("Vector Model List", "recraft:1@1 (Recraft 1)") + + if use_search_value and search_input and str(search_input).strip(): + model_air_code = str(search_input).strip() + else: + # Extract AIR code from "airId (Display Name)" format + model_air_code = current_model.split(" (")[0].strip() + + image_uuid = rwUtils.convertTensor2IMG(image) if image is not None else None + width = kwargs.get("width") + height = kwargs.get("height") + dimensions = kwargs.get("dimensions", "None") + use_positive_prompt = kwargs.get("Use positivePrompt", False) + positive_prompt = kwargs.get("positivePrompt") + provider_settings = kwargs.get("providerSettings") + gen_config = self._buildGenConfig( + model_air_code, image_uuid, + width=width, height=height, dimensions=dimensions, + use_positive_prompt=use_positive_prompt, positive_prompt=positive_prompt, + provider_settings=provider_settings, + ) + print(f"[DEBUG] Sending Vectorize Request:") - print(f"[DEBUG] Request Payload: {rwUtils.safe_json_dumps(genConfig, indent=2)}") - - genResult = rwUtils.inferenecRequest(genConfig) - + print(f"[DEBUG] Request Payload: {rwUtils.safe_json_dumps(gen_config, indent=2)}") + + gen_result = rwUtils.inferenecRequest(gen_config) print(f"[DEBUG] Received Vectorize Response:") - print(f"[DEBUG] Response: {rwUtils.safe_json_dumps(genResult, indent=2)}") - - self._validateResponse(genResult) - - svg_url = rwUtils.extractImageURLs(genResult) - + print(f"[DEBUG] Response: {rwUtils.safe_json_dumps(gen_result, indent=2)}") + + self._validateResponse(gen_result) + svg_url = rwUtils.extractImageURLs(gen_result) return (svg_url,) - def _buildGenConfig(self, model, imageUuid): - """Build generation configuration for API request""" - return [{ + @staticmethod + def _parseDimensionsPreset(dimensions): + """Parse 'Label (WxH)' to (width, height) or None if not a preset.""" + if not dimensions or dimensions in ("None", "Custom"): + return None, None + m = re.search(r"\((\d+)x(\d+)\)", dimensions) + if m: + return int(m.group(1)), int(m.group(2)) + return None, None + + def _buildGenConfig(self, model, image_uuid, width=None, height=None, dimensions="None", + use_positive_prompt=False, positive_prompt=None, provider_settings=None): + """Build generation configuration for API request. image_uuid, width, height, positivePrompt, providerSettings are optional.""" + inputs = {} + if image_uuid is not None: + inputs["image"] = image_uuid + payload = { "taskType": "vectorize", "taskUUID": rwUtils.genRandUUID(), "model": model, - "inputs": { - "image": imageUuid - }, + "inputs": inputs, "outputType": "URL", "outputFormat": "svg", - }] + } + if dimensions and dimensions != "None": + w, h = width, height + if w is None or h is None: + pw, ph = self._parseDimensionsPreset(dimensions) + if pw is not None and ph is not None: + w, h = pw, ph + if w is not None and h is not None: + payload["width"] = w + payload["height"] = h + if use_positive_prompt and positive_prompt is not None and str(positive_prompt).strip(): + payload["positivePrompt"] = str(positive_prompt).strip() + # Handle providerSettings - extract provider name from model and merge (same as image inference) + if provider_settings is not None: + provider_name = model.split(":")[0] if ":" in model else model + if isinstance(provider_settings, dict): + if any(key in provider_settings for key in ["alibaba", "bytedance", "klingai", "openai", "pixverse", + "bria", "lightricks", "luma", "minimax", "runway", "vidu", + "elevenlabs", "bfl", "xai", "recraft", "picsart", "sourceful"]): + payload["providerSettings"] = provider_settings + else: + payload["providerSettings"] = {provider_name: provider_settings} + else: + payload["providerSettings"] = provider_settings + return [payload] - def _validateResponse(self, genResult): + def _validateResponse(self, gen_result): """Validate API response""" - if "errors" in genResult: - errorMessage = genResult["errors"][0]["message"] - raise Exception(f"Vectorization failed: {errorMessage}") + if "errors" in gen_result: + error_message = gen_result["errors"][0]["message"] + raise Exception(f"Vectorization failed: {error_message}") -# Node class mappings NODE_CLASS_MAPPINGS = { "RunwareVectorize": vectorize, } diff --git a/modules/videoInference.py b/modules/videoInference.py index 39b0db2..378c0a2 100644 --- a/modules/videoInference.py +++ b/modules/videoInference.py @@ -144,6 +144,9 @@ class txt2vid: "Accelerator": ("RUNWAREACCELERATOR", { "tooltip": "Connect a Runware Accelerator Options Node to configure caching and acceleration settings.", }), + "settings": ("RUNWAREVIDEOSETTINGS", { + "tooltip": "Connect a Runware Video Inference Settings node to configure draft, audio, and promptUpsampling.", + }), } } @@ -181,6 +184,7 @@ class txt2vid: safetyInputs = kwargs.get("safetyInputs", None) videoAdvancedFeatureInputs = kwargs.get("videoAdvancedFeatureInputs", None) runwareAccelerator = kwargs.get("Accelerator", None) + settings = kwargs.get("settings", None) useDuration = kwargs.get("useDuration", True) duration = kwargs.get("duration", 5) fps = kwargs.get("fps", 24) @@ -350,6 +354,10 @@ class txt2vid: # Add accelerator options if provided if runwareAccelerator is not None and isinstance(runwareAccelerator, dict) and len(runwareAccelerator) > 0: genConfig[0]["acceleratorOptions"] = runwareAccelerator + + # Add settings if provided (draft, audio, promptUpsampling) + if settings is not None and isinstance(settings, dict) and len(settings) > 0: + genConfig[0]["settings"] = settings # Add acceleration if not "none" if acceleration and acceleration != "none": diff --git a/modules/videoModelSearch.py b/modules/videoModelSearch.py index e289a38..b286cdd 100644 --- a/modules/videoModelSearch.py +++ b/modules/videoModelSearch.py @@ -117,6 +117,9 @@ class videoModelSearch: "VEED": [ "veed:fabric@1.0 (VEED Fabric 1.0)", ], + "Pruna": [ + "prunaai:p-video@0 (P-Video)", + ], } # Model dimensions mapping @@ -234,6 +237,9 @@ class videoModelSearch: # VEED Models (preserves input aspect ratio; resolution = shorter side) "veed:fabric@1.0": {"width": 1280, "height": 720}, + + # Pruna Models (720p) + "prunaai:p-video@0": {"width": 1280, "height": 720}, } # Model resolutions mapping @@ -349,10 +355,13 @@ class videoModelSearch: # xAI Models "xai:grok-imagine@video": "480p", - # VEED Models + # VEED Models "veed:fabric@1.0": "720p", + + # Pruna Models + "prunaai:p-video@0": "720p", } - + MODEL_ARCHITECTURES = [ "All", "KlingAI", @@ -373,7 +382,8 @@ class videoModelSearch: "Hunyuan", "Kandinsky", "xAI", - "VEED" + "VEED", + "Pruna", ] DEFAULT_DIMENSIONS = {"width": 1024, "height": 576} diff --git a/modules/videoSettings.py b/modules/videoSettings.py new file mode 100644 index 0000000..3c2e713 --- /dev/null +++ b/modules/videoSettings.py @@ -0,0 +1,83 @@ +""" +Runware Video Inference Settings Node +Provides settings (draft, audio, promptUpsampling) for Runware Video Inference. +""" + +from typing import Dict, Any + + +class RunwareVideoSettings: + """Runware Video Inference Settings Node""" + + @classmethod + def INPUT_TYPES(cls): + return { + "required": {}, + "optional": { + "useDraft": ("BOOLEAN", { + "tooltip": "Enable to include draft (lower-quality preview mode) in video inference settings.", + "default": False, + }), + "draft": ("BOOLEAN", { + "tooltip": "Draft mode for lower-quality preview. Only used when 'Use Draft' is enabled.", + "default": False, + "label_on": "Enabled", + "label_off": "Disabled", + }), + "useAudio": ("BOOLEAN", { + "tooltip": "Enable to include audio (save video with audio) in video inference settings.", + "default": True, + }), + "audio": ("BOOLEAN", { + "tooltip": "Save the video with audio. Only used when 'Use Audio' is enabled.", + "default": True, + "label_on": "Enabled", + "label_off": "Disabled", + }), + "usePromptUpsampling": ("BOOLEAN", { + "tooltip": "Enable to include promptUpsampling (enhance prompt automatically) in video inference settings.", + "default": True, + }), + "promptUpsampling": ("BOOLEAN", { + "tooltip": "Enhance prompt automatically for better results. Only used when 'Use Prompt Upsampling' is enabled.", + "default": True, + "label_on": "Enabled", + "label_off": "Disabled", + }), + } + } + + RETURN_TYPES = ("RUNWAREVIDEOSETTINGS",) + RETURN_NAMES = ("settings",) + FUNCTION = "createSettings" + CATEGORY = "Runware" + DESCRIPTION = "Configure video inference settings (draft, audio, promptUpsampling) for Runware Video Inference. Connect to Runware Video Inference node." + + def createSettings(self, **kwargs) -> tuple: + """Create settings dict for Video Inference API""" + use_draft = kwargs.get("useDraft", False) + draft = kwargs.get("draft", False) + use_audio = kwargs.get("useAudio", True) + audio = kwargs.get("audio", True) + use_prompt_upsampling = kwargs.get("usePromptUpsampling", True) + prompt_upsampling = kwargs.get("promptUpsampling", True) + + settings: Dict[str, Any] = {} + + if use_draft: + settings["draft"] = bool(draft) + if use_audio: + settings["audio"] = bool(audio) + if use_prompt_upsampling: + settings["promptUpsampling"] = bool(prompt_upsampling) + + return (settings,) + + +NODE_CLASS_MAPPINGS = { + "RunwareVideoSettings": RunwareVideoSettings, +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "RunwareVideoSettings": "Runware Video Inference Settings", +} diff --git a/workflows/Runware_Image_Inference_Seedream_5.json b/workflows/Runware_Image_Inference_Seedream_5.json new file mode 100644 index 0000000..5234b84 --- /dev/null +++ b/workflows/Runware_Image_Inference_Seedream_5.json @@ -0,0 +1 @@ +{"id":"dd7adc3e-fe0d-482b-b9f2-214fbd2d73e0","revision":0,"last_node_id":5,"last_link_id":3,"nodes":[{"id":4,"type":"Runware Save Image","pos":[534.8482666015625,588.608642578125],"size":[270,318],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"Images","name":"Images","type":"STRING","widget":{"name":"Images"},"link":1},{"localized_name":"filenamePrefix","name":"filenamePrefix","type":"STRING","widget":{"name":"filenamePrefix"},"link":null},{"localized_name":"saveImage","name":"saveImage","type":"BOOLEAN","widget":{"name":"saveImage"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":null}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"dee0949f78f02adb54037e1df1cc2bf7df7b4bfe","Node name for S&R":"Runware Save Image"},"widgets_values":["","ComfyUI",true],"bgcolor":"#5345bf"},{"id":2,"type":"Runware Model Search","pos":[-332.40582275390625,567.2559204101562],"size":[270,154],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"Model Search","name":"Model Search","type":"STRING","widget":{"name":"Model Search"},"link":null},{"localized_name":"Model Architecture","name":"Model Architecture","type":"COMBO","widget":{"name":"Model Architecture"},"link":null},{"localized_name":"ModelType","name":"ModelType","type":"COMBO","widget":{"name":"ModelType"},"link":null},{"localized_name":"ModelList","name":"ModelList","type":"COMBO","widget":{"name":"ModelList"},"link":null},{"localized_name":"Use Search Value","name":"Use Search Value","type":"BOOLEAN","widget":{"name":"Use Search Value"},"link":null}],"outputs":[{"localized_name":"Runware Model","name":"Runware Model","type":"RUNWAREMODEL","links":[2]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"dee0949f78f02adb54037e1df1cc2bf7df7b4bfe","Node name for S&R":"Runware Model Search"},"widgets_values":["bytedance:seedream@5.0-lite","All","Base Model","bytedance:seedream@5.0-lite (Seedream 5.0 Lite 5.0)",false],"bgcolor":"#5345bf"},{"id":5,"type":"Runware Bytedance Provider Settings","pos":[-380.7424011230469,825.67919921875],"size":[336.4712829589844,322],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"useCameraFixed","name":"useCameraFixed","shape":7,"type":"BOOLEAN","widget":{"name":"useCameraFixed"},"link":null},{"localized_name":"cameraFixed","name":"cameraFixed","shape":7,"type":"BOOLEAN","widget":{"name":"cameraFixed"},"link":null},{"localized_name":"useMaxSequentialImages","name":"useMaxSequentialImages","shape":7,"type":"BOOLEAN","widget":{"name":"useMaxSequentialImages"},"link":null},{"localized_name":"maxSequentialImages","name":"maxSequentialImages","shape":7,"type":"INT","widget":{"name":"maxSequentialImages"},"link":null},{"localized_name":"useFastMode","name":"useFastMode","shape":7,"type":"BOOLEAN","widget":{"name":"useFastMode"},"link":null},{"localized_name":"fastMode","name":"fastMode","shape":7,"type":"BOOLEAN","widget":{"name":"fastMode"},"link":null},{"localized_name":"useAudio","name":"useAudio","shape":7,"type":"BOOLEAN","widget":{"name":"useAudio"},"link":null},{"localized_name":"audio","name":"audio","shape":7,"type":"BOOLEAN","widget":{"name":"audio"},"link":null},{"localized_name":"useDraft","name":"useDraft","shape":7,"type":"BOOLEAN","widget":{"name":"useDraft"},"link":null},{"localized_name":"draft","name":"draft","shape":7,"type":"BOOLEAN","widget":{"name":"draft"},"link":null},{"localized_name":"useOptimizePromptMode","name":"useOptimizePromptMode","shape":7,"type":"BOOLEAN","widget":{"name":"useOptimizePromptMode"},"link":null},{"localized_name":"optimizePromptMode","name":"optimizePromptMode","shape":7,"type":"COMBO","widget":{"name":"optimizePromptMode"},"link":null}],"outputs":[{"localized_name":"providerSettings","name":"providerSettings","type":"RUNWAREPROVIDERSETTINGS","links":[3]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"dee0949f78f02adb54037e1df1cc2bf7df7b4bfe","Node name for S&R":"Runware Bytedance Provider Settings"},"widgets_values":[false,false,false,1,false,false,false,false,false,false,true,"standard"],"bgcolor":"#5345bf"},{"id":1,"type":"Runware Image Inference","pos":[25.71064567565918,523.72021484375],"size":[400,1038],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"Model","name":"Model","type":"RUNWAREMODEL","link":2},{"localized_name":"Accelerator","name":"Accelerator","shape":7,"type":"RUNWAREACCELERATOR","link":null},{"localized_name":"Lora","name":"Lora","shape":7,"type":"RUNWARELORA","link":null},{"localized_name":"Outpainting","name":"Outpainting","shape":7,"type":"RUNWAREOUTPAINT","link":null},{"localized_name":"IPAdapters","name":"IPAdapters","shape":7,"type":"RUNWAREIPAdapter","link":null},{"localized_name":"ControlNet","name":"ControlNet","shape":7,"type":"RUNWARECONTROLNET","link":null},{"localized_name":"Refiner","name":"Refiner","shape":7,"type":"RUNWAREREFINER","link":null},{"localized_name":"seedImage","name":"seedImage","shape":7,"type":"IMAGE","link":null},{"localized_name":"maskImage","name":"maskImage","shape":7,"type":"MASK","link":null},{"localized_name":"Embeddings","name":"Embeddings","shape":7,"type":"RUNWAREEMBEDDING","link":null},{"localized_name":"VAE","name":"VAE","shape":7,"type":"RUNWAREVAE","link":null},{"localized_name":"referenceImages","name":"referenceImages","shape":7,"type":"RUNWAREREFERENCEIMAGES","link":null},{"localized_name":"inputs","name":"inputs","shape":7,"type":"RUNWAREIMAGEINFERENCEINPUTS","link":null},{"localized_name":"providerSettings","name":"providerSettings","shape":7,"type":"RUNWAREPROVIDERSETTINGS","link":3},{"localized_name":"safetyInputs","name":"safetyInputs","shape":7,"type":"RUNWARESAFETYINPUTS","link":null},{"localized_name":"settings","name":"settings","shape":7,"type":"RUNWARESETTINGS","link":null},{"localized_name":"ultralytics","name":"ultralytics","shape":7,"type":"RUNWAREULTRALYTICSINPUTS","link":null},{"localized_name":"positivePrompt","name":"positivePrompt","type":"STRING","widget":{"name":"positivePrompt"},"link":null},{"localized_name":"negativePrompt","name":"negativePrompt","type":"STRING","widget":{"name":"negativePrompt"},"link":null},{"localized_name":"Multi Inference Mode","name":"Multi Inference Mode","type":"BOOLEAN","widget":{"name":"Multi Inference Mode"},"link":null},{"localized_name":"Prompt Weighting","name":"Prompt Weighting","type":"COMBO","widget":{"name":"Prompt Weighting"},"link":null},{"localized_name":"dimensions","name":"dimensions","type":"COMBO","widget":{"name":"dimensions"},"link":null},{"localized_name":"width","name":"width","type":"INT","widget":{"name":"width"},"link":null},{"localized_name":"height","name":"height","type":"INT","widget":{"name":"height"},"link":null},{"localized_name":"useResolution","name":"useResolution","type":"BOOLEAN","widget":{"name":"useResolution"},"link":null},{"localized_name":"resolution","name":"resolution","type":"COMBO","widget":{"name":"resolution"},"link":null},{"localized_name":"useSteps","name":"useSteps","type":"BOOLEAN","widget":{"name":"useSteps"},"link":null},{"localized_name":"steps","name":"steps","type":"INT","widget":{"name":"steps"},"link":null},{"localized_name":"useScheduler","name":"useScheduler","type":"BOOLEAN","widget":{"name":"useScheduler"},"link":null},{"localized_name":"scheduler","name":"scheduler","type":"COMBO","widget":{"name":"scheduler"},"link":null},{"localized_name":"useCFGScale","name":"useCFGScale","type":"BOOLEAN","widget":{"name":"useCFGScale"},"link":null},{"localized_name":"cfgScale","name":"cfgScale","type":"FLOAT","widget":{"name":"cfgScale"},"link":null},{"localized_name":"useSeed","name":"useSeed","type":"BOOLEAN","widget":{"name":"useSeed"},"link":null},{"localized_name":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"useClipSkip","name":"useClipSkip","type":"BOOLEAN","widget":{"name":"useClipSkip"},"link":null},{"localized_name":"clipSkip","name":"clipSkip","type":"INT","widget":{"name":"clipSkip"},"link":null},{"localized_name":"strength","name":"strength","type":"FLOAT","widget":{"name":"strength"},"link":null},{"localized_name":"Mask Margin","name":"Mask Margin","type":"BOOLEAN","widget":{"name":"Mask Margin"},"link":null},{"localized_name":"maskMargin","name":"maskMargin","type":"INT","widget":{"name":"maskMargin"},"link":null},{"localized_name":"outputFormat","name":"outputFormat","type":"COMBO","widget":{"name":"outputFormat"},"link":null},{"localized_name":"batchSize","name":"batchSize","type":"INT","widget":{"name":"batchSize"},"link":null},{"localized_name":"acceleration","name":"acceleration","type":"COMBO","widget":{"name":"acceleration"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"STRING","links":[1]},{"localized_name":"RW-Task","name":"RW-Task","type":"RUNWARETASK","links":null}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"dee0949f78f02adb54037e1df1cc2bf7df7b4bfe","Node name for S&R":"Runware Image Inference"},"widgets_values":["A selfie of a cat, with the cat as the protagonist. The setting is twilight at the Eiffel Tower. The cat is happy, holding a piece of baklava in its paw. The photo has a slight motion blur and is slightly overexposed. From a selfie angle, with a bit of motion blur, the overall image presents a sense of calm madness. The text \\\"Seedream 5.0-lite is on runware\\\" should be written on the picture at the top in clearly visible font and crisp lettering. The image has a 4:3 aspect ratio","",false,"Disabled","Custom",2048,2048,false,"1k",false,4,false,"Default",false,6.5,false,2023295130,"randomize",true,0,0.8,false,32,"WEBP",1,"none"],"bgcolor":"#5345bf"}],"links":[[1,1,0,4,0,"STRING"],[2,2,0,1,0,"RUNWAREMODEL"],[3,5,0,1,13,"RUNWAREPROVIDERSETTINGS"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.638832468260247,"offset":[757.8341248546785,-491.73265096778175]}},"version":0.4} \ No newline at end of file diff --git a/workflows/Runware_Vectorize_Recraft.json b/workflows/Runware_Vectorize_Recraft.json new file mode 100644 index 0000000..220e241 --- /dev/null +++ b/workflows/Runware_Vectorize_Recraft.json @@ -0,0 +1 @@ +{"id":"993f4b88-acb5-4f70-968f-e3a2c9c1c5b4","revision":0,"last_node_id":19,"last_link_id":17,"nodes":[{"id":9,"type":"Runware Save Image","pos":[541.6531372070312,656.4539184570312],"size":[270,318],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"Images","name":"Images","type":"STRING","widget":{"name":"Images"},"link":15},{"localized_name":"filenamePrefix","name":"filenamePrefix","type":"STRING","widget":{"name":"filenamePrefix"},"link":null},{"localized_name":"saveImage","name":"saveImage","type":"BOOLEAN","widget":{"name":"saveImage"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":null}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"91646ada844167e36188b535ff60063735d10ca3","Node name for S&R":"Runware Save Image"},"widgets_values":["","ComfyUI",true],"bgcolor":"#5345bf"},{"id":19,"type":"Runware Provider Settings Recraft Color","pos":[-305.0177001953125,914.2234497070312],"size":[352.7818298339844,106],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"r","name":"r","shape":7,"type":"INT","widget":{"name":"r"},"link":null},{"localized_name":"g","name":"g","shape":7,"type":"INT","widget":{"name":"g"},"link":null},{"localized_name":"b","name":"b","shape":7,"type":"INT","widget":{"name":"b"},"link":null}],"outputs":[{"localized_name":"Color","name":"Color","type":"RUNWARERECRAFTCOLOR","links":[16]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"dee0949f78f02adb54037e1df1cc2bf7df7b4bfe","Node name for S&R":"Runware Provider Settings Recraft Color"},"widgets_values":[0,0,128],"bgcolor":"#5345bf"},{"id":18,"type":"Runware Recraft Provider Settings","pos":[-282.6740417480469,646.2836303710938],"size":[315.4371032714844,182],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"color1","name":"color1","shape":7,"type":"RUNWARERECRAFTCOLOR","link":null},{"localized_name":"color2","name":"color2","shape":7,"type":"RUNWARERECRAFTCOLOR","link":null},{"localized_name":"color3","name":"color3","shape":7,"type":"RUNWARERECRAFTCOLOR","link":null},{"localized_name":"color4","name":"color4","shape":7,"type":"RUNWARERECRAFTCOLOR","link":null},{"localized_name":"color5","name":"color5","shape":7,"type":"RUNWARERECRAFTCOLOR","link":null},{"localized_name":"backgroundColor","name":"backgroundColor","shape":7,"type":"RUNWARERECRAFTCOLOR","link":16},{"localized_name":"useStyleId","name":"useStyleId","shape":7,"type":"BOOLEAN","widget":{"name":"useStyleId"},"link":null},{"localized_name":"styleId","name":"styleId","shape":7,"type":"STRING","widget":{"name":"styleId"},"link":null}],"outputs":[{"localized_name":"Provider Settings","name":"Provider Settings","type":"RUNWAREPROVIDERSETTINGS","links":[17]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"dee0949f78f02adb54037e1df1cc2bf7df7b4bfe","Node name for S&R":"Runware Recraft Provider Settings"},"widgets_values":[false,""],"bgcolor":"#5345bf"},{"id":17,"type":"Runware Vectorize","pos":[72.84228515625,650.274658203125],"size":[400,300],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"Image","name":"Image","shape":7,"type":"IMAGE","link":null},{"localized_name":"providerSettings","name":"providerSettings","shape":7,"type":"RUNWAREPROVIDERSETTINGS","link":17},{"localized_name":"Model Search","name":"Model Search","type":"STRING","widget":{"name":"Model Search"},"link":null},{"localized_name":"Model Architecture","name":"Model Architecture","type":"COMBO","widget":{"name":"Model Architecture"},"link":null},{"localized_name":"Vector Model List","name":"Vector Model List","type":"COMBO","widget":{"name":"Vector Model List"},"link":null},{"localized_name":"Use Search Value","name":"Use Search Value","type":"BOOLEAN","widget":{"name":"Use Search Value"},"link":null},{"localized_name":"dimensions","name":"dimensions","shape":7,"type":"COMBO","widget":{"name":"dimensions"},"link":null},{"localized_name":"width","name":"width","shape":7,"type":"INT","widget":{"name":"width"},"link":null},{"localized_name":"height","name":"height","shape":7,"type":"INT","widget":{"name":"height"},"link":null},{"localized_name":"Use positivePrompt","name":"Use positivePrompt","shape":7,"type":"BOOLEAN","widget":{"name":"Use positivePrompt"},"link":null},{"localized_name":"positivePrompt","name":"positivePrompt","shape":7,"type":"STRING","widget":{"name":"positivePrompt"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"STRING","links":[15]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"dee0949f78f02adb54037e1df1cc2bf7df7b4bfe","Node name for S&R":"Runware Vectorize"},"widgets_values":["","Recraft","recraft:v4@vector (Recraft V4 Vector)",false,"Square HD (1024x1024)",1024,1024,true,"Retro 1970s style poster with the text 'Recraft V4'"],"bgcolor":"#5345bf"}],"links":[[15,17,0,9,0,"STRING"],[16,19,0,18,5,"RUNWARERECRAFTCOLOR"],[17,18,0,17,1,"RUNWAREPROVIDERSETTINGS"]],"groups":[],"config":{},"extra":{"ds":{"scale":1.02884607845781,"offset":[484.37043720120533,-463.73196868190934]}},"version":0.4} \ No newline at end of file diff --git a/workflows/Runware_Video_Inference_Pruna_Video.json b/workflows/Runware_Video_Inference_Pruna_Video.json new file mode 100644 index 0000000..b999498 --- /dev/null +++ b/workflows/Runware_Video_Inference_Pruna_Video.json @@ -0,0 +1 @@ +{"id":"afea0ddc-60ea-4dcc-ba99-8179aec77dd1","revision":0,"last_node_id":8,"last_link_id":6,"nodes":[{"id":3,"type":"Runware Video Model Search","pos":[-433.2157287597656,676.550048828125],"size":[287.380859375,250],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"Model Search","name":"Model Search","type":"STRING","widget":{"name":"Model Search"},"link":null},{"localized_name":"Model Architecture","name":"Model Architecture","type":"COMBO","widget":{"name":"Model Architecture"},"link":null},{"localized_name":"VideoList","name":"VideoList","type":"COMBO","widget":{"name":"VideoList"},"link":null},{"localized_name":"Use Search Value","name":"Use Search Value","type":"BOOLEAN","widget":{"name":"Use Search Value"},"link":null},{"localized_name":"useCustomDimensions","name":"useCustomDimensions","type":"COMBO","widget":{"name":"useCustomDimensions"},"link":null},{"localized_name":"Width","name":"Width","type":"INT","widget":{"name":"Width"},"link":null},{"localized_name":"Height","name":"Height","type":"INT","widget":{"name":"Height"},"link":null},{"localized_name":"useResolution","name":"useResolution","type":"BOOLEAN","widget":{"name":"useResolution"},"link":null},{"localized_name":"resolution","name":"resolution","type":"COMBO","widget":{"name":"resolution"},"link":null}],"outputs":[{"localized_name":"Runware Video Model","name":"Runware Video Model","type":"RUNWAREVIDEOMODEL","links":[1]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"dee0949f78f02adb54037e1df1cc2bf7df7b4bfe","Node name for S&R":"Runware Video Model Search"},"widgets_values":["","Pruna","prunaai:p-video@0 (P-Video)",false,"Model Default",1280,720,false,"1080p"],"bgcolor":"#5345bf"},{"id":4,"type":"SaveVideo","pos":[470.9870910644531,750.4152221679688],"size":[270,503],"flags":{},"order":5,"mode":0,"inputs":[{"localized_name":"video","name":"video","type":"VIDEO","link":2},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null},{"localized_name":"format","name":"format","type":"COMBO","widget":{"name":"format"},"link":null},{"localized_name":"codec","name":"codec","type":"COMBO","widget":{"name":"codec"},"link":null}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.46","Node name for S&R":"SaveVideo"},"widgets_values":["video/ComfyUI","auto","auto"]},{"id":8,"type":"LoadImage","pos":[-760.1270751953125,764.8264770507812],"size":[274.080078125,314],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[5]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"properties":{"cnr_id":"comfy-core","ver":"0.3.46","Node name for S&R":"LoadImage"},"widgets_values":["woman-by-car.jpg","image"]},{"id":7,"type":"Runware Video Inputs Frame Images","pos":[-775.2938232421875,1166.427490234375],"size":[331.5357360839844,190],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"image1","name":"image1","shape":7,"type":"IMAGE","link":5},{"localized_name":"image2","name":"image2","shape":7,"type":"IMAGE","link":null},{"localized_name":"image3","name":"image3","shape":7,"type":"IMAGE","link":null},{"localized_name":"image4","name":"image4","shape":7,"type":"IMAGE","link":null},{"localized_name":"frame1 position","name":"frame1 position","shape":7,"type":"STRING","widget":{"name":"frame1 position"},"link":null},{"localized_name":"frame2 position","name":"frame2 position","shape":7,"type":"STRING","widget":{"name":"frame2 position"},"link":null},{"localized_name":"frame3 position","name":"frame3 position","shape":7,"type":"STRING","widget":{"name":"frame3 position"},"link":null},{"localized_name":"frame4 position","name":"frame4 position","shape":7,"type":"STRING","widget":{"name":"frame4 position"},"link":null}],"outputs":[{"localized_name":"Video Inputs Frame Images","name":"Video Inputs Frame Images","type":"RUNWAREVIDEOINPUTSFRAMEIMAGES","links":[3]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"dee0949f78f02adb54037e1df1cc2bf7df7b4bfe","Node name for S&R":"Runware Video Inputs Frame Images"},"widgets_values":["","","",""],"bgcolor":"#5345bf"},{"id":6,"type":"Runware Video Inference Inputs","pos":[-410.7387390136719,994.8055419921875],"size":[320.0390625,290],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"Image","name":"Image","shape":7,"type":"IMAGE","link":null},{"localized_name":"Frame Images","name":"Frame Images","shape":7,"type":"RUNWAREVIDEOINPUTSFRAMEIMAGES","link":3},{"localized_name":"Audio Inputs","name":"Audio Inputs","shape":7,"type":"RUNWAREAUDIOINPUT","link":null},{"localized_name":"Speech Inputs","name":"Speech Inputs","shape":7,"type":"RUNWARESPEECHINPUT","link":null},{"localized_name":"Mask","name":"Mask","shape":7,"type":"IMAGE","link":null},{"localized_name":"Frame","name":"Frame","shape":7,"type":"IMAGE","link":null},{"localized_name":"References","name":"References","shape":7,"type":"RUNWAREVIDEOINPUTSREFERENCEIMAGES","link":null},{"localized_name":"Reference Videos","name":"Reference Videos","shape":7,"type":"RUNWAREREFERENCEVIDEOS","link":null},{"localized_name":"Reference Voices","name":"Reference Voices","shape":7,"type":"RUNWAREREFERENCEVOICES","link":null},{"localized_name":"Audio","name":"Audio","shape":7,"type":"STRING","widget":{"name":"Audio"},"link":null},{"localized_name":"Video","name":"Video","shape":7,"type":"STRING","widget":{"name":"Video"},"link":null},{"localized_name":"draftId","name":"draftId","shape":7,"type":"STRING","widget":{"name":"draftId"},"link":null},{"localized_name":"videoId","name":"videoId","shape":7,"type":"STRING","widget":{"name":"videoId"},"link":null}],"outputs":[{"localized_name":"Video Inference Inputs","name":"Video Inference Inputs","type":"RUNWAREVIDEOINFERENCEINPUTS","links":[6]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"dee0949f78f02adb54037e1df1cc2bf7df7b4bfe","Node name for S&R":"Runware Video Inference Inputs"},"widgets_values":["","","",""],"bgcolor":"#5345bf"},{"id":1,"type":"Runware Video Inference","pos":[-64.3003158569336,610.6160278320312],"size":[400,876],"flags":{},"order":4,"mode":0,"inputs":[{"localized_name":"Model","name":"Model","type":"RUNWAREVIDEOMODEL","link":1},{"localized_name":"frameImages","name":"frameImages","shape":7,"type":"RUNWAREFRAMEIMAGES","link":null},{"localized_name":"referenceImages","name":"referenceImages","shape":7,"type":"RUNWAREREFERENCEIMAGES","link":null},{"localized_name":"providerSettings","name":"providerSettings","shape":7,"type":"RUNWAREPROVIDERSETTINGS","link":null},{"localized_name":"inputAudios","name":"inputAudios","shape":7,"type":"RUNWAREINPUTAUDIOS","link":null},{"localized_name":"referenceVideos","name":"referenceVideos","shape":7,"type":"RUNWAREREFERENCEVIDEOS","link":null},{"localized_name":"inputs","name":"inputs","shape":7,"type":"RUNWAREVIDEOINFERENCEINPUTS","link":6},{"localized_name":"safetyInputs","name":"safetyInputs","shape":7,"type":"RUNWARESAFETYINPUTS","link":null},{"localized_name":"videoAdvancedFeatureInputs","name":"videoAdvancedFeatureInputs","shape":7,"type":"RUNWAREVIDEOADVANCEDFEATUREINPUTS","link":null},{"localized_name":"Accelerator","name":"Accelerator","shape":7,"type":"RUNWAREACCELERATOR","link":null},{"localized_name":"settings","name":"settings","shape":7,"type":"RUNWAREVIDEOSETTINGS","link":null},{"localized_name":"Multi Inference Mode","name":"Multi Inference Mode","type":"BOOLEAN","widget":{"name":"Multi Inference Mode"},"link":null},{"localized_name":"Prompt Weighting","name":"Prompt Weighting","type":"COMBO","widget":{"name":"Prompt Weighting"},"link":null},{"localized_name":"useDuration","name":"useDuration","type":"BOOLEAN","widget":{"name":"useDuration"},"link":null},{"localized_name":"duration","name":"duration","type":"INT","widget":{"name":"duration"},"link":null},{"localized_name":"useFps","name":"useFps","type":"BOOLEAN","widget":{"name":"useFps"},"link":null},{"localized_name":"fps","name":"fps","type":"INT","widget":{"name":"fps"},"link":null},{"localized_name":"outputFormat","name":"outputFormat","type":"COMBO","widget":{"name":"outputFormat"},"link":null},{"localized_name":"useSeed","name":"useSeed","type":"BOOLEAN","widget":{"name":"useSeed"},"link":null},{"localized_name":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"useSteps","name":"useSteps","type":"BOOLEAN","widget":{"name":"useSteps"},"link":null},{"localized_name":"steps","name":"steps","type":"INT","widget":{"name":"steps"},"link":null},{"localized_name":"useBatchSize","name":"useBatchSize","type":"BOOLEAN","widget":{"name":"useBatchSize"},"link":null},{"localized_name":"batchSize","name":"batchSize","type":"INT","widget":{"name":"batchSize"},"link":null},{"localized_name":"useSchedulers","name":"useSchedulers","type":"BOOLEAN","widget":{"name":"useSchedulers"},"link":null},{"localized_name":"scheduler","name":"scheduler","type":"COMBO","widget":{"name":"scheduler"},"link":null},{"localized_name":"useCFGScale","name":"useCFGScale","type":"BOOLEAN","widget":{"name":"useCFGScale"},"link":null},{"localized_name":"cfgScale","name":"cfgScale","type":"FLOAT","widget":{"name":"cfgScale"},"link":null},{"localized_name":"acceleration","name":"acceleration","type":"COMBO","widget":{"name":"acceleration"},"link":null},{"localized_name":"positivePrompt","name":"positivePrompt","shape":7,"type":"STRING","widget":{"name":"positivePrompt"},"link":null},{"localized_name":"negativePrompt","name":"negativePrompt","shape":7,"type":"STRING","widget":{"name":"negativePrompt"},"link":null},{"localized_name":"speechVoice","name":"speechVoice","shape":7,"type":"STRING","widget":{"name":"speechVoice"},"link":null},{"localized_name":"speechText","name":"speechText","shape":7,"type":"STRING","widget":{"name":"speechText"},"link":null}],"outputs":[{"localized_name":"VIDEO","name":"VIDEO","type":"VIDEO","links":[2]},{"localized_name":"RW-Task","name":"RW-Task","type":"RUNWARETASK","links":null},{"localized_name":"OUTPUT","name":"OUTPUT","type":"RUNWARETASK","links":null}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"dee0949f78f02adb54037e1df1cc2bf7df7b4bfe","Node name for S&R":"Runware Video Inference"},"widgets_values":[false,"Disabled",true,5,true,24,"mp4",true,1266538428,"randomize",false,20,false,1,false,"euler",false,5,"none","The character in the image turns their head and smiles warmly at the camera.","","",""],"bgcolor":"#5345bf"}],"links":[[1,3,0,1,0,"RUNWAREVIDEOMODEL"],[2,1,0,4,0,"VIDEO"],[3,7,0,6,1,"RUNWAREVIDEOINPUTSFRAMEIMAGES"],[5,8,0,7,0,"IMAGE"],[6,6,0,1,6,"RUNWAREVIDEOINFERENCEINPUTS"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.5596026867057808,"offset":[1236.3994579579808,-363.06274955379973]}},"version":0.4} \ No newline at end of file