Add New workflows + Add juggernaut flux models + Add support for deepCache and TeaCache + Add Multi Inference
This commit is contained in:
+8
-1
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -116,4 +116,4 @@ class bgremoval:
|
||||
|
||||
genResult = rwUtils.inferenecRequest([genConfig])
|
||||
images = rwUtils.convertImageB64List(genResult)
|
||||
return images
|
||||
return (images, )
|
||||
@@ -116,4 +116,4 @@ class controlNetPreprocessor:
|
||||
|
||||
genResult = rwUtils.inferenecRequest(genConfig)
|
||||
images = rwUtils.convertImageB64List(genResult)
|
||||
return images
|
||||
return (images, )
|
||||
@@ -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,
|
||||
},
|
||||
)
|
||||
@@ -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)
|
||||
|
||||
@@ -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)",
|
||||
|
||||
@@ -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)
|
||||
@@ -187,4 +187,4 @@ class photoMaker:
|
||||
|
||||
genResult = rwUtils.inferenecRequest(genConfig)
|
||||
images = rwUtils.convertImageB64List(genResult)
|
||||
return images
|
||||
return (images, )
|
||||
|
||||
@@ -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
@@ -40,4 +40,4 @@ class upscaler:
|
||||
|
||||
genResult = rwUtils.inferenecRequest(genConfig)
|
||||
images = rwUtils.convertImageB64List(genResult)
|
||||
return images
|
||||
return (images, )
|
||||
@@ -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
Reference in New Issue
Block a user