Merge pull request #82 from Runware/fix-tiffNode/feature-outputNode
Create custom "Runware Save Image" node
This commit is contained in:
@@ -71,6 +71,7 @@ from .modules.safetyInputs import safetyInputs
|
||||
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
|
||||
from .modules.threeDInference import threeDInference
|
||||
from .modules.threeDInferenceInputs import threeDInferenceInputs
|
||||
@@ -160,6 +161,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"Runware Settings": RunwareSettings,
|
||||
"Runware Video Advanced Feature Inputs": videoAdvancedFeatureInputs,
|
||||
"Runware Wan Animate Advanced Feature Settings": RunwareWanAnimateAdvancedFeatureSettings,
|
||||
"Runware Save Image": RunwareSaveImage,
|
||||
"Runware Video Inference Outputs": RunwareVideoInferenceOutputs,
|
||||
"Runware 3D Inference": threeDInference,
|
||||
"Runware 3D Inference Inputs": threeDInferenceInputs,
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 706 KiB |
@@ -121,6 +121,7 @@ const RUNWARE_NODE_TYPES = {
|
||||
SETTINGS: "Runware Settings",
|
||||
VIDEOADVANCEDFEATUREINPUTS: "Runware Video Advanced Feature Inputs",
|
||||
WANANIMATEADVANCEDFEATURESETTINGS: "Runware Wan Animate Advanced Feature Settings",
|
||||
SAVEIMAGE: "Runware Save Image",
|
||||
VIDEOINFERENCEOUTPUTS: "Runware Video Inference Outputs",
|
||||
THREEDINFERENCE: "Runware 3D Inference",
|
||||
THREEDINFERENCEINPUTS: "Runware 3D Inference Inputs",
|
||||
@@ -424,6 +425,10 @@ const RUNWARE_NODE_PROPS = {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.SAVEIMAGE]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.VIDEOINFERENCEOUTPUTS]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
|
||||
@@ -80,7 +80,8 @@ class bgremoval:
|
||||
|
||||
DESCRIPTION = "Remove backgrounds from images effortlessly using Runware's low-cost image editing Inference."
|
||||
FUNCTION = "rembg"
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("IMAGE",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def rembg(self, **kwargs):
|
||||
@@ -112,7 +113,7 @@ class bgremoval:
|
||||
"model": modelAIR,
|
||||
"outputFormat": outputFormat,
|
||||
"outputQuality": rwUtils.OUTPUT_QUALITY,
|
||||
"outputType": "base64Data",
|
||||
"outputType": "URL",
|
||||
}
|
||||
|
||||
if includeExtraSettings:
|
||||
@@ -166,5 +167,5 @@ class bgremoval:
|
||||
print(f"[DEBUG] Error in Background Removal Request: {str(e)}", flush=True)
|
||||
raise
|
||||
|
||||
images = rwUtils.convertImageB64List(genResult)
|
||||
return (images, )
|
||||
images = rwUtils.extractImageURLs(genResult)
|
||||
return (images,)
|
||||
@@ -76,7 +76,7 @@ class controlNetPreprocessor:
|
||||
|
||||
DESCRIPTION = "ControlNet offers advanced capabilities for precise image processing through the use of guide images in specific formats, known as preprocessed images. This powerful tool enhances the control and customization of image generation, enabling users to achieve desired artistic styles and detailed adjustments effectively."
|
||||
FUNCTION = "controlNetPreProcess"
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("GUIDE IMAGE",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
@@ -98,7 +98,7 @@ class controlNetPreprocessor:
|
||||
"preProcessorType": preProcessorType,
|
||||
"outputFormat": rwUtils.OUTPUT_FORMAT,
|
||||
"outputQuality": rwUtils.OUTPUT_QUALITY,
|
||||
"outputType": "base64Data",
|
||||
"outputType": "URL",
|
||||
}
|
||||
]
|
||||
|
||||
@@ -115,5 +115,5 @@ class controlNetPreprocessor:
|
||||
genConfig[0]["highThresholdCanny"] = cannyHighThreshold
|
||||
|
||||
genResult = rwUtils.inferenecRequest(genConfig)
|
||||
images = rwUtils.convertImageB64List(genResult)
|
||||
return (images, )
|
||||
images = rwUtils.extractImageURLs(genResult)
|
||||
return (images,)
|
||||
+19
-10
@@ -129,9 +129,9 @@ class txt2img:
|
||||
"min": 32,
|
||||
"max": 128,
|
||||
}),
|
||||
"outputFormat": (["WEBP", "PNG", "JPEG", "SVG", "TIFF"], {
|
||||
"tooltip": "Choose the output image format.",
|
||||
"default": "WEBP",
|
||||
"outputFormat": (["WEBP", "PNG", "JPEG", "TIFF"], {
|
||||
"tooltip": "Choose the output image format. This will be used for the API request. The actual saved format will match the format returned by the API (visible in imageURL).",
|
||||
"default": rwUtils.getOutputFormat(),
|
||||
}),
|
||||
"batchSize": ("INT", {
|
||||
"tooltip": "The number of images to generate in a single request.",
|
||||
@@ -196,7 +196,7 @@ class txt2img:
|
||||
|
||||
DESCRIPTION = "Generates Images Lightning Fast With Runware Image Inference Sonic Engine."
|
||||
FUNCTION = "generateImage"
|
||||
RETURN_TYPES = ("IMAGE", "RUNWARETASK")
|
||||
RETURN_TYPES = ("STRING", "RUNWARETASK")
|
||||
RETURN_NAMES = ("IMAGE", "RW-Task")
|
||||
CATEGORY = "Runware"
|
||||
|
||||
@@ -251,7 +251,7 @@ class txt2img:
|
||||
useSeed = kwargs.get("useSeed", True)
|
||||
useClipSkip = kwargs.get("useClipSkip", True)
|
||||
dimensions = kwargs.get("dimensions", "Square (512x512)")
|
||||
outputFormat = kwargs.get("outputFormat", "WEBP")
|
||||
outputFormat = kwargs.get("outputFormat", rwUtils.getOutputFormat())
|
||||
batchSize = kwargs.get("batchSize", 1)
|
||||
acceleration = kwargs.get("acceleration", "none")
|
||||
useResolution = kwargs.get("useResolution", False)
|
||||
@@ -454,11 +454,20 @@ class txt2img:
|
||||
status = image_data["status"]
|
||||
|
||||
if status == "success":
|
||||
# Check for image data (imageURL, imageBase64Data, mediaURL)
|
||||
if "imageURL" in image_data or "imageBase64Data" in image_data or "imageURL" in image_data:
|
||||
# Convert and return images
|
||||
images = rwUtils.convertImageB64List(pollResult)
|
||||
return (images, None)
|
||||
# Check for image data (imageURL, imageBase64Data)
|
||||
if "imageURL" in image_data or "imageBase64Data" in image_data:
|
||||
# Extract URLs from all results
|
||||
image_urls = []
|
||||
|
||||
for result in pollResult.get("data", []):
|
||||
imageURL = result.get("imageURL")
|
||||
if imageURL:
|
||||
image_urls.append(imageURL)
|
||||
|
||||
# Return URLs as comma-separated string (or single URL)
|
||||
image_url_str = ",".join(image_urls) if image_urls else ""
|
||||
|
||||
return (image_url_str, None)
|
||||
|
||||
# If status is "processing", continue polling
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class imageMasking:
|
||||
DESCRIPTION = "Image Masking provides intelligent detection and mask generation for specific elements in images, particularly optimized for faces, hands, and people. Built on advanced detection models, this feature enhances the inpainting workflow by automatically creating precise masks around detected elements, enabling targeted enhancement and detailing."
|
||||
|
||||
FUNCTION = "imageMasking"
|
||||
RETURN_TYPES = ("IMAGE", "IMAGE", "MASK")
|
||||
RETURN_TYPES = ("IMAGE", "STRING", "STRING")
|
||||
RETURN_NAMES = ("Image", "Mask Preview", "Mask")
|
||||
CATEGORY = "Runware"
|
||||
|
||||
@@ -87,7 +87,7 @@ class imageMasking:
|
||||
"model": detectionModel,
|
||||
"confidence": confidence,
|
||||
"maxDetections": maxDetections,
|
||||
"outputType": "base64Data",
|
||||
"outputType": "URL",
|
||||
"outputFormat": rwUtils.OUTPUT_FORMAT,
|
||||
"outputQuality": rwUtils.OUTPUT_QUALITY,
|
||||
}
|
||||
@@ -97,5 +97,5 @@ class imageMasking:
|
||||
genConfig[0]["maskBlur"] = maskBlur
|
||||
|
||||
genResult = rwUtils.inferenecRequest(genConfig)
|
||||
images = rwUtils.convertImageB64List(genResult)
|
||||
return (image, images[0], images[0])
|
||||
image_url = rwUtils.extractImageURLs(genResult)
|
||||
return (image, image_url, image_url)
|
||||
|
||||
@@ -39,7 +39,7 @@ class multiInference:
|
||||
|
||||
DESCRIPTION = "Allows you to Run Multiple Inference Tasks in Parallel."
|
||||
FUNCTION = "multiInference"
|
||||
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", "IMAGE")
|
||||
RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING")
|
||||
RETURN_NAMES = ("Result 1", "Result 2", "Result 3", "Result 4")
|
||||
CATEGORY = "Runware"
|
||||
|
||||
@@ -60,8 +60,8 @@ class multiInference:
|
||||
result = await loop.run_in_executor(
|
||||
None, rwUtils.inferenecRequest, taskData
|
||||
)
|
||||
images = rwUtils.convertImageB64List(result)
|
||||
return images
|
||||
image_url = rwUtils.extractImageURLs(result)
|
||||
return image_url
|
||||
except Exception as e:
|
||||
print(f"\n---- Runware Multi Inference Task {oindex + 1} Failed ----")
|
||||
print(f"Task-Type: {taskData[0]['taskType']}")
|
||||
|
||||
@@ -112,7 +112,8 @@ class photoMaker:
|
||||
|
||||
DESCRIPTION = "Transform and style images using PhotoMaker's advanced personalization technology. Create consistent, high-quality image variations with precise subject fidelity and style control."
|
||||
FUNCTION = "photoMaker"
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("IMAGE",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
@classmethod
|
||||
@@ -171,7 +172,7 @@ class photoMaker:
|
||||
"CFGScale": cfgScale,
|
||||
"clipSkip": clipSkip,
|
||||
"numberResults": batchSize,
|
||||
"outputType": "base64Data",
|
||||
"outputType": "URL",
|
||||
"outputFormat": rwUtils.OUTPUT_FORMAT,
|
||||
"outputQuality": rwUtils.OUTPUT_QUALITY,
|
||||
}
|
||||
@@ -186,5 +187,5 @@ class photoMaker:
|
||||
genConfig[0]["promptWeighting"] = "compel"
|
||||
|
||||
genResult = rwUtils.inferenecRequest(genConfig)
|
||||
images = rwUtils.convertImageB64List(genResult)
|
||||
return (images, )
|
||||
images = rwUtils.extractImageURLs(genResult)
|
||||
return (images,)
|
||||
|
||||
+4
-5
@@ -16,7 +16,7 @@ class RunwareSave3D:
|
||||
"3dObject": ("STRING", {
|
||||
"tooltip": "3D file URL from Runware 3D Inference node."
|
||||
}),
|
||||
"filename_prefix": ("STRING", {
|
||||
"filenamePrefix": ("STRING", {
|
||||
"default": "ComfyUI",
|
||||
"tooltip": "Prefix for the filename."
|
||||
}),
|
||||
@@ -37,10 +37,9 @@ class RunwareSave3D:
|
||||
CATEGORY = "Runware"
|
||||
DESCRIPTION = "Save 3D model files (GLB/PLY) from Runware 3D Inference to the output folder."
|
||||
|
||||
def save_3d(self, **kwargs):
|
||||
def save_3d(self, filenamePrefix="ComfyUI", **kwargs):
|
||||
"""Save 3D file from URL"""
|
||||
file_url = kwargs.get("3dObject", "")
|
||||
filename_prefix = kwargs.get("filename_prefix", "ComfyUI")
|
||||
|
||||
if not file_url or not file_url.strip():
|
||||
raise Exception("No 3D URL provided. Please connect the '3dObject' output from Runware 3D Inference node.")
|
||||
@@ -59,9 +58,9 @@ class RunwareSave3D:
|
||||
if extension not in ["glb", "ply"]:
|
||||
raise Exception(f"Unsupported 3D file extension '{extension}' from URL. Expected .glb or .ply.")
|
||||
|
||||
# Sanitize filename_prefix to prevent path traversal or arbitrary subdir creation
|
||||
# Sanitize filenamePrefix to prevent path traversal or arbitrary subdir creation
|
||||
prefix_basename = os.path.basename(
|
||||
filename_prefix.replace(os.sep, "_").replace(os.altsep or os.sep, "_")
|
||||
filenamePrefix.replace(os.sep, "_").replace(os.altsep or os.sep, "_")
|
||||
)
|
||||
safe_prefix = re.sub(r"[^\w\-]", "", prefix_basename) or "ComfyUI"
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
from .utils import runwareUtils as rwUtils
|
||||
import folder_paths
|
||||
import os
|
||||
import requests
|
||||
from datetime import datetime
|
||||
|
||||
class RunwareSaveImage:
|
||||
"""Runware Save Image node that respects format from imageURL"""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"Images": ("STRING", {
|
||||
"tooltip": "Image URL(s) from Runware Image Inference node. For multiple images, URLs should be comma-separated."
|
||||
}),
|
||||
"filenamePrefix": ("STRING", {
|
||||
"default": "ComfyUI",
|
||||
"tooltip": "Prefix for the filename."
|
||||
}),
|
||||
"saveImage": ("BOOLEAN", {
|
||||
"default": True,
|
||||
"label_on": "Enabled",
|
||||
"label_off": "Disabled",
|
||||
"tooltip": "If true, save to output folder. If false, download and preview only (purged when ComfyUI restarts)."
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ()
|
||||
FUNCTION = "save_images"
|
||||
OUTPUT_NODE = True
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def save_images(self, Images, filenamePrefix="ComfyUI", saveImage=True):
|
||||
"""Save images using URL directly"""
|
||||
|
||||
# Split URLs if comma-separated (for batch processing)
|
||||
image_urls = [url.strip() for url in Images.split(",") if url.strip()]
|
||||
|
||||
if not image_urls:
|
||||
raise Exception("No image added provided. Please connect the 'Image' from Runware Image Inference node.")
|
||||
|
||||
# Use output dir when saving, temp dir for preview only (purged on restart)
|
||||
if saveImage:
|
||||
output_dir = folder_paths.get_output_directory()
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
file_type = "output"
|
||||
else:
|
||||
output_dir = folder_paths.get_temp_directory()
|
||||
file_type = "temp"
|
||||
|
||||
saved_files = []
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
|
||||
for i, image_url in enumerate(image_urls):
|
||||
response = requests.get(image_url, timeout=30)
|
||||
response.raise_for_status()
|
||||
img_data = response.content
|
||||
|
||||
url_without_params = image_url.split('?')[0]
|
||||
extension = "." + url_without_params.split('.')[-1]
|
||||
|
||||
if len(image_urls) > 1:
|
||||
filename = f"{filenamePrefix}_{timestamp}_{i+1:03}.{extension.lstrip('.')}"
|
||||
else:
|
||||
filename = f"{filenamePrefix}_{timestamp}.{extension.lstrip('.')}"
|
||||
filepath = os.path.join(output_dir, filename)
|
||||
|
||||
with open(filepath, 'wb') as f:
|
||||
f.write(img_data)
|
||||
print(f"[Runware] {'Saved' if saveImage else 'Preview'}: {filepath}")
|
||||
|
||||
saved_files.append({
|
||||
"filename": filename,
|
||||
"subfolder": "",
|
||||
"type": file_type
|
||||
})
|
||||
|
||||
return {"ui": {"images": saved_files}}
|
||||
+18
-17
@@ -127,7 +127,8 @@ class upscaler:
|
||||
|
||||
DESCRIPTION = "Enhance the resolution and quality of your images using Runware's advanced upscaling API. Transform low-resolution images into sharp, high-definition visuals."
|
||||
FUNCTION = "upscale"
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("IMAGE",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def upscale(self, **kwargs):
|
||||
@@ -168,28 +169,28 @@ class upscaler:
|
||||
"upscaleFactor": int(upscaleFactor),
|
||||
"outputFormat": rwUtils.OUTPUT_FORMAT,
|
||||
"outputQuality": rwUtils.OUTPUT_QUALITY,
|
||||
"outputType": "base64Data",
|
||||
"outputType": "URL",
|
||||
}
|
||||
|
||||
# Add model if specified
|
||||
if model:
|
||||
genConfig["model"] = model
|
||||
|
||||
# Add common parameters at top level - only add if their toggle is enabled
|
||||
if useSteps:
|
||||
genConfig["steps"] = steps
|
||||
if useSeed:
|
||||
genConfig["seed"] = seed
|
||||
if useCFGScale:
|
||||
genConfig["CFGScale"] = CFGScale
|
||||
if usePrompts:
|
||||
if positivePrompt:
|
||||
genConfig["positivePrompt"] = positivePrompt
|
||||
if negativePrompt:
|
||||
genConfig["negativePrompt"] = negativePrompt
|
||||
|
||||
# Build settings object for advanced parameters
|
||||
settings = {}
|
||||
|
||||
# Common parameters - only add if their toggle is enabled
|
||||
if useSteps:
|
||||
settings["steps"] = steps
|
||||
if useSeed:
|
||||
settings["seed"] = seed
|
||||
if useCFGScale:
|
||||
settings["CFGScale"] = CFGScale
|
||||
if usePrompts:
|
||||
if positivePrompt:
|
||||
settings["positivePrompt"] = positivePrompt
|
||||
if negativePrompt:
|
||||
settings["negativePrompt"] = negativePrompt
|
||||
|
||||
# Clarity upscaler specific parameters
|
||||
if useClarityParams:
|
||||
@@ -249,5 +250,5 @@ class upscaler:
|
||||
print(f"[DEBUG] Error in Image Upscale Request: {str(e)}", flush=True)
|
||||
raise
|
||||
|
||||
images = rwUtils.convertImageB64List(genResult)
|
||||
return (images, )
|
||||
images = rwUtils.extractImageURLs(genResult)
|
||||
return (images,)
|
||||
@@ -577,6 +577,15 @@ def convertIMG2Tensor(b64img):
|
||||
tensorImage = torch.from_numpy(imageNP).squeeze()
|
||||
return tensorImage
|
||||
|
||||
def extractImageURLs(imageDataObject):
|
||||
"""Extract image URLs from API response and return as comma-separated string"""
|
||||
image_urls = []
|
||||
for result in imageDataObject.get("data", []):
|
||||
imageURL = result.get("imageURL")
|
||||
if imageURL:
|
||||
image_urls.append(imageURL)
|
||||
return ",".join(image_urls) if image_urls else ""
|
||||
|
||||
def convertImageB64List(imageDataObject):
|
||||
images = ()
|
||||
for result in imageDataObject["data"]:
|
||||
@@ -591,8 +600,8 @@ def convertImageB64List(imageDataObject):
|
||||
generatedImage = convertIMG2Tensor(generatedImage)
|
||||
images += (generatedImage,)
|
||||
else:
|
||||
# If no base64 data, try to get image URL (check both imageURL and mediaURL)
|
||||
imageURL = result.get("imageURL") or result.get("mediaURL")
|
||||
# If no base64 data, try to get image URL
|
||||
imageURL = result.get("imageURL")
|
||||
if imageURL:
|
||||
# Download image from URL and convert to tensor
|
||||
try:
|
||||
|
||||
+6
-32
@@ -1,14 +1,4 @@
|
||||
from .utils import runwareUtils as rwUtils
|
||||
import base64
|
||||
import io
|
||||
|
||||
|
||||
class SVGData:
|
||||
"""Wrapper class to match RecraftIO.SVG format for SaveSVGNode"""
|
||||
|
||||
def __init__(self, svgContent):
|
||||
svgBytes = io.BytesIO(svgContent.encode('utf-8'))
|
||||
self.data = [svgBytes]
|
||||
|
||||
|
||||
class vectorize:
|
||||
@@ -35,12 +25,12 @@ class vectorize:
|
||||
|
||||
DESCRIPTION = "Convert images to vector format using Runware's vectorization service."
|
||||
FUNCTION = "vectorizeImage"
|
||||
RETURN_TYPES = ("SVG",)
|
||||
RETURN_NAMES = ("SVG",)
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("IMAGE",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def vectorizeImage(self, **kwargs):
|
||||
"""Vectorize image and return SVG data"""
|
||||
"""Vectorize image and return SVG URL"""
|
||||
image = kwargs.get("Image")
|
||||
modelName = kwargs.get("Model", "recraft:1@1")
|
||||
|
||||
@@ -59,9 +49,9 @@ class vectorize:
|
||||
|
||||
self._validateResponse(genResult)
|
||||
|
||||
svgData = self._extractSvgData(genResult)
|
||||
svg_url = rwUtils.extractImageURLs(genResult)
|
||||
|
||||
return (svgData,)
|
||||
return (svg_url,)
|
||||
|
||||
def _buildGenConfig(self, model, imageUuid):
|
||||
"""Build generation configuration for API request"""
|
||||
@@ -72,7 +62,7 @@ class vectorize:
|
||||
"inputs": {
|
||||
"image": imageUuid
|
||||
},
|
||||
"outputType": "base64Data",
|
||||
"outputType": "URL",
|
||||
"outputFormat": "svg",
|
||||
}]
|
||||
|
||||
@@ -81,22 +71,6 @@ class vectorize:
|
||||
if "errors" in genResult:
|
||||
errorMessage = genResult["errors"][0]["message"]
|
||||
raise Exception(f"Vectorization failed: {errorMessage}")
|
||||
|
||||
if "data" not in genResult or len(genResult["data"]) == 0:
|
||||
raise Exception("No data returned from vectorization API")
|
||||
|
||||
def _extractSvgData(self, genResult):
|
||||
"""Extract SVG data from API response"""
|
||||
resultData = genResult["data"][0]
|
||||
|
||||
if "imageBase64Data" not in resultData:
|
||||
raise Exception("imageBase64Data not found in response")
|
||||
|
||||
base64Svg = resultData["imageBase64Data"]
|
||||
svgContent = base64.b64decode(base64Svg).decode('utf-8')
|
||||
svgData = SVGData(svgContent)
|
||||
|
||||
return svgData
|
||||
|
||||
|
||||
# Node class mappings
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
python-dotenv
|
||||
brotli
|
||||
zstd
|
||||
librosa
|
||||
librosa
|
||||
imageio
|
||||
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
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
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
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
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
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
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
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
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
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
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
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"id":"993f4b88-acb5-4f70-968f-e3a2c9c1c5b4","revision":0,"last_node_id":7,"last_link_id":8,"nodes":[{"id":6,"type":"SaveSVGNode","pos":[447.0441589355469,567.7747192382812],"size":[270,270],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"svg","name":"svg","type":"SVG","link":8},{"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","Node name for S&R":"SaveSVGNode"},"widgets_values":["svg/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":[7]},{"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":7,"type":"Runware Vectorize","pos":[146.1571044921875,546.4293823242188],"size":[270,58],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"Image","name":"Image","type":"IMAGE","link":7},{"localized_name":"Model","name":"Model","type":"COMBO","widget":{"name":"Model"},"link":null}],"outputs":[{"localized_name":"SVG","name":"SVG","type":"SVG","links":[8]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"8d75a6933feda430268dd0c555ecde9ccd99c7ef","Node name for S&R":"Runware Vectorize"},"widgets_values":["recraft:1@1"],"bgcolor":"#5345bf"}],"links":[[7,4,0,7,0,"IMAGE"],[8,7,0,6,0,"SVG"]],"groups":[],"config":{},"extra":{"ds":{"scale":1.02884607845781,"offset":[476.52544538804847,-345.82928772954745]}},"version":0.4}
|
||||
{"id":"993f4b88-acb5-4f70-968f-e3a2c9c1c5b4","revision":0,"last_node_id":10,"last_link_id":11,"nodes":[{"id":9,"type":"Runware Save Image","pos":[452.51519775390625,576.1388549804688],"size":[270,82],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"Images","name":"Images","type":"STRING","widget":{"name":"Images"},"link":11},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null}],"outputs":[],"properties":{"cnr_id":"ComfyUI-Runware","ver":"91646ada844167e36188b535ff60063735d10ca3","Node name for S&R":"Runware Save Image"},"widgets_values":["","ComfyUI"],"bgcolor":"#5345bf"},{"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":[10]},{"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":10,"type":"Runware Vectorize","pos":[162.64442443847656,533.0270385742188],"size":[270,58],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"Image","name":"Image","type":"IMAGE","link":10},{"localized_name":"Model","name":"Model","type":"COMBO","widget":{"name":"Model"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"STRING","links":[11]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"91646ada844167e36188b535ff60063735d10ca3","Node name for S&R":"Runware Vectorize"},"widgets_values":["recraft:1@1"],"bgcolor":"#5345bf"}],"links":[[10,4,0,10,0,"IMAGE"],[11,10,0,9,0,"STRING"]],"groups":[],"config":{},"extra":{"ds":{"scale":1.02884607845781,"offset":[476.67256864649244,-345.82928772954745]}},"version":0.4}
|
||||
Reference in New Issue
Block a user