Merge branch 'main' into fix-tiffNode/feature-outputNode
This commit is contained in:
@@ -72,6 +72,7 @@ from .modules.settings import RunwareSettings
|
||||
from .modules.videoAdvancedFeatureInputs import videoAdvancedFeatureInputs
|
||||
from .modules.advancedFeatureSettings.wanAnimateAdvancedFeatureSettings import RunwareWanAnimateAdvancedFeatureSettings
|
||||
from .modules.saveImage import RunwareSaveImage
|
||||
from .modules.videoOutputs import RunwareVideoInferenceOutputs
|
||||
|
||||
RUNWARE_COMFYUI_VERSION = "1.4.0 Beta"
|
||||
|
||||
@@ -158,6 +159,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"Runware Video Advanced Feature Inputs": videoAdvancedFeatureInputs,
|
||||
"Runware Wan Animate Advanced Feature Settings": RunwareWanAnimateAdvancedFeatureSettings,
|
||||
"Runware Save Image": RunwareSaveImage,
|
||||
"Runware Video Inference Outputs": RunwareVideoInferenceOutputs,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
|
||||
+14
-1
@@ -1,6 +1,6 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { api } from "../../scripts/api.js";
|
||||
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, videoTranscriptionHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, useParameterToggleHandler, imageInferenceToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler } from "./utils.js";
|
||||
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, useParameterToggleHandler, imageInferenceToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, 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 = [];
|
||||
@@ -11,6 +11,7 @@ app.registerExtension({
|
||||
api.addEventListener('runwareImageCaption', captionNodeHandler);
|
||||
api.addEventListener('runwareMediaUUID', mediaUUIDHandler);
|
||||
api.addEventListener('runwareVideoTranscription', videoTranscriptionHandler);
|
||||
api.addEventListener('runwareVideoOutputs', videoOutputsHandler);
|
||||
},
|
||||
|
||||
async nodeCreated(node) {
|
||||
@@ -39,6 +40,18 @@ app.registerExtension({
|
||||
mediaUUIDWidget.inputEl.style.fontSize = "11px";
|
||||
mediaUUIDWidget.inputEl.style.fontFamily = "monospace";
|
||||
}
|
||||
} else if(nodeClass === RUNWARE_NODE_TYPES.VIDEOINFERENCEOUTPUTS) {
|
||||
// Style draftId and videoId widgets to show full IDs (like Media Upload)
|
||||
const draftIdWidget = node.widgets.find(widget => widget.name === "draftId");
|
||||
const videoIdWidget = node.widgets.find(widget => widget.name === "videoId");
|
||||
for(const w of [draftIdWidget, videoIdWidget]) {
|
||||
if(w && w.inputEl) {
|
||||
w.inputEl.style.width = "100%";
|
||||
w.inputEl.style.minWidth = "300px";
|
||||
w.inputEl.style.fontSize = "11px";
|
||||
w.inputEl.style.fontFamily = "monospace";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nodeWidgets = node.widgets;
|
||||
|
||||
@@ -122,6 +122,7 @@ const RUNWARE_NODE_TYPES = {
|
||||
VIDEOADVANCEDFEATUREINPUTS: "Runware Video Advanced Feature Inputs",
|
||||
WANANIMATEADVANCEDFEATURESETTINGS: "Runware Wan Animate Advanced Feature Settings",
|
||||
SAVEIMAGE: "Runware Save Image",
|
||||
VIDEOINFERENCEOUTPUTS: "Runware Video Inference Outputs",
|
||||
};
|
||||
|
||||
const RUNWARE_NODE_PROPS = {
|
||||
@@ -425,6 +426,10 @@ const RUNWARE_NODE_PROPS = {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.VIDEOINFERENCEOUTPUTS]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
},
|
||||
};
|
||||
|
||||
export {
|
||||
|
||||
+48
-1
@@ -106,6 +106,44 @@ function videoTranscriptionHandler(msgEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function videoOutputsHandler(msgEvent) {
|
||||
const outputData = msgEvent.detail;
|
||||
const draftId = outputData.draftId || "";
|
||||
const videoId = outputData.videoId || "";
|
||||
const nodeID = outputData.nodeID;
|
||||
|
||||
if(outputData.success && nodeID !== undefined && nodeID !== null) {
|
||||
const nodeIdInt = typeof nodeID === 'string' ? parseInt(nodeID) : nodeID;
|
||||
const outputNode = app.graph.getNodeById(nodeIdInt);
|
||||
|
||||
if(outputNode !== null && outputNode !== undefined) {
|
||||
const draftIdWidget = outputNode.widgets.find(widget => widget.name === "draftId");
|
||||
const videoIdWidget = outputNode.widgets.find(widget => widget.name === "videoId");
|
||||
|
||||
if(draftIdWidget) {
|
||||
if(draftIdWidget.value !== undefined) draftIdWidget.value = draftId;
|
||||
if(draftIdWidget.inputEl) {
|
||||
draftIdWidget.inputEl.value = draftId;
|
||||
draftIdWidget.inputEl.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
draftIdWidget.inputEl.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
}
|
||||
|
||||
if(videoIdWidget) {
|
||||
if(videoIdWidget.value !== undefined) videoIdWidget.value = videoId;
|
||||
if(videoIdWidget.inputEl) {
|
||||
videoIdWidget.inputEl.value = videoId;
|
||||
videoIdWidget.inputEl.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
videoIdWidget.inputEl.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
}
|
||||
|
||||
outputNode.setDirtyCanvas(true);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function notifyUser(message, type="info", title = "Runware", life = 4.5) {
|
||||
app.extensionManager.toast.add({
|
||||
severity: type, // 'info', 'success', 'warn', 'error' \\
|
||||
@@ -1131,6 +1169,8 @@ function bytedanceProviderSettingsToggleHandler(bytedanceNode) {
|
||||
const fastModeWidget = bytedanceNode.widgets.find(w => w.name === "fastMode");
|
||||
const useAudioWidget = bytedanceNode.widgets.find(w => w.name === "useAudio");
|
||||
const audioWidget = bytedanceNode.widgets.find(w => w.name === "audio");
|
||||
const useDraftWidget = bytedanceNode.widgets.find(w => w.name === "useDraft");
|
||||
const draftWidget = bytedanceNode.widgets.find(w => w.name === "draft");
|
||||
|
||||
// Helper function to toggle widget enabled state (exact same pattern)
|
||||
function toggleWidgetState(useWidget, paramWidget, paramName) {
|
||||
@@ -1189,6 +1229,10 @@ function bytedanceProviderSettingsToggleHandler(bytedanceNode) {
|
||||
if (useAudioWidget && audioWidget) {
|
||||
toggleWidgetState(useAudioWidget, audioWidget, "audio");
|
||||
}
|
||||
|
||||
if (useDraftWidget && draftWidget) {
|
||||
toggleWidgetState(useDraftWidget, draftWidget, "draft");
|
||||
}
|
||||
}
|
||||
|
||||
function openaiProviderSettingsToggleHandler(openaiNode) {
|
||||
@@ -1715,7 +1759,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
|
||||
],
|
||||
"PixVerse": [
|
||||
"pixverse:1@1 (PixVerse v3.5)", "pixverse:1@2 (PixVerse v4)",
|
||||
"pixverse:1@3 (PixVerse v4.5)", "pixverse:1@5-fast (PixVerse v5 Fast)", "pixverse:1@6 (PixVerse v5.5)", "pixverse:lipsync@1 (PixVerse LipSync)",
|
||||
"pixverse:1@3 (PixVerse v4.5)", "pixverse:1@5-fast (PixVerse v5 Fast)", "pixverse:1@6 (PixVerse v5.5)", "pixverse:1@7 (PixVerse v5.6)", "pixverse:lipsync@1 (PixVerse LipSync)",
|
||||
],
|
||||
"Vidu": [
|
||||
"vidu:1@0 (Vidu Q1 Classic)", "vidu:1@1 (Vidu Q1)",
|
||||
@@ -1801,6 +1845,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
|
||||
"pixverse:1@2": {"width": 640, "height": 360},
|
||||
"pixverse:1@3": {"width": 640, "height": 360},
|
||||
"pixverse:1@6": {"width": 640, "height": 360},
|
||||
"pixverse:1@7": {"width": 640, "height": 360},
|
||||
"pixverse:lipsync@1": {"width": 640, "height": 360},
|
||||
"vidu:1@0": {"width": 1920, "height": 1080},
|
||||
"vidu:1@1": {"width": 1920, "height": 1080},
|
||||
@@ -1869,6 +1914,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
|
||||
"pixverse:1@2": "360p",
|
||||
"pixverse:1@3": "360p",
|
||||
"pixverse:1@6": "360p",
|
||||
"pixverse:1@7": "360p",
|
||||
"pixverse:lipsync@1": "360p",
|
||||
"vidu:1@0": "1080p",
|
||||
"vidu:1@1": "1080p",
|
||||
@@ -3149,6 +3195,7 @@ export {
|
||||
mediaUUIDHandler,
|
||||
captionNodeHandler,
|
||||
videoTranscriptionHandler,
|
||||
videoOutputsHandler,
|
||||
handleCustomErrors,
|
||||
APIKeyHandler,
|
||||
videoInferenceDimensionsHandler,
|
||||
|
||||
@@ -47,6 +47,14 @@ class RunwareBytedanceProviderSettings:
|
||||
"tooltip": "Enable audio generation support when available.",
|
||||
"default": False,
|
||||
}),
|
||||
"useDraft": ("BOOLEAN", {
|
||||
"tooltip": "Enable to include draft parameter in provider settings",
|
||||
"default": False,
|
||||
}),
|
||||
"draft": ("BOOLEAN", {
|
||||
"tooltip": "Enable draft mode for Bytedance provider",
|
||||
"default": False,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,12 +71,14 @@ class RunwareBytedanceProviderSettings:
|
||||
useMaxSequentialImages = kwargs.get("useMaxSequentialImages", False)
|
||||
useFastMode = kwargs.get("useFastMode", False)
|
||||
useAudio = kwargs.get("useAudio", False)
|
||||
useDraft = kwargs.get("useDraft", False)
|
||||
|
||||
# Get value parameters
|
||||
cameraFixed = kwargs.get("cameraFixed", False)
|
||||
maxSequentialImages = kwargs.get("maxSequentialImages", 1)
|
||||
fastMode = kwargs.get("fastMode", False)
|
||||
audio = kwargs.get("audio", False)
|
||||
draft = kwargs.get("draft", False)
|
||||
|
||||
# Build settings dictionary - only include what is enabled
|
||||
settings = {}
|
||||
@@ -88,6 +98,10 @@ class RunwareBytedanceProviderSettings:
|
||||
# Add audio only if useAudio is enabled
|
||||
if useAudio:
|
||||
settings["audio"] = audio
|
||||
|
||||
# Add draft only if useDraft is enabled
|
||||
if useDraft:
|
||||
settings["draft"] = draft
|
||||
|
||||
# Clean up None values
|
||||
settings = {k: v for k, v in settings.items() if v is not None}
|
||||
|
||||
@@ -317,6 +317,19 @@ def sendVideoTranscription(transcriptionText, nodeID):
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def sendVideoOutputs(draftId, videoId, nodeID):
|
||||
"""Send draftId and videoId to frontend for display in Video Inference Outputs node textboxes."""
|
||||
PromptServer.instance.send_sync(
|
||||
"runwareVideoOutputs",
|
||||
{
|
||||
"success": True,
|
||||
"draftId": draftId or "",
|
||||
"videoId": videoId or "",
|
||||
"nodeID": nodeID,
|
||||
},
|
||||
)
|
||||
|
||||
def inferenecRequest(genConfig):
|
||||
global RUNWARE_API_KEY, RUNWARE_API_BASE_URL, SESSION_TIMEOUT
|
||||
RUNWARE_API_KEY = os.getenv("RUNWARE_API_KEY")
|
||||
|
||||
@@ -125,7 +125,8 @@ class videoBgRemoval:
|
||||
if status == "success":
|
||||
if "videoURL" in videoData or "videoBase64Data" in videoData:
|
||||
videos = rwUtils.convertVideoB64List(pollResult, 1920, 1080)
|
||||
return videos
|
||||
# SaveVideo expects a single video object, not a tuple
|
||||
return (videos[0],) if len(videos) > 0 else (None,)
|
||||
|
||||
comfy.model_management.throw_exception_if_processing_interrupted()
|
||||
|
||||
|
||||
@@ -141,8 +141,8 @@ class txt2vid:
|
||||
|
||||
DESCRIPTION = "Generates Videos Lightning Fast With Runware Video Inference Engine."
|
||||
FUNCTION = "generateVideo"
|
||||
RETURN_TYPES = ("VIDEO", "RUNWARETASK")
|
||||
RETURN_NAMES = ("VIDEO", "RW-Task")
|
||||
RETURN_TYPES = ("VIDEO", "RUNWARETASK", "RUNWARETASK")
|
||||
RETURN_NAMES = ("VIDEO", "RW-Task", "OUTPUT")
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def generateVideo(self, **kwargs):
|
||||
@@ -325,7 +325,7 @@ class txt2vid:
|
||||
genConfig[0]["acceleration"] = acceleration
|
||||
|
||||
if (multiInferenceMode):
|
||||
return (None, genConfig)
|
||||
return (None, genConfig, None)
|
||||
else:
|
||||
try:
|
||||
# Debug: Print the request being sent
|
||||
@@ -388,7 +388,9 @@ class txt2vid:
|
||||
if status == "success":
|
||||
if "videoURL" in video_data or "videoBase64Data" in video_data:
|
||||
videos = rwUtils.convertVideoB64List(pollResult, width, height)
|
||||
return videos
|
||||
# SaveVideo expects a single video object, not a tuple
|
||||
video_output = videos[0] if len(videos) > 0 else None
|
||||
return (video_output, genConfig, pollResult)
|
||||
|
||||
# If status is "processing", continue polling
|
||||
|
||||
|
||||
@@ -43,6 +43,16 @@ class videoInferenceInputs:
|
||||
"Reference Voices": ("RUNWAREREFERENCEVOICES", {
|
||||
"tooltip": "Connect the Reference Voices node to provide reference voice URLs or mediaUUIDs."
|
||||
}),
|
||||
"draftId": ("STRING", {
|
||||
"default": "",
|
||||
"multiline": False,
|
||||
"tooltip": "Draft ID from a previous Bytedance video generation. Used when continuing or extending a draft output",
|
||||
}),
|
||||
"videoId": ("STRING", {
|
||||
"default": "",
|
||||
"multiline": False,
|
||||
"tooltip": "Video ID from a previous generation. Used when extending or editing an existing OpenAI Sora video",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +75,8 @@ class videoInferenceInputs:
|
||||
references = kwargs.get("References", None)
|
||||
referenceVideos = kwargs.get("Reference Videos", None)
|
||||
referenceVoices = kwargs.get("Reference Voices", None)
|
||||
draftId = kwargs.get("draftId", "")
|
||||
videoId = kwargs.get("videoId", "")
|
||||
|
||||
inputs = {}
|
||||
|
||||
@@ -112,4 +124,10 @@ class videoInferenceInputs:
|
||||
if referenceVoices is not None and len(referenceVoices) > 0:
|
||||
inputs["referenceVoices"] = referenceVoices
|
||||
|
||||
if draftId is not None and draftId.strip() != "":
|
||||
inputs["draftId"] = draftId.strip()
|
||||
|
||||
if videoId is not None and videoId.strip() != "":
|
||||
inputs["videoId"] = videoId.strip()
|
||||
|
||||
return (inputs,)
|
||||
|
||||
+10
-13
@@ -47,6 +47,7 @@ class videoModelSearch:
|
||||
"pixverse:1@3 (PixVerse v4.5)",
|
||||
"pixverse:1@5-fast (PixVerse v5 Fast)",
|
||||
"pixverse:1@6 (PixVerse v5.5)",
|
||||
"pixverse:1@7 (PixVerse v5.6)",
|
||||
"pixverse:lipsync@1 (PixVerse LipSync)",
|
||||
],
|
||||
"Vidu": [
|
||||
@@ -148,6 +149,7 @@ class videoModelSearch:
|
||||
"pixverse:1@3": {"width": 640, "height": 360},
|
||||
"pixverse:1@5-fast": {"width": 640, "height": 360},
|
||||
"pixverse:1@6": {"width": 640, "height": 360},
|
||||
"pixverse:1@7": {"width": 640, "height": 360},
|
||||
"pixverse:lipsync@1": {"width": 640, "height": 360},
|
||||
|
||||
# Vidu Models
|
||||
@@ -248,6 +250,7 @@ class videoModelSearch:
|
||||
"pixverse:1@3": "360p",
|
||||
"pixverse:1@5-fast": "360p",
|
||||
"pixverse:1@6": "360p",
|
||||
"pixverse:1@7": "360p",
|
||||
"pixverse:lipsync@1": "360p",
|
||||
|
||||
# Vidu Models
|
||||
@@ -390,8 +393,8 @@ class videoModelSearch:
|
||||
|
||||
DESCRIPTION = "Directly Search and Connect Video Models to Runware Video Inference Nodes In ComfyUI."
|
||||
FUNCTION = "videoModelSearch"
|
||||
RETURN_TYPES = ("RUNWAREVIDEOMODEL", "INT", "INT")
|
||||
RETURN_NAMES = ("Runware Video Model", "Width", "Height")
|
||||
RETURN_TYPES = ("RUNWAREVIDEOMODEL",)
|
||||
RETURN_NAMES = ("Runware Video Model",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
@classmethod
|
||||
@@ -421,33 +424,27 @@ class videoModelSearch:
|
||||
# Use custom dimensions from Width/Height widgets
|
||||
width = customWidth
|
||||
height = customHeight
|
||||
returnWidth = width
|
||||
returnHeight = height
|
||||
elif useCustomDimensions == "Disabled":
|
||||
# Don't pass width/height (use None in dict, but return 0 for INT output)
|
||||
# Don't pass width/height (use None in dict)
|
||||
width = None
|
||||
height = None
|
||||
returnWidth = 0
|
||||
returnHeight = 0
|
||||
else: # "Model Default"
|
||||
# Use model default dimensions
|
||||
width = dimensions["width"]
|
||||
height = dimensions["height"]
|
||||
returnWidth = width
|
||||
returnHeight = height
|
||||
|
||||
|
||||
resultDict = {
|
||||
"model": modelAirCode,
|
||||
"useCustomDimensions": useCustomDimensions,
|
||||
"width": width,
|
||||
"height": height,
|
||||
}
|
||||
|
||||
|
||||
# Add resolution if enabled and model supports it
|
||||
if useResolution and modelResolution is not None:
|
||||
resultDict["resolution"] = resolution
|
||||
resultDict["useResolution"] = True
|
||||
else:
|
||||
resultDict["useResolution"] = False
|
||||
|
||||
return (resultDict, returnWidth, returnHeight)
|
||||
|
||||
return (resultDict,)
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
from .utils import runwareUtils as rwUtils
|
||||
|
||||
|
||||
class RunwareVideoInferenceOutputs:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"Output": (
|
||||
"RUNWARETASK",
|
||||
{
|
||||
"tooltip": "Connect the OUTPUT from Runware Video Inference.",
|
||||
},
|
||||
),
|
||||
},
|
||||
"optional": {
|
||||
"draftId": ("STRING", {
|
||||
"placeholder": "Draft ID will appear here after generation.",
|
||||
"tooltip": "This field will be automatically populated with the draft ID from the video inference output.",
|
||||
}),
|
||||
"videoId": ("STRING", {
|
||||
"placeholder": "Video ID will appear here after generation.",
|
||||
"tooltip": "This field will be automatically populated with the video ID from the video inference output.",
|
||||
}),
|
||||
},
|
||||
"hidden": {"node_id": "UNIQUE_ID"},
|
||||
}
|
||||
|
||||
DESCRIPTION = "Extracts Runware video inference outputs such as draftId and videoId."
|
||||
FUNCTION = "get_outputs"
|
||||
RETURN_TYPES = ("STRING", "STRING")
|
||||
RETURN_NAMES = ("draftID", "videoID")
|
||||
CATEGORY = "Runware"
|
||||
OUTPUT_NODE = True # Ensure node executes even if outputs aren't used
|
||||
|
||||
def get_outputs(self, Output, draftId=None, videoId=None, **kwargs):
|
||||
draft_id = ""
|
||||
video_id = ""
|
||||
|
||||
try:
|
||||
data_list = None
|
||||
|
||||
# Handle different possible response shapes defensively
|
||||
if isinstance(Output, dict):
|
||||
if "data" in Output:
|
||||
data_list = Output.get("data", [])
|
||||
elif "response" in Output and isinstance(Output["response"], dict):
|
||||
data_list = Output["response"].get("data", [])
|
||||
|
||||
if data_list and len(data_list) > 0:
|
||||
first = data_list[0]
|
||||
outputs = first.get("outputs") or {}
|
||||
if isinstance(outputs, dict):
|
||||
# draftId is used by some providers
|
||||
draft_id = outputs.get("draftId", "") or outputs.get("draftID", "")
|
||||
# videoId / videoID used by other providers
|
||||
video_id = outputs.get("videoId", "") or outputs.get("videoID", "")
|
||||
|
||||
# Send to frontend so values appear in textboxes (like Media Upload)
|
||||
rwUtils.sendVideoOutputs(draft_id, video_id, kwargs.get("node_id"))
|
||||
|
||||
except Exception as e:
|
||||
print(f"[Runware Video Outputs] Failed to parse outputs: {e}")
|
||||
|
||||
return (draft_id, video_id)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"RunwareVideoInferenceOutputs": RunwareVideoInferenceOutputs,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"RunwareVideoInferenceOutputs": "Runware Video Inference Outputs",
|
||||
}
|
||||
|
||||
@@ -121,7 +121,8 @@ class videoUpscaler:
|
||||
if status == "success":
|
||||
if "mediaURL" in video_data or "videoURL" in video_data or "videoBase64Data" in video_data:
|
||||
videos = rwUtils.convertVideoB64List(pollResult, 1920, 1080)
|
||||
return videos
|
||||
# SaveVideo expects a single video object, not a tuple
|
||||
return (videos[0],) if len(videos) > 0 else (None,)
|
||||
|
||||
# If status is "processing", continue polling
|
||||
|
||||
|
||||
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
Reference in New Issue
Block a user