Add New workflows + Add juggernaut flux models + Add support for deepCache and TeaCache + Add Multi Inference

This commit is contained in:
Jack
2025-04-26 06:30:51 +03:00
parent 9a8ddcb5c3
commit c7171c4d12
14 changed files with 239 additions and 10 deletions
+8 -1
View File
@@ -6,6 +6,9 @@ from .modules.upscaler import upscaler
from .modules.modelSearch import modelSearch
from .modules.bridges import mainRoute
from .modules.controlNet import controlNet
from .modules.multiInference import multiInference
from .modules.teaCache import teaCache
from .modules.deepCache import deepCache
from .modules.loraSearch import loraSearch
from .modules.loraCombine import loraCombine
from .modules.refiner import refiner
@@ -20,7 +23,7 @@ from .modules.ipAdapter import ipAdapter
from .modules.ipAdapterCombine import ipAdapterCombine
from .modules.vaeSearch import vaeSearch
RUNWARE_COMFYUI_VERSION = "1.0.8 Beta"
RUNWARE_COMFYUI_VERSION = "1.0.9 Beta"
RESET_COLOR = "\033[0m"
BLUE_COLOR = "\033[94m"
@@ -38,6 +41,9 @@ NODE_CLASS_MAPPINGS = {
"Runware PhotoMaker V2": photoMaker,
"Runware Image Upscaler": upscaler,
"Runware Model Search": modelSearch,
"Runware Multi Inference": multiInference,
"Runware TeaCache": teaCache,
"Runware DeepCache": deepCache,
"Runware Lora Search": loraSearch,
"Runware Embedding Search": embeddingSearch,
"Runware VAE Search": vaeSearch,
@@ -59,6 +65,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"Runware Lora Search": "Runware Lora",
"Runware Embedding Search": "Runware Embedding",
"Runware VAE Search": "Runware VAE",
"Runware Multi Inference": "Runware Multi Inference [BETA]",
}
WEB_DIRECTORY = "./clientlibs"
+15
View File
@@ -51,6 +51,9 @@ const RUNWARE_NODE_TYPES = {
OUTPAINT: "Runware Outpaint",
PHOTOMAKER: "Runware PhotoMaker V2",
MODELSEARCH: "Runware Model Search",
MULTIINFERENCE: "Runware Multi Inference",
TEACACHE: "Runware TeaCache",
DEEPCACHE: "Runware DeepCache",
LORASEARCH: "Runware Lora Search",
CONTROLNET: "Runware ControlNet",
BGREMOVAL: "Runware Background Removal",
@@ -88,6 +91,18 @@ const RUNWARE_NODE_PROPS = {
bgColor: DEFAULT_BGCOLOR,
liveSearch: true,
},
[RUNWARE_NODE_TYPES.MULTIINFERENCE]: {
bgColor: DEFAULT_BGCOLOR,
colorModeOnly: true,
},
[RUNWARE_NODE_TYPES.TEACACHE]: {
bgColor: DEFAULT_BGCOLOR,
colorModeOnly: true,
},
[RUNWARE_NODE_TYPES.DEEPCACHE]: {
bgColor: DEFAULT_BGCOLOR,
colorModeOnly: true,
},
[RUNWARE_NODE_TYPES.LORASEARCH]: {
bgColor: DEFAULT_BGCOLOR,
liveSearch: true,
+1 -1
View File
@@ -116,4 +116,4 @@ class bgremoval:
genResult = rwUtils.inferenecRequest([genConfig])
images = rwUtils.convertImageB64List(genResult)
return images
return (images, )
+1 -1
View File
@@ -116,4 +116,4 @@ class controlNetPreprocessor:
genResult = rwUtils.inferenecRequest(genConfig)
images = rwUtils.convertImageB64List(genResult)
return images
return (images, )
+45
View File
@@ -0,0 +1,45 @@
class deepCache:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"DeepCache Interval": (
"INT",
{
"tooltip": "Represents the frequency of feature caching, specified as the number of steps between each cache operation.\n\nA larger interval value will make inference faster but may impact quality. A smaller interval prioritizes quality over speed.",
"default": 3,
"min": 1,
"max": 5,
"step": 1,
},
),
"DeepCache BranchId": (
"INT",
{
"tooltip": "Determines which branch of the network (ordered from the shallowest to the deepest layer) is responsible for executing the caching processes.\n\nLower branch IDs (e.g., 0) result in more aggressive caching for faster generation, while higher branch IDs produce more conservative caching with potentially higher quality results.",
"default": 0,
"min": 0,
"max": 5,
"step": 1,
},
),
},
}
DESCRIPTION = "Can Be connected to Runware Inference to accelerate image generation by reusing past computations.\n\nDeepCache feature, which speeds up diffusion-based image generation by caching internal feature maps from the neural network.\n\nDeepCache can provide significant performance improvements for high-throughput scenarios or when generating multiple similar images."
FUNCTION = "deepCache"
RETURN_TYPES = ("RUNWAREACCELERATOR",)
RETURN_NAMES = ("Runware Accelerator",)
CATEGORY = "Runware"
def deepCache(self, **kwargs):
deepCacheInterval = kwargs.get("DeepCache Interval")
deepCacheBranchId = kwargs.get("DeepCache BranchId")
return (
{
"deepCache": True,
# "deepCacheInterval": deepCacheInterval,
"deepCacheBranchId": deepCacheBranchId,
},
)
+21 -4
View File
@@ -19,6 +19,12 @@ class txt2img:
"placeholder": "Negative Prompt: a text instruction to guide the model on generating the image. It is usually a sentence or a paragraph that provides negative guidance for the task. This parameter helps to avoid certain undesired results.",
"tooltip": "Negative Prompt: a text instruction to guide the model on generating the image."
}),
"Multi Inference Mode": ("BOOLEAN", {
"tooltip": "If Enabled the node will skip the image generation process and will only return the Runware Task Object to be used in the Multi Inference Node.",
"default": False,
"label_on": "Enabled",
"label_off": "Disabled",
}),
"Prompt Weighting": (["Disabled", "sdEmbeds", "Compel"], {
"default": "Disabled",
"tooltip": "Prompt weighting allows you to adjust how strongly different parts of your prompt influence the generated image.\n\nChoose between \"compel\" notation with advanced weighting operations or \"sdEmbeds\" for simple emphasis adjustments.\n\nCompel Example: \"small+ dog, pixar style\"\n\nsdEmbeds Example: \"(small:2.5) dog, pixar style\"",
@@ -101,6 +107,9 @@ class txt2img:
}),
},
"optional": {
"Accelerator": ("RUNWAREACCELERATOR", {
"tooltip": "Connect a Runware Accelerator Node (TeaCache, DeepCache) to speed up the image generation process.",
}),
"Lora": ("RUNWARELORA", {
"tooltip": "Connect a Runware Lora From Lora Search Node Or Lora Combine For Multiple Lora's Together.",
}),
@@ -143,15 +152,18 @@ class txt2img:
DESCRIPTION = "Generates Images Lightning Fast With Runware Image Inference Sonic Engine."
FUNCTION = "generateImage"
RETURN_TYPES = ("IMAGE",)
RETURN_TYPES = ("IMAGE", "RUNWARETASK")
RETURN_NAMES = ("IMAGE", "RW-Task")
CATEGORY = "Runware"
def generateImage(self, **kwargs):
runwareModel = kwargs.get("Model")
positivePrompt = kwargs.get("positivePrompt")
negativePrompt = kwargs.get("negativePrompt", None)
multiInferenceMode = kwargs.get("Multi Inference Mode", False)
promptWeighting = kwargs.get("Prompt Weighting", "Disabled")
runwareControlNet = kwargs.get("ControlNet", None)
runwareAccelerator = kwargs.get("Accelerator", None)
runwareLora = kwargs.get("Lora", None)
runwareOutpainting = kwargs.get("Outpainting", None)
runwareIPAdapters = kwargs.get("IPAdapters", None)
@@ -205,6 +217,8 @@ class txt2img:
genConfig[0]["promptWeighting"] = "sdEmbeds"
else:
genConfig[0]["promptWeighting"] = "compel"
if(runwareAccelerator is not None):
genConfig[0]["acceleratorOptions"] = runwareAccelerator
if (runwareLora is not None):
if (isinstance(runwareLora, list)):
genConfig[0]["lora"] = runwareLora
@@ -238,6 +252,9 @@ class txt2img:
if (enableMaskMargin):
genConfig[0]["maskMargin"] = maskImageMargin
genResult = rwUtils.inferenecRequest(genConfig)
images = rwUtils.convertImageB64List(genResult)
return images
if (multiInferenceMode):
return (None, genConfig)
else:
genResult = rwUtils.inferenecRequest(genConfig)
images = rwUtils.convertImageB64List(genResult)
return (images, None)
+2
View File
@@ -33,6 +33,8 @@ class modelSearch:
"default": "Base Model",
}),
"ModelList": ([
"rundiffusion:110@101 (Juggernaut Lightning Flux by RunDiffusion)",
"rundiffusion:130@100 (Juggernaut Pro Flux by RunDiffusion)",
"runware:100@1 (Flux Schnell)",
"runware:101@1 (Flux Dev)",
"runware:5@1 (SD3)",
+108
View File
@@ -0,0 +1,108 @@
import asyncio
from .utils import runwareUtils as rwUtils
from comfy_execution.graph import ExecutionBlocker
class multiInference:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"Task 1": (
"RUNWARETASK",
{
"tooltip": "Connect a Runware Task From Any Inference Node.",
},
),
},
"optional": {
"Task 2": (
"RUNWARETASK",
{
"tooltip": "Connect a Runware Task From Any Inference Node.",
},
),
"Task 3": (
"RUNWARETASK",
{
"tooltip": "Connect a Runware Task From Any Inference Node.",
},
),
"Task 4": (
"RUNWARETASK",
{
"tooltip": "Connect a Runware Task From Any Inference Node.",
},
),
},
}
DESCRIPTION = "Allows you to Run Multiple Inference Tasks in Parallel."
FUNCTION = "multiInference"
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", "IMAGE")
RETURN_NAMES = ("Result 1", "Result 2", "Result 3", "Result 4")
CATEGORY = "Runware"
def multiInference(self, **kwargs):
tasksData = [kwargs.get(f"Task {i}", None) for i in range(1, 5)]
validTasks = [task for task in tasksData if task is not None]
if not validTasks:
raise Exception("Error: No valid tasks provided for Multi Inference!")
taskIncidents = {}
async def runInference(taskData, taskIndex, oindex):
try:
print(f"[Debugging] Task {oindex + 1} UUID => {taskData[0]['taskUUID']}")
loop = asyncio.get_running_loop()
result = await loop.run_in_executor(
None, rwUtils.inferenecRequest, taskData
)
images = rwUtils.convertImageB64List(result)
return images
except Exception as e:
print(f"\n---- Runware Multi Inference Task {oindex + 1} Failed ----")
print(f"Task-Type: {taskData[0]['taskType']}")
print(f"Task-UUID: {taskData[0]['taskUUID']}")
print(f"{e}")
print(f"-------------------\n")
taskIncidents[taskIndex] = e
return ExecutionBlocker(None)
async def main():
coroutines = []
valid_indices = [idx for idx, t in enumerate(tasksData) if t is not None]
for i, config in enumerate(validTasks):
original_index = valid_indices[i]
coroutines.append(runInference(config, i, original_index))
results = await asyncio.gather(*coroutines, return_exceptions=False)
return results
try:
loop = asyncio.get_event_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
finalResults = loop.run_until_complete(main())
optResult = [ExecutionBlocker(None)] * 4
rindex = 0
workingTasks = 0
for i, task_config in enumerate(tasksData):
if task_config is not None:
result = finalResults[rindex]
if result is not None and not isinstance(result, ExecutionBlocker):
workingTasks += 1
optResult[i] = result
rindex += 1
if workingTasks == 0 and len(validTasks) > 0:
firstError = min(taskIncidents.keys())
raise Exception(
f"Error in Task {firstError + 1} => {taskIncidents[firstError]}"
)
return tuple(optResult)
+1 -1
View File
@@ -187,4 +187,4 @@ class photoMaker:
genResult = rwUtils.inferenecRequest(genConfig)
images = rwUtils.convertImageB64List(genResult)
return images
return (images, )
+33
View File
@@ -0,0 +1,33 @@
class teaCache:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"TeaCache Distance": (
"FLOAT",
{
"tooltip": "Controls the aggressiveness of the TeaCache feature.\n\nValues range from 0.0 (most conservative) to 1.0 (most aggressive).\n\nLower values prioritize quality by being more selective about which computations to reuse, while higher values prioritize speed by reusing more computations.",
"default": 0.5,
"min": 0.0,
"max": 1.0,
"step": 0.1,
},
),
},
}
DESCRIPTION = "Can Be connected to Runware Inference to accelerate image generation by reusing past computations.\n\nTeaCache is specifically designed for transformer-based models such as Flux and SD3, and does not work with UNet models like SDXL or SD1.5."
FUNCTION = "teaCache"
RETURN_TYPES = ("RUNWAREACCELERATOR",)
RETURN_NAMES = ("Runware Accelerator",)
CATEGORY = "Runware"
def teaCache(self, **kwargs):
teaCacheDistance = kwargs.get("TeaCache Distance")
return (
{
"teaCache": True,
"teaCacheDistance": round(teaCacheDistance, 2),
},
)
+1 -1
View File
@@ -40,4 +40,4 @@ class upscaler:
genResult = rwUtils.inferenecRequest(genConfig)
images = rwUtils.convertImageB64List(genResult)
return images
return (images, )
+1 -1
View File
@@ -411,4 +411,4 @@ def convertImageB64List(imageDataObject):
generatedImage = convertIMG2Tensor(generatedImage)
images += (generatedImage,)
images = torch.stack(images, dim=0)
return (images,)
return images
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long