Skip to content

Commit c427958

Browse files
committed
Added Support for Luma ray 3.2
1 parent 83113c7 commit c427958

11 files changed

Lines changed: 369 additions & 17 deletions

__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
from .modules.videoInferenceSettingsActiveSpeakerDetection import RunwareVideoInferenceSettingsActiveSpeakerDetection
4141
from .modules.videoInferenceSettingsActiveSpeakerBoundingBoxes import RunwareVideoInferenceSettingsActiveSpeakerBoundingBoxes
4242
from .modules.videoInferenceSettingsSegments import RunwareVideoInferenceSettingsSegments
43+
from .modules.videoInferenceSettingsControl import RunwareVideoInferenceSettingsControl
44+
from .modules.videoInferenceSettingsSourcePosition import RunwareVideoInferenceSettingsSourcePosition
4345
from .modules.frameImages import RunwareFrameImages
4446
from .modules.providerSettings.pixverseProviderSettings import RunwarePixverseProviderSettings
4547
from .modules.providerSettings.openaiProviderSettings import RunwareOpenAIProviderSettings
@@ -232,6 +234,8 @@
232234
"Runware Video Inference Settings Active Speaker Detection": RunwareVideoInferenceSettingsActiveSpeakerDetection,
233235
"Runware Video Inference Settings Active Speaker Bounding Boxes": RunwareVideoInferenceSettingsActiveSpeakerBoundingBoxes,
234236
"Runware Video Inference Settings Segments": RunwareVideoInferenceSettingsSegments,
237+
"Runware Video Inference Settings Edit": RunwareVideoInferenceSettingsControl,
238+
"Runware Video Inference Settings Source Position": RunwareVideoInferenceSettingsSourcePosition,
235239
"Runware Lightricks Provider Settings": RunwareLightricksProviderSettings,
236240
"Runware MiniMax Provider Settings": RunwareMiniMaxProviderSettings,
237241
"Runware Luma Provider Settings": RunwareLumaProviderSettings,

clientlibs/main.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { app } from "../../scripts/app.js";
22
import { api } from "../../scripts/api.js";
3-
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, saveTextHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, threeDModelSearchFilterHandler, 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, threeDInferenceSettingsMeshClusterToggleHandler, threeDInferenceSettingsDracoCompressionToggleHandler, ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, outpaintSettingsToggleHandler, safetyInputsToggleHandler, imageInferenceSettingsColorPaletteToggleHandler, imageInferenceSettingsMoodboardsToggleHandler, imageInferenceSettingsStructuredPromptToggleHandler, imageInferenceSettingsPromptEnhanceToggleHandler, imageInferenceSettingsScoringRubricToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler, audioInferenceReferenceVoiceToggleHandler, audioInferenceSpeechVoicesToggleHandler, videoInputsFrameToggleHandler, referenceVideosToggleHandler } from "./utils.js";
3+
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, saveTextHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, threeDModelSearchFilterHandler, audioModelSearchFilterHandler, textModelSearchFilterHandler, vectorizeModelSearchFilterHandler, vectorizeToggleHandler, useParameterToggleHandler, imageInferenceToggleHandler, imageInferenceAdvancedFeaturesToggleHandler, watermarkAdvancedFeatureToggleHandler, videoInferenceSpeechInputToggleHandler, regionalPromptingRegionsToggleHandler, upscalerToggleHandler, imageUpscalerSettingsToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, textInferenceSettingsToggleHandler, videoSettingsToggleHandler, videoInferenceSettingsTtsToggleHandler, videoInferenceSettingsActiveSpeakerDetectionToggleHandler, videoInferenceSettingsActiveSpeakerBoundingBoxesToggleHandler, videoInferenceSettingsSegmentsToggleHandler, videoInferenceSettingsControlToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, viduProviderSettingsToggleHandler, sourcefulProviderSettingsToggleHandler, sourcefulProviderSettingsFontsToggleHandler, threeDInferenceToggleHandler, threeDInferenceSettingsToggleHandler, threeDInferenceSettingsLatToggleHandler, threeDInferenceSettingsMeshClusterToggleHandler, threeDInferenceSettingsDracoCompressionToggleHandler, ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, outpaintSettingsToggleHandler, safetyInputsToggleHandler, imageInferenceSettingsColorPaletteToggleHandler, imageInferenceSettingsMoodboardsToggleHandler, imageInferenceSettingsStructuredPromptToggleHandler, imageInferenceSettingsPromptEnhanceToggleHandler, imageInferenceSettingsScoringRubricToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler, audioInferenceReferenceVoiceToggleHandler, audioInferenceSpeechVoicesToggleHandler, videoInputsFrameToggleHandler, referenceVideosToggleHandler } from "./utils.js";
44
import { RUNWARE_NODE_TYPES, RUNWARE_NODE_PROPS, SEARCH_TERMS } from "./types.js";
55

66
const nodeInitList = [];
@@ -107,6 +107,8 @@ app.registerExtension({
107107
videoInferenceSettingsActiveSpeakerBoundingBoxesToggleHandler(node);
108108
} else if(nodeClass === RUNWARE_NODE_TYPES.VIDEOINFERENCESETTINGSSEGMENTS) {
109109
videoInferenceSettingsSegmentsToggleHandler(node);
110+
} else if(nodeClass === RUNWARE_NODE_TYPES.VIDEOINFERENCESETTINGSEDIT) {
111+
videoInferenceSettingsControlToggleHandler(node);
110112
} else if(nodeClass === RUNWARE_NODE_TYPES.ACCELERATOROPTIONS) {
111113
acceleratorOptionsToggleHandler(node);
112114
} else if(nodeClass === RUNWARE_NODE_TYPES.BYTEDANCEPROVIDERSETTINGS) {

clientlibs/types.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ const RUNWARE_NODE_TYPES = {
130130
VIDEOINFERENCESETTINGSACTIVESPEAKERDETECTION: "Runware Video Inference Settings Active Speaker Detection",
131131
VIDEOINFERENCESETTINGSACTIVESPEAKERBOUNDINGBOXES: "Runware Video Inference Settings Active Speaker Bounding Boxes",
132132
VIDEOINFERENCESETTINGSSEGMENTS: "Runware Video Inference Settings Segments",
133+
VIDEOINFERENCESETTINGSEDIT: "Runware Video Inference Settings Edit",
134+
VIDEOINFERENCESETTINGSSOURCEPOSITION: "Runware Video Inference Settings Source Position",
133135
LIGHTRICKSPROVIDERSETTINGS: "Runware Lightricks Provider Settings",
134136
KLINGPROVIDERSETTINGS: "Runware KlingAI Provider Settings",
135137
KLINGMULTIPROMPTSEGMENT: "Runware Kling MultiPrompt Segment",
@@ -620,6 +622,14 @@ const RUNWARE_NODE_PROPS = {
620622
bgColor: DEFAULT_BGCOLOR,
621623
colorModeOnly: true,
622624
},
625+
[RUNWARE_NODE_TYPES.VIDEOINFERENCESETTINGSEDIT]: {
626+
bgColor: DEFAULT_BGCOLOR,
627+
colorModeOnly: true,
628+
},
629+
[RUNWARE_NODE_TYPES.VIDEOINFERENCESETTINGSSOURCEPOSITION]: {
630+
bgColor: DEFAULT_BGCOLOR,
631+
colorModeOnly: true,
632+
},
623633
[RUNWARE_NODE_TYPES.ACCELERATOROPTIONS]: {
624634
bgColor: DEFAULT_BGCOLOR,
625635
colorModeOnly: true,

clientlibs/utils.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,12 @@ function videoSettingsToggleHandler(settingsNode) {
14321432
const sourceAudioSyncWidget = settingsNode.widgets.find(w => w && w.name === "sourceAudioSync");
14331433
const useTurboWidget = settingsNode.widgets.find(w => w && w.name === "useTurbo");
14341434
const turboWidget = settingsNode.widgets.find(w => w && w.name === "turbo");
1435+
const useLoopWidget = settingsNode.widgets.find(w => w && w.name === "useLoop");
1436+
const loopWidget = settingsNode.widgets.find(w => w && w.name === "loop");
1437+
const useHdrWidget = settingsNode.widgets.find(w => w && w.name === "useHdr");
1438+
const hdrWidget = settingsNode.widgets.find(w => w && w.name === "hdr");
1439+
const useExrExportWidget = settingsNode.widgets.find(w => w && w.name === "useExrExport");
1440+
const exrExportWidget = settingsNode.widgets.find(w => w && w.name === "exrExport");
14351441
const useVoicePromptWidget = settingsNode.widgets.find(w => w && w.name === "useVoicePrompt");
14361442
const voicePromptWidget = settingsNode.widgets.find(w => w && w.name === "voicePrompt");
14371443
const useSafetyFilterWidget = settingsNode.widgets.find(w => w && w.name === "useSafetyFilter");
@@ -1494,6 +1500,9 @@ function videoSettingsToggleHandler(settingsNode) {
14941500
if (usePreserveAudioWidget && preserveAudioWidget) toggleWidgetState(usePreserveAudioWidget, preserveAudioWidget, "preserveAudio");
14951501
if (useSourceAudioSyncWidget && sourceAudioSyncWidget) toggleWidgetState(useSourceAudioSyncWidget, sourceAudioSyncWidget, "sourceAudioSync");
14961502
if (useTurboWidget && turboWidget) toggleWidgetState(useTurboWidget, turboWidget, "turbo");
1503+
if (useLoopWidget && loopWidget) toggleWidgetState(useLoopWidget, loopWidget, "loop");
1504+
if (useHdrWidget && hdrWidget) toggleWidgetState(useHdrWidget, hdrWidget, "hdr");
1505+
if (useExrExportWidget && exrExportWidget) toggleWidgetState(useExrExportWidget, exrExportWidget, "exrExport");
14971506
if (useVoicePromptWidget && voicePromptWidget) toggleWidgetState(useVoicePromptWidget, voicePromptWidget, "voicePrompt");
14981507
if (useSafetyFilterWidget && safetyFilterWidget) toggleWidgetState(useSafetyFilterWidget, safetyFilterWidget, "safetyFilter");
14991508
if (usePromptUpsamplingWidget && promptUpsamplingWidget) toggleWidgetState(usePromptUpsamplingWidget, promptUpsamplingWidget, "promptUpsampling");
@@ -1674,6 +1683,49 @@ function videoInferenceSettingsSegmentsToggleHandler(node) {
16741683
wireSegment(4);
16751684
}
16761685

1686+
function videoInferenceSettingsControlToggleHandler(node) {
1687+
if (!node?.widgets) return;
1688+
1689+
const useAutoControlsWidget = node.widgets.find(w => w && w.name === "useAutoControls");
1690+
const autoControlsWidget = node.widgets.find(w => w && w.name === "autoControls");
1691+
const useStrengthWidget = node.widgets.find(w => w && w.name === "useStrength");
1692+
const strengthWidget = node.widgets.find(w => w && w.name === "strength");
1693+
const useDepthBlurWidget = node.widgets.find(w => w && w.name === "useDepthBlur");
1694+
const depthBlurWidget = node.widgets.find(w => w && w.name === "depthBlur");
1695+
const useFaceWidget = node.widgets.find(w => w && w.name === "useFace");
1696+
const faceWidget = node.widgets.find(w => w && w.name === "face");
1697+
const useNormalsAugmentationWidget = node.widgets.find(w => w && w.name === "useNormalsAugmentation");
1698+
const normalsAugmentationWidget = node.widgets.find(w => w && w.name === "normalsAugmentation");
1699+
const usePoseStrengthWidget = node.widgets.find(w => w && w.name === "usePoseStrength");
1700+
const poseStrengthWidget = node.widgets.find(w => w && w.name === "poseStrength");
1701+
const useTrajectorySparsityWidget = node.widgets.find(w => w && w.name === "useTrajectorySparsity");
1702+
const trajectorySparsityWidget = node.widgets.find(w => w && w.name === "trajectorySparsity");
1703+
1704+
function toggleWidgetState(useWidget, paramWidget, paramName) {
1705+
if (!useWidget || !paramWidget) return;
1706+
function applyState() {
1707+
const enabled = useWidget.value === true;
1708+
toggleWidgetEnabled(paramWidget, enabled, node);
1709+
if (paramWidget.options && paramWidget.options.element) {
1710+
paramWidget.options.element.disabled = !enabled;
1711+
paramWidget.options.element.style.opacity = enabled ? "1" : "0.5";
1712+
paramWidget.options.element.style.pointerEvents = enabled ? "auto" : "none";
1713+
}
1714+
node.setDirtyCanvas(true);
1715+
}
1716+
setTimeout(applyState, 100);
1717+
appendWidgetCB(useWidget, () => setTimeout(applyState, 50));
1718+
}
1719+
1720+
if (useAutoControlsWidget && autoControlsWidget) toggleWidgetState(useAutoControlsWidget, autoControlsWidget, "autoControls");
1721+
if (useStrengthWidget && strengthWidget) toggleWidgetState(useStrengthWidget, strengthWidget, "strength");
1722+
if (useDepthBlurWidget && depthBlurWidget) toggleWidgetState(useDepthBlurWidget, depthBlurWidget, "depthBlur");
1723+
if (useFaceWidget && faceWidget) toggleWidgetState(useFaceWidget, faceWidget, "face");
1724+
if (useNormalsAugmentationWidget && normalsAugmentationWidget) toggleWidgetState(useNormalsAugmentationWidget, normalsAugmentationWidget, "normalsAugmentation");
1725+
if (usePoseStrengthWidget && poseStrengthWidget) toggleWidgetState(usePoseStrengthWidget, poseStrengthWidget, "poseStrength");
1726+
if (useTrajectorySparsityWidget && trajectorySparsityWidget) toggleWidgetState(useTrajectorySparsityWidget, trajectorySparsityWidget, "trajectorySparsity");
1727+
}
1728+
16771729
function audioInferenceSpeechToggleHandler(speechNode) {
16781730
if (!speechNode?.widgets) return;
16791731

@@ -2937,6 +2989,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
29372989
"lumaai:1@1 (Luma Ray 1.6)",
29382990
"lumaai:2@1 (Luma Ray 2)",
29392991
"lumaai:2@2 (Luma Ray 2 Flash)",
2992+
"luma:ray@3.2 (Luma Ray 3.2)",
29402993
],
29412994
"Sync": [
29422995
"sync:lipsync-2@1 (Sync LipSync 2)",
@@ -3063,6 +3116,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
30633116
"lumaai:1@1": {"width": 1080, "height": 720},
30643117
"lumaai:2@1": {"width": 1080, "height": 720},
30653118
"lumaai:2@2": {"width": 1080, "height": 720},
3119+
"luma:ray@3.2": {"width": 1280, "height": 720},
30663120
"sync:lipsync-2@1": {"width": 0, "height": 0},
30673121
"sync:lipsync-2-pro@1": {"width": 0, "height": 0},
30683122
"sync:react-1@1": {"width": 0, "height": 0},
@@ -3168,6 +3222,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
31683222
"lumaai:1@1": "720p",
31693223
"lumaai:2@1": "720p",
31703224
"lumaai:2@2": "720p",
3225+
"luma:ray@3.2": "720p",
31713226
"sync:lipsync-2@1": "720p",
31723227
"sync:lipsync-2-pro@1": "720p",
31733228
"sync:react-1@1": "720p",
@@ -5314,6 +5369,7 @@ export {
53145369
videoInferenceSettingsActiveSpeakerDetectionToggleHandler,
53155370
videoInferenceSettingsActiveSpeakerBoundingBoxesToggleHandler,
53165371
videoInferenceSettingsSegmentsToggleHandler,
5372+
videoInferenceSettingsControlToggleHandler,
53175373
acceleratorOptionsToggleHandler,
53185374
bytedanceProviderSettingsToggleHandler,
53195375
xaiProviderSettingsToggleHandler,

modules/utils/runwareUtils.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
import threading
2121
import re
2222

23-
import websocket
23+
from websockets.sync.client import connect as ws_connect
24+
from websockets.exceptions import ConnectionClosed, WebSocketException
2425

2526
from ..version import __version__
2627

@@ -191,6 +192,13 @@ def getRunwareWsHeaders():
191192
f"X-SDK-Version: {__version__}",
192193
]
193194

195+
def getRunwareWsHeadersDict():
196+
headers = {}
197+
for header in getRunwareWsHeaders():
198+
key, value = header.split(": ", 1)
199+
headers[key] = value
200+
return headers
201+
194202
WS_CONNECT_TIMEOUT = 10
195203
WS_READ_TIMEOUT = 1
196204

@@ -333,12 +341,12 @@ def _connect(self):
333341
self._reader_thread.join(timeout=2)
334342

335343
self._stop_reader.clear()
336-
self._ws = websocket.create_connection(
344+
self._ws = ws_connect(
337345
url,
338-
timeout=WS_CONNECT_TIMEOUT,
339-
header=getRunwareWsHeaders(),
346+
max_size=None,
347+
additional_headers=getRunwareWsHeadersDict(),
348+
open_timeout=WS_CONNECT_TIMEOUT,
340349
)
341-
self._ws.settimeout(WS_READ_TIMEOUT)
342350
self._reader_thread = threading.Thread(
343351
target=self._reader_loop,
344352
name="RunwareWebSocketReader",
@@ -381,12 +389,12 @@ def _authenticate(self, api_key=None):
381389
def _reader_loop(self):
382390
while not self._stop_reader.is_set() and self._ws is not None:
383391
try:
384-
raw = self._ws.recv()
385-
except websocket.WebSocketTimeoutException:
392+
raw = self._ws.recv(timeout=WS_READ_TIMEOUT)
393+
except TimeoutError:
386394
continue
387-
except websocket.WebSocketConnectionClosedException:
395+
except ConnectionClosed:
388396
break
389-
except Exception as e:
397+
except WebSocketException as e:
390398
if not self._stop_reader.is_set():
391399
print(f"[Runware] WebSocket reader error: {e}")
392400
break
@@ -533,9 +541,11 @@ def wsRequestWrapper(recaller):
533541
try:
534542
return recaller()
535543
except (
536-
websocket.WebSocketException,
544+
WebSocketException,
545+
ConnectionClosed,
537546
ConnectionError,
538547
OSError,
548+
TimeoutError,
539549
):
540550
if attempt == MAX_RETRIES:
541551
raise
@@ -554,10 +564,11 @@ def checkAPIKeyWithWebSocket(apiKey):
554564
url = getCustomEndpoint()
555565
ws = None
556566
try:
557-
ws = websocket.create_connection(
567+
ws = ws_connect(
558568
url,
559-
timeout=WS_CONNECT_TIMEOUT,
560-
header=getRunwareWsHeaders(),
569+
max_size=None,
570+
additional_headers=getRunwareWsHeadersDict(),
571+
open_timeout=WS_CONNECT_TIMEOUT,
561572
)
562573
ws.send(json.dumps([{"taskType": "authentication", "apiKey": apiKey}]))
563574
response = json.loads(ws.recv())

0 commit comments

Comments
 (0)