diff --git a/README.md b/README.md index 649f79e..b6f7305 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/__init__.py b/__init__.py index f71331b..192884c 100644 --- a/__init__.py +++ b/__init__.py @@ -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 = { diff --git a/clientlibs/types.js b/clientlibs/types.js index 2ec2c48..18741af 100644 --- a/clientlibs/types.js +++ b/clientlibs/types.js @@ -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, diff --git a/modules/referenceImages.py b/modules/referenceImages.py new file mode 100644 index 0000000..b22d768 --- /dev/null +++ b/modules/referenceImages.py @@ -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, ) diff --git a/modules/runwareBFL.py b/modules/runwareBFL.py new file mode 100644 index 0000000..bf45434 --- /dev/null +++ b/modules/runwareBFL.py @@ -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)