Added support for SkyReels
This commit is contained in:
@@ -260,6 +260,14 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"Runware Text Model Search": "Runware Text Model",
|
||||
"Runware Image Inference Settings Color Palette": "Runware Image Inference Color Palette",
|
||||
"Runware Video Transcription": "Runware Video Caption",
|
||||
"Runware Video Inputs References": "Runware Video Inference Inputs Reference Images",
|
||||
"Runware Video Inference Inputs Reference Images": "Runware Video Inference Inputs Reference Images",
|
||||
"Runware Reference Voices": "Runware Video Inference Inputs Reference Voices",
|
||||
"Runware Video Inference Inputs Reference Voices": "Runware Video Inference Inputs Reference Voices",
|
||||
"Runware Reference Videos": "Runware Video Inference Inputs Reference Videos",
|
||||
"Runware Video Inference Inputs Reference Videos": "Runware Video Inference Inputs Reference Videos",
|
||||
"Runware Reference Audios": "Runware Video Inference Inputs Reference Audios",
|
||||
"Runware Video Inference Inputs Reference Audios": "Runware Video Inference Inputs Reference Audios",
|
||||
}
|
||||
|
||||
WEB_DIRECTORY = "./clientlibs"
|
||||
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { api } from "../../scripts/api.js";
|
||||
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, saveTextHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, textModelSearchFilterHandler, vectorizeModelSearchFilterHandler, vectorizeToggleHandler, useParameterToggleHandler, imageInferenceToggleHandler, imageInferenceAdvancedFeaturesToggleHandler, watermarkAdvancedFeatureToggleHandler, videoInferenceSpeechInputToggleHandler, regionalPromptingRegionsToggleHandler, upscalerToggleHandler, imageUpscalerSettingsToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, textInferenceSettingsToggleHandler, videoSettingsToggleHandler, videoInferenceSettingsTtsToggleHandler, videoInferenceSettingsActiveSpeakerDetectionToggleHandler, videoInferenceSettingsActiveSpeakerBoundingBoxesToggleHandler, videoInferenceSettingsSegmentsToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, viduProviderSettingsToggleHandler, sourcefulProviderSettingsToggleHandler, sourcefulProviderSettingsFontsToggleHandler, threeDInferenceToggleHandler, threeDInferenceSettingsToggleHandler, threeDInferenceSettingsLatToggleHandler, ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, safetyInputsToggleHandler, imageInferenceSettingsColorPaletteToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler, audioInferenceSpeechVoicesToggleHandler } from "./utils.js";
|
||||
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, saveTextHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, textModelSearchFilterHandler, vectorizeModelSearchFilterHandler, vectorizeToggleHandler, useParameterToggleHandler, imageInferenceToggleHandler, imageInferenceAdvancedFeaturesToggleHandler, watermarkAdvancedFeatureToggleHandler, videoInferenceSpeechInputToggleHandler, regionalPromptingRegionsToggleHandler, upscalerToggleHandler, imageUpscalerSettingsToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, textInferenceSettingsToggleHandler, videoSettingsToggleHandler, videoInferenceSettingsTtsToggleHandler, videoInferenceSettingsActiveSpeakerDetectionToggleHandler, videoInferenceSettingsActiveSpeakerBoundingBoxesToggleHandler, videoInferenceSettingsSegmentsToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, viduProviderSettingsToggleHandler, sourcefulProviderSettingsToggleHandler, sourcefulProviderSettingsFontsToggleHandler, threeDInferenceToggleHandler, threeDInferenceSettingsToggleHandler, threeDInferenceSettingsLatToggleHandler, ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, safetyInputsToggleHandler, imageInferenceSettingsColorPaletteToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler, audioInferenceSpeechVoicesToggleHandler, referenceVideosToggleHandler } from "./utils.js";
|
||||
import { RUNWARE_NODE_TYPES, RUNWARE_NODE_PROPS, SEARCH_TERMS } from "./types.js";
|
||||
|
||||
const nodeInitList = [];
|
||||
@@ -161,6 +161,9 @@ app.registerExtension({
|
||||
videoAdvancedFeatureInputsToggleHandler(node);
|
||||
} else if(nodeClass === RUNWARE_NODE_TYPES.AUDIOINFERENCEINPUTS) {
|
||||
audioInferenceInputsToggleHandler(node);
|
||||
} else if(nodeClass === RUNWARE_NODE_TYPES.REFERENCEVIDEOS ||
|
||||
nodeClass === RUNWARE_NODE_TYPES.REFERENCEVIDEOS_LEGACY) {
|
||||
referenceVideosToggleHandler(node);
|
||||
} else if(nodeClass === RUNWARE_NODE_TYPES.THREEDINFERENCE) {
|
||||
threeDInferenceToggleHandler(node);
|
||||
} else if(nodeClass === RUNWARE_NODE_TYPES.THREEDINFERENCESETTINGS) {
|
||||
|
||||
@@ -2838,6 +2838,9 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
|
||||
"Pruna": [
|
||||
"prunaai:p-video@0 (P-Video)",
|
||||
],
|
||||
"SkyReels": [
|
||||
"skywork:skyreels@v4 (SkyReels V4)",
|
||||
],
|
||||
};
|
||||
|
||||
const MODEL_DIMENSIONS = {
|
||||
@@ -2930,6 +2933,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
|
||||
"prunaai:p-video@0": {"width": 1280, "height": 720},
|
||||
"heygen:avatar@4": {"width": 1280, "height": 720},
|
||||
"heygen:video-agent@0": {"width": 1280, "height": 720},
|
||||
"skywork:skyreels@v4": {"width": 1280, "height": 720},
|
||||
};
|
||||
|
||||
const MODEL_RESOLUTIONS = {
|
||||
@@ -3022,6 +3026,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
|
||||
"prunaai:p-video@0": "720p",
|
||||
"heygen:avatar@4": "720p",
|
||||
"heygen:video-agent@0": "720p",
|
||||
"skywork:skyreels@v4": "720p",
|
||||
};
|
||||
|
||||
const DEFAULT_DIMENSIONS = {"width": 1024, "height": 576};
|
||||
@@ -4851,6 +4856,74 @@ function audioInferenceSpeechVoicesToggleHandler(voicesNode) {
|
||||
}
|
||||
}
|
||||
|
||||
function referenceVideosToggleHandler(referenceVideosNode) {
|
||||
if (!referenceVideosNode?.widgets) return;
|
||||
|
||||
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
||||
if (!useWidget || !paramWidget) return;
|
||||
|
||||
function toggleEnabled() {
|
||||
const enabled = useWidget.value === true;
|
||||
|
||||
if (paramWidget.inputEl) {
|
||||
paramWidget.inputEl.disabled = !enabled;
|
||||
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
|
||||
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
|
||||
paramWidget.inputEl.readOnly = !enabled;
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
paramWidget.disabled = !enabled;
|
||||
|
||||
if (!paramWidget.inputEl && paramName) {
|
||||
const nodeElement = referenceVideosNode.htmlElements?.widgetsContainer || referenceVideosNode.htmlElements;
|
||||
if (nodeElement) {
|
||||
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
|
||||
if (input) {
|
||||
input.disabled = !enabled;
|
||||
input.style.opacity = enabled ? "1" : "0.5";
|
||||
input.style.cursor = enabled ? "text" : "not-allowed";
|
||||
input.readOnly = !enabled;
|
||||
if (input.tagName === "SELECT") {
|
||||
input.style.pointerEvents = enabled ? "auto" : "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
referenceVideosNode.setDirtyCanvas(true);
|
||||
}
|
||||
|
||||
appendWidgetCB(useWidget, () => {
|
||||
setTimeout(toggleEnabled, 50);
|
||||
});
|
||||
|
||||
setTimeout(toggleEnabled, 100);
|
||||
}
|
||||
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
const useVideoWidget = referenceVideosNode.widgets.find((w) => w && w.name === `useVideo${i}`);
|
||||
const videoWidget = referenceVideosNode.widgets.find((w) => w && w.name === `Video${i}`);
|
||||
const tagWidget = referenceVideosNode.widgets.find((w) => w && w.name === `Tag${i}`);
|
||||
const typeWidget = referenceVideosNode.widgets.find((w) => w && w.name === `Type${i}`);
|
||||
|
||||
if (useVideoWidget && videoWidget) {
|
||||
toggleWidgetState(useVideoWidget, videoWidget, `Video${i}`);
|
||||
}
|
||||
if (useVideoWidget && tagWidget) {
|
||||
toggleWidgetState(useVideoWidget, tagWidget, `Tag${i}`);
|
||||
}
|
||||
if (useVideoWidget && typeWidget) {
|
||||
toggleWidgetState(useVideoWidget, typeWidget, `Type${i}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
notifyUser,
|
||||
promptEnhanceHandler,
|
||||
@@ -4919,6 +4992,7 @@ export {
|
||||
videoAdvancedFeatureInputsToggleHandler,
|
||||
audioInferenceInputsToggleHandler,
|
||||
audioInferenceSpeechVoicesToggleHandler,
|
||||
referenceVideosToggleHandler,
|
||||
};
|
||||
|
||||
function googleProviderSettingsToggleHandler(googleNode) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List
|
||||
from typing import Any, Dict, List
|
||||
from .utils import runwareUtils as rwUtils
|
||||
|
||||
|
||||
@@ -13,30 +13,67 @@ class referenceVideos:
|
||||
|
||||
for i in range(1, cls.MAX_VIDEOS + 1):
|
||||
ordinal = rwUtils.getOrdinal(i)
|
||||
optionalInputs[f"useVideo{i}"] = ("BOOLEAN", {
|
||||
"default": False,
|
||||
"tooltip": f"Enable to include the {ordinal} reference video.",
|
||||
})
|
||||
optionalInputs[f"Video{i}"] = ("STRING", {
|
||||
"tooltip": f"MediaUUID for the {ordinal} reference video from Runware Media Upload node.",
|
||||
})
|
||||
optionalInputs[f"Tag{i}"] = ("STRING", {
|
||||
"default": "",
|
||||
"tooltip": f"Optional tag for the {ordinal} reference video (e.g., @video{i}). Must be used in the prompt.",
|
||||
})
|
||||
optionalInputs[f"Type{i}"] = ("STRING", {
|
||||
"default": "reference",
|
||||
"tooltip": (
|
||||
f"Optional type for the {ordinal} reference video. "
|
||||
"For example: reference or extend."
|
||||
),
|
||||
})
|
||||
|
||||
return {
|
||||
"required": {},
|
||||
"optional": optionalInputs
|
||||
}
|
||||
|
||||
DESCRIPTION = "Configure multiple reference video inputs (mediaUUIDs) for video generation."
|
||||
DESCRIPTION = (
|
||||
"Configure multiple reference video inputs (mediaUUIDs) for video generation, "
|
||||
"with optional tag and type per reference."
|
||||
)
|
||||
FUNCTION = "createReferenceVideos"
|
||||
RETURN_TYPES = ("RUNWAREREFERENCEVIDEOS",)
|
||||
RETURN_NAMES = ("Reference Videos",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def createReferenceVideos(self, **kwargs) -> tuple[List[str]]:
|
||||
"""Create list of reference video UUIDs"""
|
||||
videoList = []
|
||||
def createReferenceVideos(self, **kwargs) -> tuple[List[Any]]:
|
||||
"""Create list of reference video entries (string UUIDs or objects with tag/type)."""
|
||||
videoList: List[Any] = []
|
||||
|
||||
for i in range(1, self.MAX_VIDEOS + 1):
|
||||
useKey = f"useVideo{i}"
|
||||
videoKey = f"Video{i}"
|
||||
tagKey = f"Tag{i}"
|
||||
typeKey = f"Type{i}"
|
||||
useVideo = bool(kwargs.get(useKey, False))
|
||||
videoUuid = kwargs.get(videoKey)
|
||||
tagValue = (kwargs.get(tagKey) or "").strip()
|
||||
typeValue = (kwargs.get(typeKey) or "reference").strip()
|
||||
|
||||
if videoUuid and videoUuid.strip() != "":
|
||||
videoList.append(videoUuid.strip())
|
||||
if useVideo and videoUuid and videoUuid.strip() != "":
|
||||
normalized_video = videoUuid.strip()
|
||||
|
||||
# Backward compatible payload:
|
||||
# - If tag/type are not provided, keep legacy string entry.
|
||||
# - If tag or non-default type is provided, emit object entry.
|
||||
if tagValue or typeValue != "reference":
|
||||
entry: Dict[str, str] = {"video": normalized_video}
|
||||
if tagValue:
|
||||
entry["tag"] = tagValue
|
||||
if typeValue:
|
||||
entry["type"] = typeValue
|
||||
videoList.append(entry)
|
||||
else:
|
||||
videoList.append(normalized_video)
|
||||
|
||||
return (videoList,)
|
||||
|
||||
@@ -158,7 +158,7 @@ def getCustomEndpoint():
|
||||
custom_endpoint = os.getenv("RUNWARE_CUSTOM_ENDPOINT")
|
||||
if custom_endpoint and isinstance(custom_endpoint, str):
|
||||
return custom_endpoint
|
||||
return "https://api.runware.ai/v1"
|
||||
return "https://api.runware.dev/v1"
|
||||
|
||||
SESSION_TIMEOUT = getTimeout()
|
||||
RUNWARE_API_KEY = getAPIKey()
|
||||
|
||||
@@ -14,10 +14,18 @@ class videoInputsReferences:
|
||||
for i in range(1, cls.MAX_REFERENCES + 1):
|
||||
ordinal = rwUtils.getOrdinal(i)
|
||||
optionalInputs[f"Image{i}"] = ("IMAGE", {
|
||||
"tooltip": f"{ordinal.capitalize()} reference image.",
|
||||
"tooltip": f"{ordinal.capitalize()} reference image (primary image for this reference entry).",
|
||||
})
|
||||
optionalInputs[f"Tag{i}"] = ("STRING", {
|
||||
"tooltip": f"Optional tag for the {ordinal} reference (e.g., @image{i}, @Actor-1).",
|
||||
"default": "",
|
||||
})
|
||||
optionalInputs[f"Type{i}"] = ("STRING", {
|
||||
"tooltip": f"Type for the {ordinal} reference (e.g., 'asset'). Leave empty to omit.",
|
||||
"tooltip": f"Type for the {ordinal} reference (e.g., grid or image).",
|
||||
"default": "",
|
||||
})
|
||||
optionalInputs[f"Audio{i}"] = ("STRING", {
|
||||
"tooltip": f"Optional audio URL/mediaUUID for the {ordinal} reference (supported for type=image).",
|
||||
"default": "",
|
||||
})
|
||||
|
||||
@@ -26,35 +34,57 @@ class videoInputsReferences:
|
||||
"optional": optionalInputs
|
||||
}
|
||||
|
||||
DESCRIPTION = "Configure multiple reference images with optional types for video inference inputs."
|
||||
DESCRIPTION = (
|
||||
"Configure multiple reference image entries for video inference inputs, "
|
||||
"with optional tag, type, images list, and audio per entry."
|
||||
)
|
||||
FUNCTION = "createReferences"
|
||||
RETURN_TYPES = ("RUNWAREVIDEOINPUTSREFERENCEIMAGES",)
|
||||
RETURN_NAMES = ("Video Inputs Reference Images",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def createReferences(self, **kwargs) -> tuple[List[Dict[str, Any]]]:
|
||||
"""Create list of reference objects from provided parameters"""
|
||||
def createReferences(self, **kwargs) -> tuple[List[Any]]:
|
||||
"""Create list of reference entries from provided parameters."""
|
||||
references = []
|
||||
|
||||
for i in range(1, self.MAX_REFERENCES + 1):
|
||||
imageKey = f"Image{i}"
|
||||
tagKey = f"Tag{i}"
|
||||
typeKey = f"Type{i}"
|
||||
audioKey = f"Audio{i}"
|
||||
|
||||
image = kwargs.get(imageKey)
|
||||
refType = kwargs.get(typeKey, "")
|
||||
refTag = (kwargs.get(tagKey) or "").strip()
|
||||
refType = (kwargs.get(typeKey) or "").strip()
|
||||
refAudio = (kwargs.get(audioKey) or "").strip()
|
||||
|
||||
if image is not None:
|
||||
reference = self._createReference(image, refType)
|
||||
reference = self._createReference(image, refTag, refType, refAudio)
|
||||
references.append(reference)
|
||||
|
||||
return (references,)
|
||||
|
||||
def _createReference(self, image, refType):
|
||||
"""Create reference entry (API expects direct strings)"""
|
||||
def _createReference(self, image, refTag: str, refType: str, refAudio: str):
|
||||
"""
|
||||
Backward compatible behavior:
|
||||
- If no extra metadata is provided, return legacy string entry.
|
||||
- If tag/type/images/audio are provided, return object entry.
|
||||
"""
|
||||
imageUrl = rwUtils.convertTensor2IMG(image)
|
||||
# API expects referenceImages to be a list of strings (UUID/URL/data URI)
|
||||
# so we return the converted string directly.
|
||||
return imageUrl
|
||||
images = [imageUrl]
|
||||
|
||||
has_extended_fields = bool(refTag or refType or refAudio or len(images) > 1)
|
||||
if not has_extended_fields:
|
||||
return imageUrl
|
||||
|
||||
entry: Dict[str, Any] = {"images": images}
|
||||
if refTag:
|
||||
entry["tag"] = refTag
|
||||
if refType:
|
||||
entry["type"] = refType
|
||||
if refAudio:
|
||||
entry["audio"] = refAudio
|
||||
return entry
|
||||
|
||||
|
||||
# Node class mappings
|
||||
|
||||
@@ -134,6 +134,9 @@ class videoModelSearch:
|
||||
"Pruna": [
|
||||
"prunaai:p-video@0 (P-Video)",
|
||||
],
|
||||
"SkyReels": [
|
||||
"skywork:skyreels@v4 (SkyReels V4)",
|
||||
],
|
||||
}
|
||||
|
||||
# Model dimensions mapping
|
||||
@@ -268,6 +271,9 @@ class videoModelSearch:
|
||||
# HeyGen Models (Model ID: heygen-avatar-iv)
|
||||
"heygen:avatar@4": {"width": 1280, "height": 720},
|
||||
"heygen:video-agent@0": {"width": 1280, "height": 720},
|
||||
|
||||
# SkyReels Models
|
||||
"skywork:skyreels@v4": {"width": 1280, "height": 720},
|
||||
}
|
||||
|
||||
# Model resolutions mapping
|
||||
@@ -402,6 +408,9 @@ class videoModelSearch:
|
||||
# HeyGen Models
|
||||
"heygen:avatar@4": "720p",
|
||||
"heygen:video-agent@0": "720p",
|
||||
|
||||
# SkyReels Models
|
||||
"skywork:skyreels@v4": "720p",
|
||||
}
|
||||
|
||||
MODEL_ARCHITECTURES = [
|
||||
@@ -427,6 +436,7 @@ class videoModelSearch:
|
||||
"xAI",
|
||||
"VEED",
|
||||
"Pruna",
|
||||
"SkyReels",
|
||||
]
|
||||
|
||||
DEFAULT_DIMENSIONS = {"width": 1024, "height": 576}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user