diff --git a/__init__.py b/__init__.py index 987d343..88357d3 100644 --- a/__init__.py +++ b/__init__.py @@ -19,7 +19,7 @@ from .modules.ipAdapter import ipAdapter from .modules.ipAdapterCombine import ipAdapterCombine from .modules.vaeSearch import vaeSearch -RUNWARE_COMFYUI_VERSION = "1.0.3 Beta" +RUNWARE_COMFYUI_VERSION = "1.0.4 Beta" RESET_COLOR = "\033[0m" BLUE_COLOR = "\033[94m" diff --git a/clientlibs/types.js b/clientlibs/types.js index d3cf86b..4b16a9f 100644 --- a/clientlibs/types.js +++ b/clientlibs/types.js @@ -57,6 +57,8 @@ const RUNWARE_NODE_TYPES = { REFINER: "Runware Refiner", LORACOMBINE: "Runware Lora Combine", CONTROLNETCOMBINE: "Runware ControlNet Combine", + IPADAPTER: "Runware IPAdapter", + IPADAPTERSCOMBINE: "Runware IPAdapters Combine", IMAGEMASKING: "Runware Image Masking", CONTROLNETPREPROCESSING: "Runware ControlNet PreProcessor", APIMANAGER: "Runware API Manager", @@ -121,6 +123,14 @@ const RUNWARE_NODE_PROPS = { bgColor: DEFAULT_BGCOLOR, colorModeOnly: true, }, + [RUNWARE_NODE_TYPES.IPADAPTER]: { + bgColor: DEFAULT_BGCOLOR, + colorModeOnly: true, + }, + [RUNWARE_NODE_TYPES.IPADAPTERSCOMBINE]: { + bgColor: DEFAULT_BGCOLOR, + colorModeOnly: true, + }, [RUNWARE_NODE_TYPES.CONTROLNETCOMBINE]: { bgColor: DEFAULT_BGCOLOR, colorModeOnly: true, diff --git a/modules/bgremoval.py b/modules/bgremoval.py index 490c048..2813109 100644 --- a/modules/bgremoval.py +++ b/modules/bgremoval.py @@ -1,6 +1,20 @@ from .utils import runwareUtils as rwUtils class bgremoval: + RUNWARE_RMBG_MODELS = { + "RemBG 1.4": "runware:109@1", + "Bria RMBG 2.0": "runware:110@1", + "BiRefNet v1 Base": "runware:112@1", + "BiRefNet v1 Base - COD": "runware:112@2", + "BiRefNet Dis": "runware:112@3", + "BiRefNet General": "runware:112@5", + "BiRefNet General RES 512x512": "runware:112@6", + "BiRefNet HRSOD DHU": "runware:112@7", + "BiRefNet Massive TR DIS5K TES": "runware:112@8", + "BiRefNet Matting": "runware:112@9", + "BiRefNet Portrait": "runware:112@10" + } + @classmethod def INPUT_TYPES(cls): return { @@ -8,6 +22,10 @@ class bgremoval: "Image": ("IMAGE", { "tooltip": "Specifies the input image to be processed." }), + "Model": (list(cls.RUNWARE_RMBG_MODELS.keys()), { + "tooltip": "Select the background removal model to use. Different models have varying strengths depending on image content and complexity.", + "default": "RemBG 1.4", + }), }, "optional": { "Post Process Mask": ("BOOLEAN", { @@ -57,6 +75,7 @@ class bgremoval: def rembg(self, **kwargs): image = kwargs.get("Image") + modelName = kwargs.get("Model", "RemBG 1.4") postProcessMask = kwargs.get("Post Process Mask", False) returnOnlyMask = kwargs.get("Return Only Mask", False) alphaMatting = kwargs.get("Alpha Matting", False) @@ -64,26 +83,37 @@ class bgremoval: alphaMattingBackgroundThreshold = kwargs.get("Alpha Matting Background Threshold", 10) alphaMattingErodeSize = kwargs.get("Alpha Matting Erode Size", 10) outputFormat = kwargs.get("outputFormat", "WEBP") + modelAIR = self.RUNWARE_RMBG_MODELS.get(modelName, "runware:109@1") + includeExtraSettings = postProcessMask or returnOnlyMask or alphaMatting - genConfig = [ - { - "taskType": "imageBackgroundRemoval", - "taskUUID": rwUtils.genRandUUID(), - "inputImage": rwUtils.convertTensor2IMG(image), + if modelAIR != "runware:109@1" and includeExtraSettings: + raise ValueError( + f"Oops! The selected model '{modelName}' does not support additional settings!\n" + "Please switch to 'RemBG 1.4' if you wish to use these features." + ) + + genConfig = { + "taskType": "imageBackgroundRemoval", + "taskUUID": rwUtils.genRandUUID(), + "inputImage": rwUtils.convertTensor2IMG(image), + "model": modelAIR, + "outputFormat": outputFormat, + "outputQuality": rwUtils.OUTPUT_QUALITY, + "outputType": "base64Data", + } + + if includeExtraSettings: + settings = { "postProcessMask": postProcessMask, "returnOnlyMask": returnOnlyMask, "alphaMatting": alphaMatting, - "outputFormat": outputFormat, - "outputQuality": rwUtils.OUTPUT_QUALITY, - "outputType": "base64Data", } - ] + if alphaMatting: + settings["alphaMattingForegroundThreshold"] = alphaMattingForegroundThreshold + settings["alphaMattingBackgroundThreshold"] = alphaMattingBackgroundThreshold + settings["alphaMattingErodeSize"] = alphaMattingErodeSize + genConfig["settings"] = settings - if(alphaMatting): - genConfig[0]["alphaMattingForegroundThreshold"] = alphaMattingForegroundThreshold - genConfig[0]["alphaMattingBackgroundThreshold"] = alphaMattingBackgroundThreshold - genConfig[0]["alphaMattingErodeSize"] = alphaMattingErodeSize - - genResult = rwUtils.inferenecRequest(genConfig) + genResult = rwUtils.inferenecRequest([genConfig]) images = rwUtils.convertImageB64List(genResult) return images \ No newline at end of file diff --git a/modules/imageInference.py b/modules/imageInference.py index 83a3055..3b5edf2 100644 --- a/modules/imageInference.py +++ b/modules/imageInference.py @@ -60,7 +60,7 @@ class txt2img: "default": 6.5, "min": 1.0, "max": 30.0, - "step": 0.5, + "step": 0.1, }), "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.", @@ -79,7 +79,7 @@ class txt2img: "default": 0.8, "min": 0.0, "max": 1.0, - "step": 0.1, + "step": 0.01, }), "Mask Margin": ("BOOLEAN", { "tooltip": "Enables Or Disables Mask Margin Feature.", diff --git a/modules/ipAdapter.py b/modules/ipAdapter.py index e7b83f3..e7a1a7c 100644 --- a/modules/ipAdapter.py +++ b/modules/ipAdapter.py @@ -1,25 +1,27 @@ from .utils import runwareUtils as rwUtils class ipAdapter: + RUNWARE_IPADAPTER_MODELS = { + "IP Adapter SDXL": "runware:55@1", + "IP Adapter SDXL Plus": "runware:55@2", + "IP Adapter SDXL Plus Face": "runware:55@3", + "IP Adapter SDXL Vit-H": "runware:55@4", + "IP Adapter SD 1.5": "runware:55@5", + "IP Adapter SD 1.5 Plus": "runware:55@6", + "IP Adapter SD 1.5 Light": "runware:55@7", + "IP Adapter SD 1.5 Plus Face": "runware:55@8", + "IP Adapter SD 1.5 Full Face": "runware:55@9", + "IP Adapter SD 1.5 Vit-G": "runware:55@10" + } + @classmethod def INPUT_TYPES(cls): return { "required": { "Reference Image": ("IMAGE",), - "Model": ([ - "runware:55@1 (IP Adapter SDXL)", - "runware:55@2 (IP Adapter SDXL Plus)", - "runware:55@3 (IP Adapter SDXL Plus Face)", - "runware:55@4 (IP Adapter SDXL Vit-H)", - "runware:55@5 (IP Adapter SD 1.5)", - "runware:55@6 (IP Adapter SD 1.5 Plus)", - "runware:55@7 (IP Adapter SD 1.5 Light)", - "runware:55@8 (IP Adapter SD 1.5 Plus Face)", - "runware:55@9 (IP Adapter SD 1.5 Full Face)", - "runware:55@10 (IP Adapter SD 1.5 Vit-G)" - ], { + "Model": (list(cls.RUNWARE_IPADAPTER_MODELS.keys()), { "tooltip": "Choose IP Adapter model to use for reference-based image generation.", - "default": "runware:55@1 (IP Adapter SDXL)", + "default": "IP Adapter SDXL", }), "weight": ("FLOAT", { "default": 1.0, @@ -39,9 +41,9 @@ class ipAdapter: def ipAdapter(self, **kwargs): refImage = kwargs.get("Reference Image") - Model = kwargs.get("Model") + modelName = kwargs.get("Model") weight = kwargs.get("weight") - modelAirCode = Model.split(" ")[0] + modelAirCode = self.RUNWARE_IPADAPTER_MODELS.get(modelName) guideImage = rwUtils.convertTensor2IMG(refImage) return ({ "model": modelAirCode, diff --git a/modules/utils/runwareUtils.py b/modules/utils/runwareUtils.py index e581c12..31bb51c 100644 --- a/modules/utils/runwareUtils.py +++ b/modules/utils/runwareUtils.py @@ -36,8 +36,8 @@ RUNWARE_REMBG_OUTPUT_FORMATS = { ) } -MAX_RETRIES = 2 -RETRY_COOLDOWN = 2 +MAX_RETRIES = 4 +RETRY_COOLDOWNS = [1, 2, 5, 10] session = requests.Session() adapter = HTTPAdapter(pool_connections=10, pool_maxsize=10) @@ -52,7 +52,9 @@ def generalRequestWrapper(recaller, *args, **kwargs): if attempt == MAX_RETRIES: raise else: - time.sleep(RETRY_COOLDOWN) + cooldown = RETRY_COOLDOWNS[attempt] + print(f"[Runware] Error API Request Failed! Retrying in {cooldown} seconds... (Attempt {attempt+1}/{MAX_RETRIES})") + time.sleep(cooldown) continue return False diff --git a/workflows/Runware_Basic_Image_Inference_IPAdapter.json b/workflows/Runware_Basic_Image_Inference_IPAdapter.json new file mode 100644 index 0000000..317f508 --- /dev/null +++ b/workflows/Runware_Basic_Image_Inference_IPAdapter.json @@ -0,0 +1 @@ +{"last_node_id":5,"last_link_id":4,"nodes":[{"id":5,"type":"LoadImage","pos":[-748.4779663085938,-211.1426239013672],"size":[328.1999816894531,359.1000061035156],"flags":{},"order":0,"mode":0,"inputs":[],"outputs":[{"name":"IMAGE","localized_name":"IMAGE","type":"IMAGE","links":[4]},{"name":"MASK","localized_name":"MASK","type":"MASK","links":null}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["ggasdw.jpg","image"]},{"id":1,"type":"PreviewImage","pos":[134.92190551757812,-558.04248046875],"size":[716.7999877929688,717.5],"flags":{},"order":4,"mode":0,"inputs":[{"name":"images","localized_name":"images","type":"IMAGE","link":1}],"outputs":[],"properties":{"Node name for S&R":"PreviewImage"},"widgets_values":[]},{"id":3,"type":"Runware Model Search","pos":[-731.1779174804688,-549.74267578125],"size":[310.5999755859375,154],"flags":{},"order":1,"mode":0,"inputs":[],"outputs":[{"name":"Runware Model","localized_name":"Runware Model","type":"RUNWAREMODEL","links":[2]}],"properties":{"Node name for S&R":"Runware Model Search"},"widgets_values":["","All","Base Model","civitai:101055@128078 (SDXL v1.0 VAE fix)",false],"bgcolor":"#5345bf"},{"id":4,"type":"Runware IPAdapter","pos":[-736.3779907226562,-344.2424011230469],"size":[317.4000244140625,82],"flags":{},"order":2,"mode":0,"inputs":[{"name":"Reference Image","localized_name":"Reference Image","type":"IMAGE","link":4}],"outputs":[{"name":"IPAdapter","localized_name":"IPAdapter","type":"RUNWAREIPAdapter","links":[3]}],"properties":{"Node name for S&R":"Runware IPAdapter"},"widgets_values":["IP Adapter SDXL",1],"bgcolor":"#5345bf"},{"id":2,"type":"Runware Image Inference","pos":[-375.5780334472656,-558.5426635742188],"size":[487,719],"flags":{},"order":3,"mode":0,"inputs":[{"name":"Model","localized_name":"Model","type":"RUNWAREMODEL","link":2},{"name":"Lora","localized_name":"Lora","type":"RUNWARELORA","shape":7,"link":null},{"name":"IPAdapters","localized_name":"IPAdapters","type":"RUNWAREIPAdapter","shape":7,"link":3},{"name":"ControlNet","localized_name":"ControlNet","type":"RUNWARECONTROLNET","shape":7,"link":null},{"name":"Refiner","localized_name":"Refiner","type":"RUNWAREREFINER","shape":7,"link":null},{"name":"seedImage","localized_name":"seedImage","type":"IMAGE","shape":7,"link":null},{"name":"maskImage","localized_name":"maskImage","type":"MASK","shape":7,"link":null},{"name":"Embeddings","localized_name":"Embeddings","type":"RUNWAREEMBEDDING","shape":7,"link":null},{"name":"VAE","localized_name":"VAE","type":"RUNWAREVAE","shape":7,"link":null}],"outputs":[{"name":"IMAGE","localized_name":"IMAGE","type":"IMAGE","links":[1]}],"properties":{"Node name for S&R":"Runware Image Inference"},"widgets_values":["A stylish young woman standing confidently in a vibrant urban setting, wearing a fitted black t-shirt with a bold white skull design, detailed with subtle cracks and shading, paired with ripped blue jeans and combat boots, her hair flowing naturally in the wind, cinematic lighting, highly detailed, photorealistic, 8k resolution, sharp focus, rich textures, dynamic composition, soft bokeh background, vivid colors, intricate details on the skull graphic","blurry, low resolution, distorted, overexposed, underexposed, grainy, artifacts, extra limbs, missing details, poorly drawn hands, unnatural poses, dull colors, oversaturated, flat background, text errors, watermark, crowded composition, deformed face","Disabled","Square HD (1024x1024)",1024,1024,50,"DPM++ 2M SDE",8,599278031163006,"randomize",0,0.8,false,32,4],"bgcolor":"#5345bf"}],"links":[[1,2,0,1,0,"IMAGE"],[2,3,0,2,0,"RUNWAREMODEL"],[3,4,0,2,2,"RUNWAREIPAdapter"],[4,5,0,4,0,"IMAGE"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.9090909090909091,"offset":[1022.3779979367997,667.6425882124634]}},"version":0.4} \ No newline at end of file