Added Support For Kontext Pro, Max Image Editing With Reference Images
This commit is contained in:
@@ -7,8 +7,9 @@ Welcome to **ComfyUI-Runware**! 🌟 This is the official integration for **[Run
|
||||
Imagine creating stunning images, refining details, or even removing backgrounds—all without needing a powerful GPU. With **Runware**, all the heavy lifting happens on our servers. No GPU? No problem! 🖥️💨
|
||||
|
||||
This integration adds a suite of custom nodes to ComfyUI, allowing you to:
|
||||
- Perform advanced image inference tasks
|
||||
- Perform advanced image inference tasks, including image generation and editing with powerful models.
|
||||
- Utilize PhotoMaker V2 pipelines
|
||||
- Leverage cutting-edge models like **Flux .1 Kontext Pro** and **Flux .1 Kontext Max** for superior image generation and editing.
|
||||
- Upscale images
|
||||
- Remove backgrounds
|
||||
- Leverage specialized models and LoRAs
|
||||
|
||||
+5
-1
@@ -7,6 +7,7 @@ from .modules.modelSearch import modelSearch
|
||||
from .modules.bridges import mainRoute
|
||||
from .modules.controlNet import controlNet
|
||||
from .modules.multiInference import multiInference
|
||||
from .modules.runwareBFL import runwareKontext
|
||||
from .modules.teaCache import teaCache
|
||||
from .modules.deepCache import deepCache
|
||||
from .modules.loraSearch import loraSearch
|
||||
@@ -22,8 +23,9 @@ from .modules.embeddingsCombine import embeddingsCombine
|
||||
from .modules.ipAdapter import ipAdapter
|
||||
from .modules.ipAdapterCombine import ipAdapterCombine
|
||||
from .modules.vaeSearch import vaeSearch
|
||||
from .modules.referenceImages import referenceImages
|
||||
|
||||
RUNWARE_COMFYUI_VERSION = "1.0.9 Beta"
|
||||
RUNWARE_COMFYUI_VERSION = "1.1.0 Beta"
|
||||
|
||||
RESET_COLOR = "\033[0m"
|
||||
BLUE_COLOR = "\033[94m"
|
||||
@@ -41,6 +43,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"Runware PhotoMaker V2": photoMaker,
|
||||
"Runware Image Upscaler": upscaler,
|
||||
"Runware Model Search": modelSearch,
|
||||
"Runware Kontext Inference": runwareKontext,
|
||||
"Runware Multi Inference": multiInference,
|
||||
"Runware TeaCache": teaCache,
|
||||
"Runware DeepCache": deepCache,
|
||||
@@ -58,6 +61,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"Runware ControlNet Combine": controlNetCombine,
|
||||
"Runware IPAdapter": ipAdapter,
|
||||
"Runware IPAdapters Combine": ipAdapterCombine,
|
||||
"Runware Reference Images": referenceImages,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
|
||||
@@ -48,6 +48,7 @@ const MODEL_LIST_TERMS = ["ModelList", "LoraList", "ControlNetList", "EmbeddingL
|
||||
|
||||
const RUNWARE_NODE_TYPES = {
|
||||
IMAGEINFERENCE: "Runware Image Inference",
|
||||
KONTEXTINFERENCE: "Runware Kontext Inference",
|
||||
OUTPAINT: "Runware Outpaint",
|
||||
PHOTOMAKER: "Runware PhotoMaker V2",
|
||||
MODELSEARCH: "Runware Model Search",
|
||||
@@ -70,6 +71,7 @@ const RUNWARE_NODE_TYPES = {
|
||||
EMBEDDING: "Runware Embedding Search",
|
||||
EMBEDDINGCOMBINE: "Runware Embedding Combine",
|
||||
VAE: "Runware VAE Search",
|
||||
REFERENCEIMAGES: "Runware Reference Images",
|
||||
};
|
||||
|
||||
const RUNWARE_NODE_PROPS = {
|
||||
@@ -78,6 +80,14 @@ const RUNWARE_NODE_PROPS = {
|
||||
liveDimensions: true,
|
||||
promptEnhancer: true,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.KONTEXTINFERENCE]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
promptEnhancer: true,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.REFERENCEIMAGES]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
},
|
||||
[RUNWARE_NODE_TYPES.OUTPAINT]: {
|
||||
bgColor: DEFAULT_BGCOLOR,
|
||||
colorModeOnly: true,
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
from .utils import runwareUtils as rwUtils
|
||||
|
||||
class referenceImages:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"Image 1": ("IMAGE", {
|
||||
"tooltip": "Specifies Reference Image 1 that will be used as reference for the subject. These reference images help the AI to maintain identity consistency during the generation process."
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"Image 2": ("IMAGE", {
|
||||
"tooltip": "Specifies Reference Image 2 that will be used as reference for the subject. These reference images help the AI to maintain identity consistency during the generation process."
|
||||
}),
|
||||
"Image 3": ("IMAGE", {
|
||||
"tooltip": "Specifies Reference Image 3 that will be used as reference for the subject. These reference images help the AI to maintain identity consistency during the generation process."
|
||||
}),
|
||||
"Image 4": ("IMAGE", {
|
||||
"tooltip": "Specifies Reference Image 4 that will be used as reference for the subject. These reference images help the AI to maintain identity consistency during the generation process."
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
DESCRIPTION = "Used With Runware Tasks To Provide Reference Images For The Subject. These Reference Images Help The AI To Maintain Identity Consistency During The Generation Process."
|
||||
FUNCTION = "referenceImages"
|
||||
RETURN_TYPES = ("RUNWAREREFERENCEIMAGES",)
|
||||
RETURN_NAMES = ("Reference Images",)
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def referenceImages(self, **kwargs):
|
||||
image1 = kwargs.get("Image 1")
|
||||
image2 = kwargs.get("Image 2", None)
|
||||
image3 = kwargs.get("Image 3", None)
|
||||
image4 = kwargs.get("Image 4", None)
|
||||
|
||||
imageList = [rwUtils.convertTensor2IMG(image1)]
|
||||
if (image2 is not None):
|
||||
imageList.append(rwUtils.convertTensor2IMG(image2))
|
||||
if (image3 is not None):
|
||||
imageList.append(rwUtils.convertTensor2IMG(image3))
|
||||
if (image4 is not None):
|
||||
imageList.append(rwUtils.convertTensor2IMG(image4))
|
||||
|
||||
return (imageList, )
|
||||
@@ -0,0 +1,138 @@
|
||||
from .utils import runwareUtils as rwUtils
|
||||
|
||||
class runwareKontext:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"Model": ([
|
||||
"bfl:3@1 (FLUX.1 Kontext Pro)",
|
||||
"bfl:3@1 (FLUX.1 Kontext Max)",
|
||||
], {
|
||||
"tooltip": "Select The Model You Want For Image Generation or Image Editing.",
|
||||
"default": "bfl:3@1 (FLUX.1 Kontext Pro)",
|
||||
}),
|
||||
"positivePrompt": ("STRING", {
|
||||
"multiline": True,
|
||||
"placeholder": "Text instruction to guide the model on generating the image. It is usually a sentence or a paragraph that provides positive guidance for the task. This parameter is essential to shape the desired results.\n\nYou Can Press (Ctrl + Alt + E) To Enhance The Prompt!",
|
||||
"tooltip": "Text instruction to guide the model on generating the image. You Can Also Press (Ctrl + Alt + E) To Enhance The Prompt!"
|
||||
}),
|
||||
"Prompt Upsampling": ("BOOLEAN", {
|
||||
"tooltip": "If Enabled it Will automatically modify the prompt at generation time for more creative results.",
|
||||
"default": False,
|
||||
"label_on": "Enabled",
|
||||
"label_off": "Disabled",
|
||||
}),
|
||||
"Aspect Ratio": ([
|
||||
"21:9 (Ultra-Wide / Landscape)",
|
||||
"16:9 (Wide / Landscape)",
|
||||
"4:3 (Standard / Landscape)",
|
||||
"3:2 (Classic Photo / Landscape)",
|
||||
"1:1 (Square)",
|
||||
"2:3 (Classic Photo / Portrait)",
|
||||
"3:4 (Standard / Portrait)",
|
||||
"9:16 (Vertical Video / Portrait)",
|
||||
"9:21 (Ultra-Tall / Portrait)"
|
||||
], {
|
||||
"default": "16:9 (Wide / Landscape)",
|
||||
"tooltip": "Adjust the dimensions of the generated image. This setting allows you to choose from various aspect ratios, such as 16:9 for wide images or 1:1 for square images. The width and height will be automatically adjusted based on the selected aspect ratio.",
|
||||
}),
|
||||
"seed": ("INT", {
|
||||
"tooltip": "A value used to randomize the image generation. If you want to make images reproducible (generate the same image multiple times), you can use the same seed value.",
|
||||
"default": rwUtils.genRandSeed(),
|
||||
"min": 1,
|
||||
"max": 9223372036854776000,
|
||||
}),
|
||||
"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",
|
||||
}),
|
||||
"batchSize": ("INT", {
|
||||
"tooltip": "The number of images to generate in a single request.",
|
||||
"default": 1,
|
||||
"min": 1,
|
||||
"max": 10,
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"Reference Images": ("RUNWAREREFERENCEIMAGES", {
|
||||
"tooltip": "Connect a Runware Reference Images Node to use reference images for image editing or generation.",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, positivePrompt):
|
||||
if (positivePrompt is not None and (positivePrompt == "" or len(positivePrompt) < 3 or len(positivePrompt) > 2000)):
|
||||
raise Exception(
|
||||
"Positive Prompt Must Be Between 3 And 2000 characters!")
|
||||
return True
|
||||
|
||||
DESCRIPTION = "Generate And Edit Images Using Runware BFL Kontext Models."
|
||||
FUNCTION = "kontextInference"
|
||||
RETURN_TYPES = ("IMAGE", "RUNWARETASK")
|
||||
RETURN_NAMES = ("IMAGE", "RW-Task")
|
||||
CATEGORY = "Runware"
|
||||
|
||||
def kontextInference(self, **kwargs):
|
||||
runwareModel = kwargs.get("Model")
|
||||
positivePrompt = kwargs.get("positivePrompt")
|
||||
promptUpsampling = kwargs.get("Prompt Upsampling")
|
||||
aspectRatio = kwargs.get("Aspect Ratio")
|
||||
multiInferenceMode = kwargs.get("Multi Inference Mode", False)
|
||||
referenceImages = kwargs.get("Reference Images", None)
|
||||
seed = kwargs.get("seed")
|
||||
batchSize = kwargs.get("batchSize", 1)
|
||||
|
||||
aspectRatioMap = {
|
||||
"21:9": (1568, 672),
|
||||
"16:9": (1392, 752),
|
||||
"4:3": (1184, 880),
|
||||
"3:2": (1248, 832),
|
||||
"1:1": (1024, 1024),
|
||||
"2:3": (832, 1248),
|
||||
"3:4": (880, 1184),
|
||||
"9:16": (752, 1392),
|
||||
"9:21": (672, 1568),
|
||||
}
|
||||
|
||||
secAspectRatio = aspectRatio.split(" ")[0]
|
||||
width, height = aspectRatioMap.get(secAspectRatio, (1024, 1024))
|
||||
|
||||
genConfig = [
|
||||
{
|
||||
"taskType": "imageInference",
|
||||
"taskUUID": rwUtils.genRandUUID(),
|
||||
"positivePrompt": positivePrompt,
|
||||
"height": height,
|
||||
"width": width,
|
||||
"model": runwareModel,
|
||||
"seed": seed,
|
||||
"outputType": "base64Data",
|
||||
"outputFormat": rwUtils.OUTPUT_FORMAT,
|
||||
"outputQuality": rwUtils.OUTPUT_QUALITY,
|
||||
"numberResults": batchSize,
|
||||
}
|
||||
]
|
||||
|
||||
if (referenceImages is not None):
|
||||
genConfig[0]["referenceImages"] = referenceImages
|
||||
|
||||
if (promptUpsampling):
|
||||
genConfig[0]["providerSettings"] = {
|
||||
"bfl": {
|
||||
"promptUpsampling": True
|
||||
}
|
||||
}
|
||||
|
||||
# For Debugging Purposes Only
|
||||
print(f"[Debugging] Task UUID: {genConfig[0]['taskUUID']}")
|
||||
|
||||
if (multiInferenceMode):
|
||||
return (None, genConfig)
|
||||
else:
|
||||
genResult = rwUtils.inferenecRequest(genConfig)
|
||||
images = rwUtils.convertImageB64List(genResult)
|
||||
return (images, None)
|
||||
Reference in New Issue
Block a user