Added Support For Kontext Pro, Max Image Editing With Reference Images

This commit is contained in:
Jack
2025-05-30 15:19:43 +03:00
parent 26c313731e
commit b5c46a48e6
5 changed files with 200 additions and 2 deletions
+2 -1
View File
@@ -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
View File
@@ -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 = {
+10
View File
@@ -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,
+45
View File
@@ -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, )
+138
View File
@@ -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)