import os import random import sys import torch from typing import Sequence, Mapping, Any, Union import gradio as gr from huggingface_hub import hf_hub_download import spaces import sys from comfy import model_management from nodes import NODE_CLASS_MAPPINGS print("Starting Space...") os.makedirs('models/ultralytics/bbox',exist_ok=True) os.makedirs('models/inpaint',exist_ok=True) os.makedirs('models/sams',exist_ok=True) def download_model(repo_id, filename, local_dir): local_path = os.path.join(local_dir, filename) if not os.path.exists(local_path): hf_hub_download(repo_id=repo_id, filename=filename, local_dir=local_dir, force_download=True) else: print(f"Model {filename} already exists. Skipping download.") download_model("Acly/MAT", "MAT_Places512_G_fp16.safetensors", "models/inpaint") download_model("stabilityai/sd-vae-ft-mse-original", "vae-ft-mse-840000-ema-pruned.safetensors", "models/vae") download_model("Ultralytics/YOLOv8", "yolov8m.pt", "models/ultralytics/bbox") download_model("xingren23/comfyflow-models", "sams/sam_vit_b_01ec64.pth", "models/sams") # ------ JIT's Files -------- download_model("camenduru/YoloWorld-EfficientSAM", "efficient_sam_s_cpu.jit", "custom_nodes/ComfyUI-YoloWorld-EfficientSAM") download_model("camenduru/YoloWorld-EfficientSAM", "efficient_sam_s_gpu.jit", "custom_nodes/ComfyUI-YoloWorld-EfficientSAM") print("Downloaded Models") def get_value_at_index(obj: Union[Sequence, Mapping], index: int) -> Any: """Returns the value at the given index of a sequence or mapping. If the object is a sequence (like list or string), returns the value at the given index. If the object is a mapping (like a dictionary), returns the value at the index-th key. Some return a dictionary, in these cases, we look for the "results" key Args: obj (Union[Sequence, Mapping]): The object to retrieve the value from. index (int): The index of the value to retrieve. Returns: Any: The value at the given index. Raises: IndexError: If the index is out of bounds for the object and the object is not a mapping. """ if obj is None: raise ValueError("Object is None, cannot retrieve index.") try: return obj[index] except (KeyError, IndexError, TypeError): return obj.get("result", [])[index] if isinstance(obj, dict) and "result" in obj else None def find_path(name: str, path: str = None) -> str: """ Recursively looks at parent folders starting from the given path until it finds the given name. Returns the path as a Path object if found, or None otherwise. """ # If no path is given, use the current working directory if path is None: path = os.getcwd() # Check if the current directory contains the name if name in os.listdir(path): path_name = os.path.join(path, name) print(f"{name} found: {path_name}") return path_name # Get the parent directory parent_directory = os.path.dirname(path) # If the parent directory is the same as the current directory, we've reached the root and stop the search if parent_directory == path: return None # Recursively call the function with the parent directory return find_path(name, parent_directory) def add_comfyui_directory_to_sys_path() -> None: """ Add 'ComfyUI' to the sys.path """ comfyui_path = find_path("ComfyUI") if comfyui_path and os.path.isdir(comfyui_path): sys.path.append(comfyui_path) print(f"'{comfyui_path}' added to sys.path") else: print("⚠️ Warning: 'ComfyUI' directory not found. Ensure it is installed properly.") def add_extra_model_paths() -> None: load_extra_path_config = None try: from main import load_extra_path_config except ImportError: print("Could not import load_extra_path_config from main.py.") try: from utils.extra_config import load_extra_path_config except ImportError: print("Could not import load_extra_path_config from utils.extra_config. Skipping extra model paths.") extra_model_paths = find_path("extra_model_paths.yaml") if extra_model_paths is not None and load_extra_path_config is not None: load_extra_path_config(extra_model_paths) else: print("Skipping extra model paths: config file or loader function not found.") # add_comfyui_directory_to_sys_path() add_extra_model_paths() print("Model paths added") def import_custom_nodes() -> None: """Find all custom nodes in the custom_nodes folder and add those node objects to NODE_CLASS_MAPPINGS This function sets up a new asyncio event loop, initializes the PromptServer, creates a PromptQueue, and initializes the custom nodes. """ import asyncio import execution from nodes import init_extra_nodes import server # Creating a new event loop and setting it as the default loop loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) NODE_CLASS_MAPPINGS.clear() # Clear previous mappings print("Reloading custom nodes...") # Creating an instance of PromptServer with the loop server_instance = server.PromptServer(loop) execution.PromptQueue(server_instance) # Initializing custom nodes init_extra_nodes() print("Custom Nodes Loaded:", NODE_CLASS_MAPPINGS.keys()) import_custom_nodes() from nodes import NODE_CLASS_MAPPINGS @spaces.GPU(duration=120) def object_remover(object_name, image) : import_custom_nodes() with torch.inference_mode(): loadimage_1 = loadimage.load_image(image=image) yoloworld_esam_zho = NODE_CLASS_MAPPINGS["Yoloworld_ESAM_Zho"]() yoloworld_esam_zho_2 = yoloworld_esam_zho.yoloworld_esam_image( categories=object_name, confidence_threshold=0.10000000000000002, iou_threshold=0.10000000000000002, box_thickness=2, text_thickness=2, text_scale=1, with_confidence=True, with_class_agnostic_nms=False, with_segmentation=True, mask_combined=True, mask_extracted=True, mask_extracted_index=0, yolo_world_model=get_value_at_index(yoloworld_modelloader_zho_3, 0), esam_model=get_value_at_index(esam_modelloader_zho_4, 0), image=get_value_at_index(loadimage_1, 0), ) growmask = NODE_CLASS_MAPPINGS["GrowMask"]() growmask_8 = growmask.expand_mask( expand=30, tapered_corners=True, mask=get_value_at_index(yoloworld_esam_zho_2, 1), ) loadimage = NODE_CLASS_MAPPINGS["LoadImage"]() inpaint_inpaintwithmodel = NODE_CLASS_MAPPINGS["INPAINT_InpaintWithModel"]() inpaint_inpaintwithmodel_12 = inpaint_inpaintwithmodel.inpaint( seed=random.randint(1, 2**64), inpaint_model=get_value_at_index(inpaint_loadinpaintmodel_13, 0), image=get_value_at_index(loadimage_1, 0), mask=get_value_at_index(growmask_8, 0), ) vaeencode = NODE_CLASS_MAPPINGS["VAEEncode"]() vaeencode_18 = vaeencode.encode( pixels=get_value_at_index(inpaint_inpaintwithmodel_12, 0), vae=get_value_at_index(vaeloader_20, 0), ) masktoimage = NODE_CLASS_MAPPINGS["MaskToImage"]() vaedecode = NODE_CLASS_MAPPINGS["VAEDecode"]() image_comparer_rgthree = NODE_CLASS_MAPPINGS["Image Comparer (rgthree)"]() saveimage = NODE_CLASS_MAPPINGS["SaveImage"]() for q in range(1): masktoimage_9 = masktoimage.mask_to_image( mask=get_value_at_index(growmask_8, 0) ) vaedecode_19 = vaedecode.decode( samples=get_value_at_index(vaeencode_18, 0), vae=get_value_at_index(vaeloader_20, 0), ) image_comparer_rgthree_17 = image_comparer_rgthree.compare_images( image_a=get_value_at_index(vaedecode_19, 0), image_b=get_value_at_index(loadimage_1, 0), ) saveimage_24 = saveimage.save_images( filename_prefix="ComfyUI", images=get_value_at_index(inpaint_inpaintwithmodel_12, 0), ) if saveimage_24 and "ui" in saveimage_24 and "images" in saveimage_24["ui"]: output_dir = "output" os.makedirs(output_dir, exist_ok=True) saved_path = os.path.join(output_dir, saveimage_24['ui']['images'][0]['filename']) return saved_path else: raise ValueError("Image generation failed. Check model inputs.") return "Error: Image generation failed." # yoloworld_modelloader_zho = NODE_CLASS_MAPPINGS["Yoloworld_ModelLoader_Zho"]() if "Yoloworld_ModelLoader_Zho" in NODE_CLASS_MAPPINGS: yoloworld_modelloader_zho = NODE_CLASS_MAPPINGS["Yoloworld_ModelLoader_Zho"]() yoloworld_modelloader_zho_3 = yoloworld_modelloader_zho.load_yolo_world_model( yolo_world_model="yolo_world/m" ) else: raise KeyError("❌ Error: 'Yoloworld_ModelLoader_Zho' not found. Check if custom nodes are loaded.") esam_modelloader_zho = NODE_CLASS_MAPPINGS["ESAM_ModelLoader_Zho"]() esam_modelloader_zho_4 = esam_modelloader_zho.load_esam_model(device="CUDA") inpaint_loadinpaintmodel = NODE_CLASS_MAPPINGS["INPAINT_LoadInpaintModel"]() inpaint_loadinpaintmodel_13 = inpaint_loadinpaintmodel.load( model_name="MAT_Places512_G_fp16.safetensors" ) vaeloader = NODE_CLASS_MAPPINGS["VAELoader"]() vaeloader_20 = vaeloader.load_vae( vae_name="vae-ft-mse-840000-ema-pruned.safetensors" ) loadimage = NODE_CLASS_MAPPINGS["LoadImage"]() yoloworld_esam_zho = NODE_CLASS_MAPPINGS["Yoloworld_ESAM_Zho"]() growmask = NODE_CLASS_MAPPINGS["GrowMask"]() inpaint_inpaintwithmodel = NODE_CLASS_MAPPINGS["INPAINT_InpaintWithModel"]() vaeloader = NODE_CLASS_MAPPINGS["VAELoader"]() vaeencode = NODE_CLASS_MAPPINGS["VAEEncode"]() masktoimage = NODE_CLASS_MAPPINGS["MaskToImage"]() vaedecode = NODE_CLASS_MAPPINGS["VAEDecode"]() image_comparer_rgthree = NODE_CLASS_MAPPINGS["Image Comparer (rgthree)"]() saveimage = NODE_CLASS_MAPPINGS["SaveImage"]() #Add all the models that load a safetensors file model_loaders = [yoloworld_modelloader_zho_3,esam_modelloader_zho_4,inpaint_loadinpaintmodel_13,vaeloader_20] # Check which models are valid and how to best load them valid_models = [ getattr(loader[0], 'patcher', loader[0]) for loader in model_loaders if not isinstance(loader[0], dict) and not isinstance(getattr(loader[0], 'patcher', None), dict) ] #Finally loads the models device = "cuda" if torch.cuda.is_available() else "cpu" model_management.load_models_gpu(valid_models) if device == "cuda" else model_management.load_models_cpu(valid_models) with gr.Blocks() as app: gr.Markdown("# Object Remover") with gr.Column(): image = gr.Image(label="Image",type="filepath") object_name = gr.Textbox(label="Obj_name") generate = gr.Button("Generate") with gr.Column(): output = gr.Image(label="output") generate.click(fn=object_remover,inputs=[image,object_name],outputs=[output]) print("Launching app...") app.launch(share=True, debug=True)