Add video background removal and video upscaler nodes
- Add Runware Video Background Removal node with Bria support - Add Runware Video Upscaler node with Bria support - Add Runware Vectorize node for image vectorization - Add Lightricks Provider Settings node - Add Video Inference Inputs node for structured inputs - Add Input Audios and Reference Videos nodes - Update video inference with speech support and reference videos - Add new video models: OmniHuman 1/1.5, PixVerse LipSync, LTX - Update Bytedance provider settings with boolean controls - Add corresponding workflow examples
This commit is contained in:
+14
@@ -40,6 +40,13 @@ from .modules.elevenlabsProviderSettingsSections import RunwareElevenLabsProvide
|
||||
from .modules.acceleratorOptions import acceleratorOptions
|
||||
from .modules.viduProviderSettings import RunwareViduProviderSettings
|
||||
from .modules.mediaUpload import runwareMediaUpload
|
||||
from .modules.inputAudios import inputAudios
|
||||
from .modules.referenceVideos import referenceVideos
|
||||
from .modules.videoInferenceInputs import videoInferenceInputs
|
||||
from .modules.lightricksProviderSettings import RunwareLightricksProviderSettings
|
||||
from .modules.vectorize import vectorize
|
||||
from .modules.videoBgRemoval import videoBgRemoval
|
||||
from .modules.videoUpscaler import videoUpscaler
|
||||
|
||||
RUNWARE_COMFYUI_VERSION = "1.4.0 Beta"
|
||||
|
||||
@@ -94,6 +101,13 @@ NODE_CLASS_MAPPINGS = {
|
||||
"Runware Accelerator Options": acceleratorOptions,
|
||||
"Runware Vidu Provider Settings": RunwareViduProviderSettings,
|
||||
"Runware Media Upload": runwareMediaUpload,
|
||||
"Runware Input Audios": inputAudios,
|
||||
"Runware Reference Videos": referenceVideos,
|
||||
"Runware Video Inference Inputs": videoInferenceInputs,
|
||||
"Runware Lightricks Provider Settings": RunwareLightricksProviderSettings,
|
||||
"Runware Vectorize": vectorize,
|
||||
"Runware Video Background Removal": videoBgRemoval,
|
||||
"Runware Video Upscaler": videoUpscaler,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
|
||||
@@ -29,6 +29,15 @@ app.registerExtension({
|
||||
captionInput.style.outline = "none";
|
||||
captionInput.readOnly = true;
|
||||
return;
|
||||
} else if(nodeClass === RUNWARE_NODE_TYPES.MEDIAUPLOAD) {
|
||||
// Style the mediaUUID widget to show full UUID
|
||||
const mediaUUIDWidget = node.widgets.find(widget => widget.name === "mediaUUID");
|
||||
if(mediaUUIDWidget && mediaUUIDWidget.inputEl) {
|
||||
mediaUUIDWidget.inputEl.style.width = "100%";
|
||||
mediaUUIDWidget.inputEl.style.minWidth = "300px";
|
||||
mediaUUIDWidget.inputEl.style.fontSize = "11px";
|
||||
mediaUUIDWidget.inputEl.style.fontFamily = "monospace";
|
||||
}
|
||||
}
|
||||
|
||||
if(crNodeProps.colorModeOnly === true) return;
|
||||
|
||||
@@ -89,6 +89,13 @@ const RUNWARE_NODE_TYPES = {
|
||||
ELEVENLABSPROVIDERSETTINGSSECTIONS: "Runware ElevenLabs Provider Settings Sections",
|
||||
VIDUPROVIDERSETTINGS: "Runware Vidu Provider Settings",
|
||||
MEDIAUPLOAD: "Runware Media Upload",
|
||||
INPUTAUDIOS: "Runware Input Audios",
|
||||
REFERENCEVIDEOS: "Runware Reference Videos",
|
||||
VIDEOINFERENCEINPUTS: "Runware Video Inference Inputs",
|
||||
LIGHTRICKSPROVIDERSETTINGS: "Runware Lightricks Provider Settings",
|
||||
VECTORIZE: "Runware Vectorize",
|
||||
VIDEOBGREMOVAL: "Runware Video Background Removal",
|
||||
VIDEOUPSCALER: "Runware Video Upscaler",
|
||||
};
|
||||
|
||||
const RUNWARE_NODE_PROPS = {
|
||||
@@ -259,6 +266,31 @@ const RUNWARE_NODE_PROPS = {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.INPUTAUDIOS]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.REFERENCEVIDEOS]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.VIDEOINFERENCEINPUTS]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.LIGHTRICKSPROVIDERSETTINGS]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.VECTORIZE]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.VIDEOBGREMOVAL]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.VIDEOUPSCALER]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
},
|
||||
};
|
||||
|
||||
export {
|
||||
|
||||
+14
-2
@@ -47,11 +47,23 @@ function mediaUUIDHandler(msgEvent) {
|
||||
|
||||
if(mediaData.success) {
|
||||
const mediaNode = app.graph.getNodeById(mediaNodeID);
|
||||
|
||||
if(mediaNode !== null && mediaNode !== undefined) {
|
||||
// Find the mediaUUID widget specifically
|
||||
const mediaUUIDWidget = mediaNode.widgets.find(widget => widget.name === "mediaUUID");
|
||||
if(mediaUUIDWidget && mediaUUIDWidget.inputEl) {
|
||||
mediaUUIDWidget.inputEl.value = mediaUUID;
|
||||
|
||||
if(mediaUUIDWidget) {
|
||||
// Update both widget.value and inputEl.value for STRING widgets
|
||||
if(mediaUUIDWidget.value !== undefined) {
|
||||
mediaUUIDWidget.value = mediaUUID;
|
||||
}
|
||||
|
||||
if(mediaUUIDWidget.inputEl) {
|
||||
mediaUUIDWidget.inputEl.value = mediaUUID;
|
||||
// Trigger change events to update the UI
|
||||
mediaUUIDWidget.inputEl.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
mediaUUIDWidget.inputEl.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ Runware Bytedance Image Provider Settings Node
|
||||
Provides Bytedance-specific settings for image generation
|
||||
"""
|
||||
|
||||
import torch
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
class RunwareBytedanceProviderSettings:
|
||||
@@ -14,16 +13,32 @@ class RunwareBytedanceProviderSettings:
|
||||
return {
|
||||
"required": {},
|
||||
"optional": {
|
||||
"useCameraFixed": ("BOOLEAN", {
|
||||
"tooltip": "Enable to include cameraFixed parameter in provider settings",
|
||||
"default": False,
|
||||
}),
|
||||
"cameraFixed": ("BOOLEAN", {
|
||||
"tooltip": "Enable to fix camera position during video generation",
|
||||
"default": False,
|
||||
}),
|
||||
"useMaxSequentialImages": ("BOOLEAN", {
|
||||
"tooltip": "Enable to include maxSequentialImages parameter in provider settings",
|
||||
"default": False,
|
||||
}),
|
||||
"maxSequentialImages": ("INT", {
|
||||
"tooltip": "Maximum number of sequential images to generate (1-15)",
|
||||
"default": 1,
|
||||
"min": 1,
|
||||
"max": 15,
|
||||
}),
|
||||
"useFastMode": ("BOOLEAN", {
|
||||
"tooltip": "Enable to include fastMode parameter in provider settings",
|
||||
"default": False,
|
||||
}),
|
||||
"fastMode": ("BOOLEAN", {
|
||||
"tooltip": "When enabled, speeds up generation by sacrificing some effects. Default: false. RTF: 25-28 (fast) vs 35 (normal). Supported by OmniHuman 1.5.",
|
||||
"default": False,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,21 +50,31 @@ class RunwareBytedanceProviderSettings:
|
||||
def create_provider_settings(self, **kwargs) -> tuple[Dict[str, Any]]:
|
||||
"""Create Bytedance provider settings"""
|
||||
|
||||
# Get parameters
|
||||
# Get control parameters
|
||||
useCameraFixed = kwargs.get("useCameraFixed", False)
|
||||
useMaxSequentialImages = kwargs.get("useMaxSequentialImages", False)
|
||||
useFastMode = kwargs.get("useFastMode", False)
|
||||
|
||||
# Get value parameters
|
||||
cameraFixed = kwargs.get("cameraFixed", False)
|
||||
maxSequentialImages = kwargs.get("maxSequentialImages", 1)
|
||||
fastMode = kwargs.get("fastMode", False)
|
||||
|
||||
# Build settings dictionary
|
||||
# Build settings dictionary - only include what is enabled
|
||||
settings = {}
|
||||
|
||||
# Add cameraFixed only if it's true
|
||||
if cameraFixed is True:
|
||||
# Add cameraFixed only if useCameraFixed is enabled
|
||||
if useCameraFixed:
|
||||
settings["cameraFixed"] = cameraFixed
|
||||
|
||||
# Add maxSequentialImages if provided and valid
|
||||
if maxSequentialImages is not None and 1 <= maxSequentialImages <= 15:
|
||||
# Add maxSequentialImages only if useMaxSequentialImages is enabled
|
||||
if useMaxSequentialImages:
|
||||
settings["maxSequentialImages"] = maxSequentialImages
|
||||
|
||||
# Add fastMode only if useFastMode is enabled
|
||||
if useFastMode:
|
||||
settings["fastMode"] = fastMode
|
||||
|
||||
# Clean up None values
|
||||
settings = {k: v for k, v in settings.items() if v is not None}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
from .utils import runwareUtils as rwUtils
|
||||
from typing import List, Dict, Any
|
||||
|
||||
class inputAudios:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {},
|
||||
"optional": {
|
||||
"Audio1": ("STRING", {
|
||||
"tooltip": "MediaUUID for the first audio file from Runware Media Upload node.",
|
||||
}),
|
||||
"Audio2": ("STRING", {
|
||||
"tooltip": "MediaUUID for the second audio file from Runware Media Upload node.",
|
||||
}),
|
||||
"Audio3": ("STRING", {
|
||||
"tooltip": "MediaUUID for the third audio file from Runware Media Upload node.",
|
||||
}),
|
||||
"Audio4": ("STRING", {
|
||||
"tooltip": "MediaUUID for the fourth audio file from Runware Media Upload node.",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
DESCRIPTION = "Configure multiple audio inputs (mediaUUIDs) for video generation with audio synchronization."
|
||||
FUNCTION = "createInputAudios"
|
||||
RETURN_TYPES = ("RUNWAREINPUTAUDIOS",)
|
||||
RETURN_NAMES = ("Input Audios",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def createInputAudios(self, **kwargs) -> tuple[List[str]]:
|
||||
audio_list = []
|
||||
for i in range(1, 5):
|
||||
audio_key = f"Audio{i}"
|
||||
audio_uuid = kwargs.get(audio_key)
|
||||
if audio_uuid and audio_uuid.strip() != "":
|
||||
audio_list.append(audio_uuid.strip())
|
||||
return (audio_list,)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
Runware Lightricks Provider Settings Node
|
||||
Provides Lightricks-specific settings for video generation
|
||||
"""
|
||||
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
class RunwareLightricksProviderSettings:
|
||||
"""Runware Lightricks Provider Settings Node"""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {},
|
||||
"optional": {
|
||||
"generateAudio": ("BOOLEAN", {
|
||||
"tooltip": "Enable to generate audio for the video. Default: false.",
|
||||
"default": False,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("RUNWAREPROVIDERSETTINGS",)
|
||||
RETURN_NAMES = ("providerSettings",)
|
||||
FUNCTION = "create_provider_settings"
|
||||
CATEGORY = "Runware/Provider Settings"
|
||||
|
||||
def create_provider_settings(self, **kwargs) -> tuple[Dict[str, Any]]:
|
||||
"""Create Lightricks provider settings"""
|
||||
|
||||
# Get value parameters
|
||||
generateAudio = kwargs.get("generateAudio", False)
|
||||
|
||||
# Build settings dictionary
|
||||
settings = {}
|
||||
|
||||
# Add generateAudio if it's True
|
||||
if generateAudio:
|
||||
settings["generateAudio"] = generateAudio
|
||||
|
||||
return (settings,)
|
||||
|
||||
# Node class mappings
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"RunwareLightricksProviderSettings": RunwareLightricksProviderSettings,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"RunwareLightricksProviderSettings": "Runware Lightricks Provider Settings",
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ class RunwareMediaUpload:
|
||||
"tooltip": "Media tensor from ComfyUI load video or audio node",
|
||||
}),
|
||||
"mediaUUID": ("STRING", {
|
||||
"multiline": True,
|
||||
"placeholder": "Generated media UUID will appear here automatically.",
|
||||
"tooltip": "This field will be automatically populated with the generated media UUID after upload.",
|
||||
}),
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
from .utils import runwareUtils as rwUtils
|
||||
from typing import List, Dict, Any
|
||||
|
||||
class referenceVideos:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {},
|
||||
"optional": {
|
||||
"Video1": ("STRING", {
|
||||
"tooltip": "MediaUUID for the first reference video from Runware Media Upload node.",
|
||||
}),
|
||||
"Video2": ("STRING", {
|
||||
"tooltip": "MediaUUID for the second reference video from Runware Media Upload node.",
|
||||
}),
|
||||
"Video3": ("STRING", {
|
||||
"tooltip": "MediaUUID for the third reference video from Runware Media Upload node.",
|
||||
}),
|
||||
"Video4": ("STRING", {
|
||||
"tooltip": "MediaUUID for the fourth reference video from Runware Media Upload node.",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
DESCRIPTION = "Configure multiple reference video inputs (mediaUUIDs) for video generation."
|
||||
FUNCTION = "createReferenceVideos"
|
||||
RETURN_TYPES = ("RUNWAREREFERENCEVIDEOS",)
|
||||
RETURN_NAMES = ("Reference Videos",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def createReferenceVideos(self, **kwargs) -> tuple[List[str]]:
|
||||
video_list = []
|
||||
for i in range(1, 5):
|
||||
video_key = f"Video{i}"
|
||||
video_uuid = kwargs.get(video_key)
|
||||
if video_uuid and video_uuid.strip() != "":
|
||||
video_list.append(video_uuid.strip())
|
||||
return (video_list,)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
from .utils import runwareUtils as rwUtils
|
||||
import json
|
||||
|
||||
class vectorize:
|
||||
RUNWARE_VECTORIZE_MODELS = {
|
||||
"recraft:1@1": "recraft:1@1",
|
||||
"picsart:1@1": "picsart:1@1",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"Image": ("IMAGE", {
|
||||
"tooltip": "Input image to be vectorized."
|
||||
}),
|
||||
"Model": (list(cls.RUNWARE_VECTORIZE_MODELS.keys()), {
|
||||
"tooltip": "Select the vectorization model to use.",
|
||||
"default": "recraft:1@1",
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
DESCRIPTION = "Convert images to vector format using Runware's vectorization service."
|
||||
FUNCTION = "vectorizeImage"
|
||||
RETURN_TYPES = ("IMAGE", "STRING")
|
||||
RETURN_NAMES = ("IMAGE", "Vector Data")
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def vectorizeImage(self, **kwargs):
|
||||
image = kwargs.get("Image")
|
||||
modelName = kwargs.get("Model", "recraft:1@1")
|
||||
|
||||
# Get the model AIR code
|
||||
model = self.RUNWARE_VECTORIZE_MODELS.get(modelName, "recraft:1@1")
|
||||
|
||||
# Convert image to UUID
|
||||
image_uuid = rwUtils.convertTensor2IMG(image)
|
||||
|
||||
# Build the API request
|
||||
genConfig = [
|
||||
{
|
||||
"taskType": "vectorize",
|
||||
"taskUUID": rwUtils.genRandUUID(),
|
||||
"model": model,
|
||||
"inputs": {
|
||||
"image": image_uuid
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
try:
|
||||
# Debug: Print the request being sent
|
||||
print(f"[DEBUG] Sending Vectorize Request:")
|
||||
print(f"[DEBUG] Request Payload: {json.dumps(genConfig, indent=2)}")
|
||||
|
||||
genResult = rwUtils.inferenecRequest(genConfig)
|
||||
|
||||
# Debug: Print the response received
|
||||
print(f"[DEBUG] Received Vectorize Response:")
|
||||
print(f"[DEBUG] Response: {json.dumps(genResult, indent=2)}")
|
||||
|
||||
# Check for errors
|
||||
if "errors" in genResult:
|
||||
error_message = genResult["errors"][0]["message"]
|
||||
raise Exception(f"Vectorization failed: {error_message}")
|
||||
|
||||
# Extract the result
|
||||
if "data" in genResult and len(genResult["data"]) > 0:
|
||||
result_data = genResult["data"][0]
|
||||
|
||||
# Return the vectorized image URL
|
||||
if "imageURL" in result_data:
|
||||
vector_url = result_data["imageURL"]
|
||||
return (image, vector_url)
|
||||
else:
|
||||
raise Exception("imageURL not found in response")
|
||||
else:
|
||||
raise Exception("No data returned from vectorization API")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[Error] Vectorization failed: {str(e)}")
|
||||
raise e
|
||||
|
||||
# Node class mappings
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"RunwareVectorize": vectorize,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"RunwareVectorize": "Runware Vectorize",
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
from .utils import runwareUtils as rwUtils
|
||||
import json
|
||||
import comfy.model_management
|
||||
|
||||
class videoBgRemoval:
|
||||
RUNWARE_VRMBG_MODELS = {
|
||||
"bria:51@1": "bria:51@1",
|
||||
}
|
||||
|
||||
BACKGROUND_COLORS = {
|
||||
"Transparent": [0, 0, 0, 0],
|
||||
"Black": [0, 0, 0, 1],
|
||||
"White": [255, 255, 255, 0],
|
||||
"Gray": [128, 128, 128, 0],
|
||||
"Red": [255, 0, 0, 0],
|
||||
"Green": [0, 255, 0, 0],
|
||||
"Blue": [0, 0, 255, 0],
|
||||
"Yellow": [255, 255, 0, 0],
|
||||
"Cyan": [0, 255, 255, 0],
|
||||
"Magenta": [255, 0, 255, 0],
|
||||
"Orange": [255, 165, 0, 0],
|
||||
}
|
||||
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"Video": ("STRING", {
|
||||
"tooltip": "MediaUUID from Runware Media Upload node for the video to process (max 30 seconds). Supports resolution up to 16000x16000 (16K)."
|
||||
}),
|
||||
"Model": (list(cls.RUNWARE_VRMBG_MODELS.keys()), {
|
||||
"tooltip": "Select the video background removal model to use.",
|
||||
"default": "Bria Video Background Removal",
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"Background Color": (list(cls.BACKGROUND_COLORS.keys()), {
|
||||
"default": "Transparent",
|
||||
"tooltip": "Background color preset to use. Hex values are not supported.",
|
||||
}),
|
||||
"Output Format": (["mp4", "webm", "mov"], {
|
||||
"default": "mp4",
|
||||
"tooltip": "Choose the output video format.",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
DESCRIPTION = "Remove complex or moving video backgrounds in real time, isolating subjects with clean alpha channels for seamless compositing."
|
||||
FUNCTION = "removeBackground"
|
||||
RETURN_TYPES = ("VIDEO",)
|
||||
RETURN_NAMES = ("VIDEO",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def removeBackground(self, **kwargs):
|
||||
video_uuid = kwargs.get("Video")
|
||||
modelName = kwargs.get("Model", "Bria Video Background Removal")
|
||||
backgroundColor = kwargs.get("Background Color", "Transparent")
|
||||
outputFormat = kwargs.get("Output Format", "mp4")
|
||||
|
||||
# Validate mediaUUID
|
||||
if not video_uuid or video_uuid.strip() == "":
|
||||
raise ValueError("Video mediaUUID is required")
|
||||
|
||||
# Get the model AIR code
|
||||
modelAIR = self.RUNWARE_VRMBG_MODELS.get(modelName, "bria:51@1")
|
||||
|
||||
# Get background color RGBA
|
||||
rgba_color = self.BACKGROUND_COLORS.get(backgroundColor, [0, 0, 0, 0])
|
||||
|
||||
# Build the API request
|
||||
genConfig = [
|
||||
{
|
||||
"taskType": "removeBackground",
|
||||
"taskUUID": rwUtils.genRandUUID(),
|
||||
"inputs": {
|
||||
"video": video_uuid
|
||||
},
|
||||
"model": modelAIR,
|
||||
"outputFormat": outputFormat,
|
||||
"settings": {
|
||||
"rgba": rgba_color
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
try:
|
||||
# Debug: Print the request being sent
|
||||
print(f"[DEBUG] Sending Video Background Removal Request:")
|
||||
print(f"[DEBUG] Request Payload: {json.dumps(genConfig, indent=2)}")
|
||||
|
||||
genResult = rwUtils.inferenecRequest(genConfig)
|
||||
|
||||
# Debug: Print the response received
|
||||
print(f"[DEBUG] Received Video Background Removal Response:")
|
||||
print(f"[DEBUG] Response: {json.dumps(genResult, indent=2)}")
|
||||
|
||||
# Check for errors
|
||||
if "errors" in genResult:
|
||||
error_message = genResult["errors"][0]["message"]
|
||||
raise Exception(f"Video background removal failed: {error_message}")
|
||||
|
||||
# Extract task UUID for polling
|
||||
taskUUID = genConfig[0]["taskUUID"]
|
||||
|
||||
# Poll for video completion
|
||||
while True:
|
||||
# Check for interrupt before each poll
|
||||
comfy.model_management.throw_exception_if_processing_interrupted()
|
||||
|
||||
# Poll for video result
|
||||
pollResult = rwUtils.pollVideoResult(taskUUID)
|
||||
print(f"[Debugging] Poll result: {pollResult}")
|
||||
|
||||
# Check for errors first
|
||||
if pollResult and "errors" in pollResult and len(pollResult["errors"]) > 0:
|
||||
error_info = pollResult["errors"][0]
|
||||
error_message = error_info.get("message", "Unknown error")
|
||||
raise Exception(f"Video background removal failed: {error_message}")
|
||||
|
||||
if pollResult and "data" in pollResult and len(pollResult["data"]) > 0:
|
||||
video_data = pollResult["data"][0]
|
||||
|
||||
# Check status directly
|
||||
if "status" in video_data:
|
||||
status = video_data["status"]
|
||||
|
||||
if status == "success":
|
||||
if "videoURL" in video_data or "videoBase64Data" in video_data:
|
||||
videos = rwUtils.convertVideoB64List(pollResult, 1920, 1080)
|
||||
return videos
|
||||
|
||||
# If status is "processing", continue polling
|
||||
|
||||
# Check for interrupt before waiting
|
||||
comfy.model_management.throw_exception_if_processing_interrupted()
|
||||
|
||||
# Wait before next poll
|
||||
for _ in range(10): # 10 x 0.1 second = 1 second total
|
||||
comfy.model_management.throw_exception_if_processing_interrupted()
|
||||
rwUtils.time.sleep(0.1)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[Error] Video background removal failed: {str(e)}")
|
||||
raise e
|
||||
|
||||
# Node class mappings
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"RunwareVideoBgRemoval": videoBgRemoval,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"RunwareVideoBgRemoval": "Runware Video Background Removal",
|
||||
}
|
||||
|
||||
+70
-18
@@ -84,16 +84,6 @@ class txt2vid:
|
||||
"Model": ("RUNWAREVIDEOMODEL", {
|
||||
"tooltip": "Connect a Runware Video Model From Runware Video Model Search Node.",
|
||||
}),
|
||||
"positivePrompt": ("STRING", {
|
||||
"multiline": True,
|
||||
"placeholder": "Positive Prompt: a text instruction to guide the model on generating the video. It is usually a sentence or a paragraph that provides positive guidance for the task. This parameter is essential to shape the desired results.\n\nYou Can Press (Ctrl + Alt + E) To Enhance The Prompt!",
|
||||
"tooltip": "Positive Prompt: a text instruction to guide the model on generating the video. You Can Also Press (Ctrl + Alt + E) To Enhance The Prompt!"
|
||||
}),
|
||||
"negativePrompt": ("STRING", {
|
||||
"multiline": True,
|
||||
"placeholder": "Negative Prompt: a text instruction to guide the model on generating the video. It is usually a sentence or a paragraph that provides negative guidance for the task. This parameter helps to avoid certain undesired results.",
|
||||
"tooltip": "Negative Prompt: a text instruction to guide the model on generating the video."
|
||||
}),
|
||||
"Multi Inference Mode": ("BOOLEAN", {
|
||||
"tooltip": "If Enabled the node will skip the video generation process and will only return the Runware Task Object to be used in the Multi Inference Node.",
|
||||
"default": False,
|
||||
@@ -162,6 +152,16 @@ class txt2vid:
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"positivePrompt": ("STRING", {
|
||||
"multiline": True,
|
||||
"placeholder": "Positive Prompt: a text instruction to guide the model on generating the video. It is usually a sentence or a paragraph that provides positive guidance for the task. This parameter is essential to shape the desired results.\n\nYou Can Press (Ctrl + Alt + E) To Enhance The Prompt!",
|
||||
"tooltip": "Positive Prompt: a text instruction to guide the model on generating the video. You Can Also Press (Ctrl + Alt + E) To Enhance The Prompt!"
|
||||
}),
|
||||
"negativePrompt": ("STRING", {
|
||||
"multiline": True,
|
||||
"placeholder": "Negative Prompt: a text instruction to guide the model on generating the video. It is usually a sentence or a paragraph that provides negative guidance for the task. This parameter helps to avoid certain undesired results.",
|
||||
"tooltip": "Negative Prompt: a text instruction to guide the model on generating the video."
|
||||
}),
|
||||
"frameImages": ("RUNWAREFRAMEIMAGES", {
|
||||
"tooltip": "Frame images configuration from Runware Frame Images node. Allows precise control over frame positioning.",
|
||||
}),
|
||||
@@ -174,17 +174,31 @@ class txt2vid:
|
||||
"inputAudios": ("RUNWAREINPUTAUDIOS", {
|
||||
"tooltip": "Connect input audio files for video generation with audio synchronization.",
|
||||
}),
|
||||
"referenceVideos": ("RUNWAREREFERENCEVIDEOS", {
|
||||
"tooltip": "Connect reference video files for video generation.",
|
||||
}),
|
||||
"speechVoice": ("STRING", {
|
||||
"tooltip": "Voice for speech synthesis. Specify the voice to use for text-to-speech generation.",
|
||||
}),
|
||||
"speechText": ("STRING", {
|
||||
"multiline": True,
|
||||
"tooltip": "Text for speech synthesis. The text that will be converted to speech using the specified voice.",
|
||||
}),
|
||||
"inputs": ("RUNWAREVIDEOINFERENCEINPUTS", {
|
||||
"tooltip": "Connect a Runware Video Inference Inputs node to provide custom inputs like image, audio, mask, and parameters for OmniHuman 1.5 and other video models.",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, positivePrompt, negativePrompt):
|
||||
if (positivePrompt is not None and (positivePrompt == "" or len(positivePrompt) < 3 or len(positivePrompt) > 2000)):
|
||||
raise Exception(
|
||||
"Positive Prompt Must Be Between 3 And 2000 characters!")
|
||||
if (negativePrompt is not None and negativePrompt != "" and (len(negativePrompt) < 3 or len(negativePrompt) > 2000)):
|
||||
raise Exception(
|
||||
"Negative Prompt Must Be Between 3 And 2000 characters!")
|
||||
def VALIDATE_INPUTS(cls, positivePrompt=None, negativePrompt=None):
|
||||
# Only validate if prompts are provided and not empty
|
||||
if positivePrompt is not None and positivePrompt.strip() != "":
|
||||
if len(positivePrompt) < 3 or len(positivePrompt) > 2000:
|
||||
raise Exception("Positive Prompt Must Be Between 3 And 2000 characters!")
|
||||
if negativePrompt is not None and negativePrompt.strip() != "":
|
||||
if len(negativePrompt) < 3 or len(negativePrompt) > 2000:
|
||||
raise Exception("Negative Prompt Must Be Between 3 And 2000 characters!")
|
||||
return True
|
||||
|
||||
DESCRIPTION = "Generates Videos Lightning Fast With Runware Video Inference Engine."
|
||||
@@ -203,6 +217,10 @@ class txt2vid:
|
||||
frameImages = kwargs.get("frameImages", None)
|
||||
referenceImages = kwargs.get("referenceImages", None)
|
||||
inputAudios = kwargs.get("inputAudios", None)
|
||||
referenceVideos = kwargs.get("referenceVideos", None)
|
||||
speechVoice = kwargs.get("speechVoice", None)
|
||||
speechText = kwargs.get("speechText", None)
|
||||
inputs = kwargs.get("inputs", None)
|
||||
useCustomDimensions = kwargs.get("useCustomDimensions", False)
|
||||
customWidth = kwargs.get("width", 864)
|
||||
customHeight = kwargs.get("height", 480)
|
||||
@@ -235,7 +253,6 @@ class txt2vid:
|
||||
{
|
||||
"taskType": "videoInference",
|
||||
"taskUUID": rwUtils.genRandUUID(),
|
||||
"positivePrompt": positivePrompt,
|
||||
"height": height,
|
||||
"width": width,
|
||||
"model": model,
|
||||
@@ -245,6 +262,10 @@ class txt2vid:
|
||||
}
|
||||
]
|
||||
|
||||
# Only add positivePrompt if it's not empty
|
||||
if positivePrompt and positivePrompt.strip() != "":
|
||||
genConfig[0]["positivePrompt"] = positivePrompt
|
||||
|
||||
# Add fps parameter only if enabled
|
||||
if useFps:
|
||||
genConfig[0]["fps"] = fps
|
||||
@@ -276,6 +297,37 @@ class txt2vid:
|
||||
if inputAudios is not None and len(inputAudios) > 0:
|
||||
genConfig[0]["inputAudios"] = inputAudios
|
||||
print(f"[Debugging] Input audios array: {inputAudios}")
|
||||
|
||||
# Add referenceVideos if provided and not empty
|
||||
if referenceVideos is not None:
|
||||
# Handle both single mediaUUID (string) and multiple mediaUUIDs (list)
|
||||
if isinstance(referenceVideos, str) and referenceVideos.strip() != "":
|
||||
genConfig[0]["referenceVideos"] = [referenceVideos.strip()]
|
||||
print(f"[Debugging] Reference videos: {genConfig[0].get('referenceVideos', [])}")
|
||||
elif isinstance(referenceVideos, list) and len(referenceVideos) > 0:
|
||||
genConfig[0]["referenceVideos"] = referenceVideos
|
||||
print(f"[Debugging] Reference videos: {genConfig[0].get('referenceVideos', [])}")
|
||||
|
||||
# Add speech parameters if both voice and text are provided
|
||||
if speechVoice and speechVoice.strip() != "" and speechText and speechText.strip() != "":
|
||||
genConfig[0]["speech"] = {
|
||||
"voice": speechVoice.strip(),
|
||||
"text": speechText.strip()
|
||||
}
|
||||
print(f"[Debugging] Speech parameters: voice='{speechVoice.strip()}', text='{speechText.strip()[:50]}...'")
|
||||
|
||||
# Handle inputs - merge custom inputs from Video Inference Inputs node
|
||||
if inputs is not None:
|
||||
# Merge inputs from video inference inputs node
|
||||
if "inputs" not in genConfig[0]:
|
||||
genConfig[0]["inputs"] = {}
|
||||
|
||||
# Merge each input from inputs (only actual input data, not provider settings)
|
||||
for key, value in inputs.items():
|
||||
genConfig[0]["inputs"][key] = value
|
||||
|
||||
print(f"[Debugging] Video inference inputs merged: {inputs}")
|
||||
|
||||
# Handle providerSettings - extract provider name from model and merge with custom settings
|
||||
if providerSettings is not None:
|
||||
# Extract provider name from model (e.g., "pixverse:1@1" -> "pixverse")
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
from .utils import runwareUtils as rwUtils
|
||||
|
||||
class videoInferenceInputs:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {},
|
||||
"optional": {
|
||||
"Image": ("IMAGE", {
|
||||
"tooltip": "Portrait image for video generation. This will be the main subject that will speak and move in the generated video."
|
||||
}),
|
||||
"Audio": ("STRING", {
|
||||
"tooltip": "Connect the mediaUUID output from Runware Media Upload node with audio file. This audio will be synchronized with the generated video."
|
||||
}),
|
||||
"Mask": ("IMAGE", {
|
||||
"tooltip": "Mask image to specify a specific subject in the image to speak. Use white/black mask format."
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
DESCRIPTION = "Configure custom inputs for Runware Video Inference with OmniHuman 1.5 support, including image, audio, and mask inputs."
|
||||
FUNCTION = "createInputs"
|
||||
RETURN_TYPES = ("RUNWAREVIDEOINFERENCEINPUTS",)
|
||||
RETURN_NAMES = ("Video Inference Inputs",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def createInputs(self, **kwargs):
|
||||
image = kwargs.get("Image", None)
|
||||
audio = kwargs.get("Audio", None)
|
||||
mask = kwargs.get("Mask", None)
|
||||
|
||||
inputs = {}
|
||||
|
||||
if image is not None:
|
||||
image_uuid = rwUtils.convertTensor2IMG(image)
|
||||
inputs["image"] = image_uuid
|
||||
|
||||
if audio is not None and audio.strip() != "":
|
||||
inputs["audio"] = audio.strip()
|
||||
|
||||
if mask is not None:
|
||||
mask_uuid = rwUtils.convertTensor2IMG(mask)
|
||||
inputs["mask"] = mask_uuid
|
||||
|
||||
return (inputs,)
|
||||
|
||||
@@ -21,6 +21,8 @@ class videoModelSearch:
|
||||
"Seedance": [
|
||||
"bytedance:2@1 (Seedance 1.0 Pro)",
|
||||
"bytedance:1@1 (Seedance 1.0 Lite)",
|
||||
"bytedance:5@1 (OmniHuman 1)",
|
||||
"bytedance:5@2 (OmniHuman 1.5)",
|
||||
],
|
||||
"MiniMax": [
|
||||
"minimax:1@1 (MiniMax 01 Base)",
|
||||
@@ -32,6 +34,7 @@ class videoModelSearch:
|
||||
"pixverse:1@1 (PixVerse v3.5)",
|
||||
"pixverse:1@2 (PixVerse v4)",
|
||||
"pixverse:1@3 (PixVerse v4.5)",
|
||||
"pixverse:lipsync@1 (PixVerse LipSync)",
|
||||
],
|
||||
"Vidu": [
|
||||
"vidu:1@0 (Vidu Q1 Classic)",
|
||||
@@ -47,6 +50,9 @@ class videoModelSearch:
|
||||
"openai:3@1 (OpenAI Sora 3.1)",
|
||||
"openai:3@0 (OpenAI Sora 3.0)",
|
||||
],
|
||||
"Lightricks": [
|
||||
"lightricks:2@1 (LTX)",
|
||||
],
|
||||
}
|
||||
|
||||
# Model dimensions mapping
|
||||
@@ -71,6 +77,8 @@ class videoModelSearch:
|
||||
# Seedance Models
|
||||
"bytedance:2@1": {"width": 864, "height": 480}, # Seedance 1.0 Pro
|
||||
"bytedance:1@1": {"width": 864, "height": 480}, # Seedance 1.0 Lite
|
||||
"bytedance:5@1": {"width": 1024, "height": 1024}, # OmniHuman 1
|
||||
"bytedance:5@2": {"width": 1024, "height": 1024}, # OmniHuman 1.5
|
||||
|
||||
# MiniMax Models
|
||||
"minimax:1@1": {"width": 1366, "height": 768}, # MiniMax 01 Base
|
||||
@@ -82,6 +90,7 @@ class videoModelSearch:
|
||||
"pixverse:1@1": {"width": 640, "height": 360}, # PixVerse v3.5
|
||||
"pixverse:1@2": {"width": 640, "height": 360}, # PixVerse v4
|
||||
"pixverse:1@3": {"width": 640, "height": 360}, # PixVerse v4.5
|
||||
"pixverse:lipsync@1": {"width": 640, "height": 360}, # PixVerse LipSync
|
||||
|
||||
# Vidu Models
|
||||
"vidu:1@0": {"width": 1920, "height": 1080}, # Vidu Q1 Classic
|
||||
@@ -96,6 +105,9 @@ class videoModelSearch:
|
||||
# OpenAI Models
|
||||
"openai:3@1": {"width": 1280, "height": 720}, # OpenAI Sora 3.1
|
||||
"openai:3@0": {"width": 1280, "height": 720}, # OpenAI Sora 3.0
|
||||
|
||||
# Lightricks Models
|
||||
"lightricks:2@1": {"width": 1920, "height": 1080}, # Lightricks v2.1
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +132,8 @@ class videoModelSearch:
|
||||
"PixVerse",
|
||||
"Vidu",
|
||||
"Wan",
|
||||
"OpenAI"
|
||||
"OpenAI",
|
||||
"Lightricks"
|
||||
], {
|
||||
"tooltip": "Choose Video Model Architecture To Filter Results.",
|
||||
"default": "KlingAI",
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
from .utils import runwareUtils as rwUtils
|
||||
import json
|
||||
import comfy.model_management
|
||||
|
||||
class videoUpscaler:
|
||||
RUNWARE_VUPSCALER_MODELS = {
|
||||
"Bria Video Upscaler": "bria:50@1",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"Video": ("STRING", {
|
||||
"tooltip": "MediaUUID from Runware Media Upload node for the video to upscale."
|
||||
}),
|
||||
"upscaleFactor": ([2, 4], {
|
||||
"tooltip": "Integer scale factor for upscaling (2x or 4x).",
|
||||
"default": 2,
|
||||
}),
|
||||
"Model": (list(cls.RUNWARE_VUPSCALER_MODELS.keys()), {
|
||||
"tooltip": "Select the video upscaler model to use.",
|
||||
"default": "Bria Video Upscaler",
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"Output Format": (["mp4", "webm"], {
|
||||
"default": "mp4",
|
||||
"tooltip": "Choose the output video format.",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
DESCRIPTION = "Enhance the resolution and quality of your videos using Runware's advanced upscaling API."
|
||||
FUNCTION = "upscale"
|
||||
RETURN_TYPES = ("VIDEO",)
|
||||
RETURN_NAMES = ("VIDEO",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def upscale(self, **kwargs):
|
||||
video_uuid = kwargs.get("Video")
|
||||
upscaleFactor = kwargs.get("upscaleFactor", 2)
|
||||
modelName = kwargs.get("Model", "Bria Video Upscaler")
|
||||
outputFormat = kwargs.get("Output Format", "mp4")
|
||||
|
||||
# Validate mediaUUID
|
||||
if not video_uuid or video_uuid.strip() == "":
|
||||
raise ValueError("Video mediaUUID is required")
|
||||
|
||||
# Get the model AIR code
|
||||
modelAIR = self.RUNWARE_VUPSCALER_MODELS.get(modelName, "bria:50@1")
|
||||
|
||||
# Build the API request
|
||||
genConfig = [
|
||||
{
|
||||
"taskType": "upscale",
|
||||
"taskUUID": rwUtils.genRandUUID(),
|
||||
"upscaleFactor": upscaleFactor,
|
||||
"inputs": {
|
||||
"video": video_uuid
|
||||
},
|
||||
"outputType": "URL",
|
||||
"outputFormat": outputFormat.upper(),
|
||||
"model": modelAIR,
|
||||
"includeCost": True
|
||||
}
|
||||
]
|
||||
|
||||
try:
|
||||
# Debug: Print the request being sent
|
||||
print(f"[DEBUG] Sending Video Upscale Request:")
|
||||
print(f"[DEBUG] Request Payload: {json.dumps(genConfig, indent=2)}")
|
||||
|
||||
genResult = rwUtils.inferenecRequest(genConfig)
|
||||
|
||||
# Debug: Print the response received
|
||||
print(f"[DEBUG] Received Video Upscale Response:")
|
||||
print(f"[DEBUG] Response: {json.dumps(genResult, indent=2)}")
|
||||
|
||||
# Check for errors
|
||||
if "errors" in genResult:
|
||||
error_message = genResult["errors"][0]["message"]
|
||||
raise Exception(f"Video upscale failed: {error_message}")
|
||||
|
||||
# Extract task UUID for polling
|
||||
taskUUID = genConfig[0]["taskUUID"]
|
||||
|
||||
# Poll for video completion
|
||||
while True:
|
||||
# Check for interrupt before each poll
|
||||
comfy.model_management.throw_exception_if_processing_interrupted()
|
||||
|
||||
# Poll for video result
|
||||
pollResult = rwUtils.pollVideoResult(taskUUID)
|
||||
print(f"[Debugging] Poll result: {pollResult}")
|
||||
|
||||
# Check for errors first
|
||||
if pollResult and "errors" in pollResult and len(pollResult["errors"]) > 0:
|
||||
error_info = pollResult["errors"][0]
|
||||
error_message = error_info.get("message", "Unknown error")
|
||||
raise Exception(f"Video upscale failed: {error_message}")
|
||||
|
||||
if pollResult and "data" in pollResult and len(pollResult["data"]) > 0:
|
||||
video_data = pollResult["data"][0]
|
||||
|
||||
# Check status directly
|
||||
if "status" in video_data:
|
||||
status = video_data["status"]
|
||||
|
||||
if status == "success":
|
||||
if "videoURL" in video_data or "videoBase64Data" in video_data:
|
||||
videos = rwUtils.convertVideoB64List(pollResult, 1920, 1080)
|
||||
return videos
|
||||
|
||||
# If status is "processing", continue polling
|
||||
|
||||
# Check for interrupt before waiting
|
||||
comfy.model_management.throw_exception_if_processing_interrupted()
|
||||
|
||||
# Wait before next poll
|
||||
for _ in range(10): # 10 x 0.1 second = 1 second total
|
||||
comfy.model_management.throw_exception_if_processing_interrupted()
|
||||
rwUtils.time.sleep(0.1)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[Error] Video upscale failed: {str(e)}")
|
||||
raise e
|
||||
|
||||
# Node class mappings
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"RunwareVideoUpscaler": videoUpscaler,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"RunwareVideoUpscaler": "Runware Video Upscaler",
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"id":"7493d64d-0c0c-40ca-a1df-816552f0526b","revision":0,"last_node_id":6,"last_link_id":3,"nodes":[{"id":3,"type":"LoadVideo","pos":[252.06771850585938,646.0390625],"size":[274.080078125,279.56005859375],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"file","name":"file","type":"COMBO","widget":{"name":"file"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"VIDEO","name":"VIDEO","type":"VIDEO","links":[3]}],"properties":{"cnr_id":"comfy-core","ver":"0.3.46","Node name for S&R":"LoadVideo"},"widgets_values":["test_video.mp4","image"]},{"id":6,"type":"Runware Media Upload","pos":[558.8807373046875,651.7319946289062],"size":[400,200],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"media","name":"media","shape":7,"type":"VIDEO,AUDIO","link":3},{"localized_name":"mediaUUID","name":"mediaUUID","shape":7,"type":"STRING","widget":{"name":"mediaUUID"},"link":null}],"outputs":[{"localized_name":"mediaUUID","name":"mediaUUID","type":"STRING","links":null}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"16016793b1e66f9b7bf364643bdf36447a35d5c9","Node name for S&R":"Runware Media Upload"},"widgets_values":["254f37d6-98dc-4333-a530-232ea5847cce"],"bgcolor":"#5345bf"}],"links":[[3,3,0,6,0,"VIDEO,AUDIO"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.8264462809917354,"offset":[439.5536367488321,-167.09876328463446]}},"version":0.4}
|
||||
{"id":"7493d64d-0c0c-40ca-a1df-816552f0526b","revision":0,"last_node_id":11,"last_link_id":8,"nodes":[{"id":10,"type":"LoadVideo","pos":[115.29751586914062,485.1632995605469],"size":[274.080078125,279.56005859375],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"file","name":"file","type":"COMBO","widget":{"name":"file"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"VIDEO","name":"VIDEO","type":"VIDEO","links":[8]}],"properties":{"cnr_id":"comfy-core","ver":"0.3.46","Node name for S&R":"LoadVideo"},"widgets_values":["test_video.mp4","image"]},{"id":11,"type":"Runware Media Upload","pos":[448.4990234375,623.826416015625],"size":[270,58],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"media","name":"media","shape":7,"type":"VIDEO,AUDIO","link":8},{"localized_name":"mediaUUID","name":"mediaUUID","shape":7,"type":"STRING","widget":{"name":"mediaUUID"},"link":null}],"outputs":[{"localized_name":"mediaUUID","name":"mediaUUID","type":"STRING","links":null}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"1c7da18f11d51514140944e0f9f90e62ae99572c","Node name for S&R":"Runware Media Upload"},"widgets_values":["254f37d6-98dc-4333-a530-232ea5847cce"],"bgcolor":"#5345bf"}],"links":[[8,10,0,11,0,"VIDEO,AUDIO"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.8264462809917354,"offset":[453.6411562800821,-175.4364195346344]}},"version":0.4}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"id":"993f4b88-acb5-4f70-968f-e3a2c9c1c5b4","revision":0,"last_node_id":5,"last_link_id":5,"nodes":[{"id":3,"type":"SaveImage","pos":[446.1082458496094,502.5049743652344],"size":[270,270.0000305175781],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":5},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.46"},"widgets_values":["ComfyUI"]},{"id":4,"type":"LoadImage","pos":[-162.27017211914062,506.9244384765625],"size":[274.080078125,314.0000305175781],"flags":{},"order":0,"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":[4]},{"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":["bulldog_1.webp","image"]},{"id":5,"type":"Runware Vectorize","pos":[138.47059631347656,530.4171142578125],"size":[270,78],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"Image","name":"Image","type":"IMAGE","link":4},{"localized_name":"Model","name":"Model","type":"COMBO","widget":{"name":"Model"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[5]},{"localized_name":"Vector Data","name":"Vector Data","type":"STRING","links":null}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"1c7da18f11d51514140944e0f9f90e62ae99572c","Node name for S&R":"Runware Vectorize"},"widgets_values":["picsart:1@1"],"bgcolor":"#5345bf"}],"links":[[4,4,0,5,0,"IMAGE"],[5,5,0,3,0,"IMAGE"]],"groups":[],"config":{},"extra":{"ds":{"scale":1.02884607845781,"offset":[636.1817070868053,-324.5220431776123]}},"version":0.4}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"id":"a468db07-531a-4f8b-8513-003107cbfa22","revision":0,"last_node_id":5,"last_link_id":3,"nodes":[{"id":3,"type":"Runware Media Upload","pos":[92.27204895019531,542.3822021484375],"size":[270,58],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"media","name":"media","shape":7,"type":"VIDEO,AUDIO","link":1},{"localized_name":"mediaUUID","name":"mediaUUID","shape":7,"type":"STRING","widget":{"name":"mediaUUID"},"link":null}],"outputs":[{"localized_name":"mediaUUID","name":"mediaUUID","type":"STRING","links":[2]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"1c7da18f11d51514140944e0f9f90e62ae99572c","Node name for S&R":"Runware Media Upload"},"widgets_values":["b42cc934-5f2a-4b4f-b33d-d838433ce22e"],"bgcolor":"#5345bf"},{"id":4,"type":"LoadVideo","pos":[-223.58924865722656,531.5103759765625],"size":[274.080078125,442.0882263183594],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"file","name":"file","type":"COMBO","widget":{"name":"file"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"VIDEO","name":"VIDEO","type":"VIDEO","links":[1]}],"properties":{"cnr_id":"comfy-core","ver":"0.3.46","Node name for S&R":"LoadVideo"},"widgets_values":["backgroundRemoval.mp4","image"]},{"id":5,"type":"SaveVideo","pos":[443.1638488769531,554.9398803710938],"size":[270,460.60870361328125],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"video","name":"video","type":"VIDEO","link":3},{"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":2,"type":"Runware Video Background Removal","pos":[74.94189453125,660.0944213867188],"size":[333.1080017089844,130],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"Video","name":"Video","type":"STRING","widget":{"name":"Video"},"link":2},{"localized_name":"Model","name":"Model","type":"COMBO","widget":{"name":"Model"},"link":null},{"localized_name":"Background Color","name":"Background Color","shape":7,"type":"COMBO","widget":{"name":"Background Color"},"link":null},{"localized_name":"Output Format","name":"Output Format","shape":7,"type":"COMBO","widget":{"name":"Output Format"},"link":null}],"outputs":[{"localized_name":"VIDEO","name":"VIDEO","type":"VIDEO","links":[3]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"1c7da18f11d51514140944e0f9f90e62ae99572c","Node name for S&R":"Runware Video Background Removal"},"widgets_values":["","bria:51@1","Magenta","mp4"],"bgcolor":"#5345bf"}],"links":[[1,4,0,3,0,"VIDEO,AUDIO"],[2,3,0,2,0,"STRING"],[3,2,0,5,0,"VIDEO"]],"groups":[],"config":{},"extra":{"ds":{"scale":1.02884607845781,"offset":[636.1646218051795,-324.5220431776123]}},"version":0.4}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"id":"a468db07-531a-4f8b-8513-003107cbfa22","revision":0,"last_node_id":6,"last_link_id":5,"nodes":[{"id":5,"type":"SaveVideo","pos":[443.1638488769531,554.9398803710938],"size":[270,460.60870361328125],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"video","name":"video","type":"VIDEO","link":5},{"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":3,"type":"Runware Media Upload","pos":[92.27204895019531,542.3822021484375],"size":[270,58],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"media","name":"media","shape":7,"type":"VIDEO,AUDIO","link":1},{"localized_name":"mediaUUID","name":"mediaUUID","shape":7,"type":"STRING","widget":{"name":"mediaUUID"},"link":null}],"outputs":[{"localized_name":"mediaUUID","name":"mediaUUID","type":"STRING","links":[4]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"1c7da18f11d51514140944e0f9f90e62ae99572c","Node name for S&R":"Runware Media Upload"},"widgets_values":["745c761c-0a2f-4d95-b043-06e10b822391"],"bgcolor":"#5345bf"},{"id":6,"type":"Runware Video Upscaler","pos":[103.33763885498047,673.7623901367188],"size":[270,130],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"Video","name":"Video","type":"STRING","widget":{"name":"Video"},"link":4},{"localized_name":"upscaleFactor","name":"upscaleFactor","type":"COMBO","widget":{"name":"upscaleFactor"},"link":null},{"localized_name":"Model","name":"Model","type":"COMBO","widget":{"name":"Model"},"link":null},{"localized_name":"Output Format","name":"Output Format","shape":7,"type":"COMBO","widget":{"name":"Output Format"},"link":null}],"outputs":[{"localized_name":"VIDEO","name":"VIDEO","type":"VIDEO","links":[5]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"1c7da18f11d51514140944e0f9f90e62ae99572c","Node name for S&R":"Runware Video Upscaler"},"widgets_values":["",2,"Bria Video Upscaler","mp4"],"bgcolor":"#5345bf"},{"id":4,"type":"LoadVideo","pos":[-223.58924865722656,531.5103759765625],"size":[274.080078125,442.0882263183594],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"file","name":"file","type":"COMBO","widget":{"name":"file"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"VIDEO","name":"VIDEO","type":"VIDEO","links":[1]}],"properties":{"cnr_id":"comfy-core","ver":"0.3.46","Node name for S&R":"LoadVideo"},"widgets_values":["c3896e44-4869-4142-9f02-6d7b967d3a1e.mp4","image"]}],"links":[[1,4,0,3,0,"VIDEO,AUDIO"],[4,3,0,6,0,"STRING"],[5,6,0,5,0,"VIDEO"]],"groups":[],"config":{},"extra":{"ds":{"scale":1.02884607845781,"offset":[636.5234127193203,-324.5220431776123]}},"version":0.4}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user