From 11fc63d4f663bbb1dc87d65eadd338b814de45d3 Mon Sep 17 00:00:00 2001 From: Sirshendu Ganguly Date: Thu, 29 Jan 2026 21:57:48 -0500 Subject: [PATCH] add workflow --- clientlibs/main.js | 12 ++++++++- clientlibs/utils.js | 25 +++++++++++++++++++ modules/save3D.py | 12 ++++++++- modules/utils/runwareUtils.py | 12 +++++++++ .../Runware_3D_Inference_meta_sam_3d.json | 1 + 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 workflows/Runware_3D_Inference_meta_sam_3d.json diff --git a/clientlibs/main.js b/clientlibs/main.js index 22fde98..bcd3441 100644 --- a/clientlibs/main.js +++ b/clientlibs/main.js @@ -1,6 +1,6 @@ import { app } from "../../scripts/app.js"; import { api } from "../../scripts/api.js"; -import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, 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 { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, save3DFilepathHandler, 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 = []; @@ -10,6 +10,7 @@ app.registerExtension({ api.addEventListener('runwareError', handleCustomErrors); api.addEventListener('runwareImageCaption', captionNodeHandler); api.addEventListener('runwareMediaUUID', mediaUUIDHandler); + api.addEventListener('runwareSave3DFilepath', save3DFilepathHandler); api.addEventListener('runwareVideoTranscription', videoTranscriptionHandler); api.addEventListener('runwareVideoOutputs', videoOutputsHandler); }, @@ -52,6 +53,15 @@ app.registerExtension({ w.inputEl.style.fontFamily = "monospace"; } } + } else if(nodeClass === RUNWARE_NODE_TYPES.SAVE3D) { + // Style the filepath widget to show full path (like Media Upload mediaUUID) + const filepathWidget = node.widgets.find(widget => widget.name === "filepath"); + if(filepathWidget && filepathWidget.inputEl) { + filepathWidget.inputEl.style.width = "100%"; + filepathWidget.inputEl.style.minWidth = "300px"; + filepathWidget.inputEl.style.fontSize = "11px"; + filepathWidget.inputEl.style.fontFamily = "monospace"; + } } const nodeWidgets = node.widgets; diff --git a/clientlibs/utils.js b/clientlibs/utils.js index 3c08c24..2f3d6ab 100644 --- a/clientlibs/utils.js +++ b/clientlibs/utils.js @@ -70,6 +70,30 @@ function mediaUUIDHandler(msgEvent) { return false; } +function save3DFilepathHandler(msgEvent) { + const data = msgEvent.detail; + const filepath = data.filepath; + const nodeID = parseInt(data.nodeID); + + if(data.success && filepath) { + const node = app.graph.getNodeById(nodeID); + if(node !== null && node !== undefined) { + const filepathWidget = node.widgets.find(widget => widget.name === "filepath"); + if(filepathWidget) { + if(filepathWidget.value !== undefined) { + filepathWidget.value = filepath; + } + if(filepathWidget.inputEl) { + filepathWidget.inputEl.value = filepath; + filepathWidget.inputEl.dispatchEvent(new Event('input', { bubbles: true })); + filepathWidget.inputEl.dispatchEvent(new Event('change', { bubbles: true })); + } + } + } + } + return false; +} + function captionNodeHandler(msgEvent) { const captionData = msgEvent.detail; const captionText = captionData.captionText; @@ -3193,6 +3217,7 @@ export { syncDimensionsNodeHandler, searchNodeHandler, mediaUUIDHandler, + save3DFilepathHandler, captionNodeHandler, videoTranscriptionHandler, videoOutputsHandler, diff --git a/modules/save3D.py b/modules/save3D.py index 1269fbb..dc59f9c 100644 --- a/modules/save3D.py +++ b/modules/save3D.py @@ -19,7 +19,14 @@ class RunwareSave3D: "default": "ComfyUI", "tooltip": "Prefix for the filename." }), - } + }, + "optional": { + "filepath": ("STRING", { + "placeholder": "Saved file path will appear here after execution.", + "tooltip": "This field is automatically populated with the saved file path after save.", + }), + }, + "hidden": {"node_id": "UNIQUE_ID"}, } RETURN_TYPES = () @@ -83,6 +90,9 @@ class RunwareSave3D: print(f"[Runware Save 3D] Successfully saved to: {filepath}") + # Send filepath to UI (like media upload mediaUUID) + rwUtils.sendSave3DFilepath(filepath, kwargs.get("node_id")) + # Return UI info for ComfyUI return {"ui": {"text": [f"Saved: {filename}"]}} diff --git a/modules/utils/runwareUtils.py b/modules/utils/runwareUtils.py index fa70e76..f624db9 100644 --- a/modules/utils/runwareUtils.py +++ b/modules/utils/runwareUtils.py @@ -295,6 +295,18 @@ def sendMediaUUID(mediaUUID, nodeID): }, ) + +def sendSave3DFilepath(filepath, nodeID): + PromptServer.instance.send_sync( + "runwareSave3DFilepath", + { + "success": True, + "filepath": filepath, + "nodeID": nodeID, + "widgetName": "filepath", + }, + ) + def sendImageCaption(captionText, nodeID): PromptServer.instance.send_sync( "runwareImageCaption", diff --git a/workflows/Runware_3D_Inference_meta_sam_3d.json b/workflows/Runware_3D_Inference_meta_sam_3d.json new file mode 100644 index 0000000..65944a0 --- /dev/null +++ b/workflows/Runware_3D_Inference_meta_sam_3d.json @@ -0,0 +1 @@ +{"id":"4f919008-d74f-4dcb-baaa-c9f3e0cfce69","revision":0,"last_node_id":7,"last_link_id":4,"nodes":[{"id":2,"type":"Runware 3D Inference Inputs","pos":[-111.40933990478516,526.4013671875],"size":[222.00253295898438,46],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"image","name":"image","shape":7,"type":"IMAGE","link":3},{"localized_name":"mask","name":"mask","shape":7,"type":"IMAGE","link":null}],"outputs":[{"localized_name":"Inputs","name":"Inputs","type":"RUNWARE3DINFERENCEINPUTS","links":[2]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"938185cd42fdc0a25095c8e72ba42fdcef10913e","Node name for S&R":"Runware 3D Inference Inputs"},"widgets_values":[],"bgcolor":"#5345bf"},{"id":4,"type":"LoadImage","pos":[75.4135513305664,689.6184692382812],"size":[274.080078125,314],"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":[3]},{"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":["hat.png","image"]},{"id":7,"type":"Runware Save 3D","pos":[680.3914794921875,391.1221618652344],"size":[270,106],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"3dObject","name":"3dObject","type":"STRING","widget":{"name":"3dObject"},"link":4},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null},{"localized_name":"filepath","name":"filepath","shape":7,"type":"STRING","widget":{"name":"filepath"},"link":null}],"outputs":[],"properties":{"cnr_id":"ComfyUI-Runware","ver":"ff6b7d8ad4471836cfbf1637e1ee1e24fe20bc48","Node name for S&R":"Runware Save 3D"},"widgets_values":["","ComfyUI",""],"bgcolor":"#5345bf"},{"id":1,"type":"Runware 3D Inference","pos":[215.56109619140625,360.20306396484375],"size":[400,200],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"inputs","name":"inputs","shape":7,"type":"RUNWARE3DINFERENCEINPUTS","link":2},{"localized_name":"Model","name":"Model","type":"COMBO","widget":{"name":"Model"},"link":null},{"localized_name":"positivePrompt","name":"positivePrompt","type":"STRING","widget":{"name":"positivePrompt"},"link":null},{"localized_name":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"outputFormat","name":"outputFormat","type":"COMBO","widget":{"name":"outputFormat"},"link":null}],"outputs":[{"localized_name":"3dObject","name":"3dObject","type":"STRING","links":[4]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"938185cd42fdc0a25095c8e72ba42fdcef10913e","Node name for S&R":"Runware 3D Inference"},"widgets_values":["Meta SAM 3D","a hat",1562538027,"randomize","GLB"],"bgcolor":"#5345bf"}],"links":[[2,2,0,1,0,"RUNWARE3DINFERENCEINPUTS"],[3,4,0,2,0,"IMAGE"],[4,1,0,7,0,"STRING"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.6830134553650705,"offset":[565.2445846003944,-50.69034697604053]}},"version":0.4} \ No newline at end of file