Buffer

Installation

Copy the code into a .py file in your ComfyUI/custom_nodes directory, and then restart ComfyUI and refresh your ComfyUI tab.

Description

Nodes that buffer values but do not require inputs to be present. This allows you to split generation up in to many steps that can be run over multiple queuings. The basic idea is to have a group of nodes creating the input for a buffer on one queue, then you disable said nodes and use the output of the buffer on the next queue.

Example workflow

You can copy the bellow code into a .json file and load it with ComfyUI. In this workflow you start by enabling the "Low" group and generating a low-res image. After that your latent is buffered so you can disable the "Low" group and enable the "High" group and generate an upscaled image. This simple workflow allows you to generate low-res images until you're happy with the result and then move to doing high-res passes until you're happy there as well.

{"last_node_id":25,"last_link_id":40,"nodes":[{"id":6,"type":"CLIPTextEncode","pos":[0,180],"size":{"0":390,"1":130},"flags":{},"order":3,"mode":0,"inputs":[{"name":"clip","type":"CLIP","link":3}],"outputs":[{"name":"CONDITIONING","type":"CONDITIONING","links":[13],"slot_index":0}],"properties":{"Node name for S&R":"CLIPTextEncode"},"widgets_values":["beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"],"color":"#232","bgcolor":"#353"},{"id":7,"type":"CLIPTextEncode","pos":[0,360],"size":{"0":390,"1":140},"flags":{},"order":4,"mode":0,"inputs":[{"name":"clip","type":"CLIP","link":5}],"outputs":[{"name":"CONDITIONING","type":"CONDITIONING","links":[14],"slot_index":0}],"properties":{"Node name for S&R":"CLIPTextEncode"},"widgets_values":["text, watermark"],"color":"#322","bgcolor":"#533"},{"id":4,"type":"CheckpointLoaderSimple","pos":[0,30],"size":{"0":390,"1":100},"flags":{},"order":0,"mode":0,"outputs":[{"name":"MODEL","type":"MODEL","links":[12],"slot_index":0},{"name":"CLIP","type":"CLIP","links":[3,5],"slot_index":1},{"name":"VAE","type":"VAE","links":[19],"slot_index":2}],"properties":{"Node name for S&R":"CheckpointLoaderSimple"},"widgets_values":["v1-5-pruned-emaonly.safetensors"]},{"id":15,"type":"Reroute","pos":[320,-80],"size":[75,26],"flags":{},"order":5,"mode":0,"inputs":[{"name":"","type":"*","link":19}],"outputs":[{"name":"","type":"VAE","links":[20,21],"slot_index":0}],"properties":{"showOutputText":false,"horizontal":false}},{"id":12,"type":"Reroute","pos":[320,-170],"size":[75,26],"flags":{},"order":2,"mode":0,"inputs":[{"name":"","type":"*","link":12}],"outputs":[{"name":"","type":"MODEL","links":[15,22],"slot_index":0}],"properties":{"showOutputText":false,"horizontal":false}},{"id":13,"type":"Reroute","pos":[320,-140],"size":[75,26],"flags":{},"order":7,"mode":0,"inputs":[{"name":"","type":"*","link":13}],"outputs":[{"name":"","type":"CONDITIONING","links":[16,23],"slot_index":0}],"properties":{"showOutputText":false,"horizontal":false}},{"id":14,"type":"Reroute","pos":[320,-110],"size":[75,26],"flags":{},"order":8,"mode":0,"inputs":[{"name":"","type":"*","link":14}],"outputs":[{"name":"","type":"CONDITIONING","links":[17,24],"slot_index":0}],"properties":{"showOutputText":false,"horizontal":false}},{"id":17,"type":"Reroute","pos":[1020,-170],"size":[75,26],"flags":{},"order":6,"mode":0,"inputs":[{"name":"","type":"*","link":22}],"outputs":[{"name":"","type":"MODEL","links":[27],"slot_index":0}],"properties":{"showOutputText":false,"horizontal":false}},{"id":18,"type":"Reroute","pos":[1020,-140],"size":[75,26],"flags":{},"order":10,"mode":0,"inputs":[{"name":"","type":"*","link":23}],"outputs":[{"name":"","type":"CONDITIONING","links":[28],"slot_index":0}],"properties":{"showOutputText":false,"horizontal":false}},{"id":19,"type":"Reroute","pos":[1020,-110],"size":[75,26],"flags":{},"order":12,"mode":0,"inputs":[{"name":"","type":"*","link":24}],"outputs":[{"name":"","type":"CONDITIONING","links":[29],"slot_index":0}],"properties":{"showOutputText":false,"horizontal":false}},{"id":5,"type":"EmptyLatentImage","pos":[810,30],"size":{"0":280,"1":110},"flags":{},"order":1,"mode":2,"outputs":[{"name":"LATENT","type":"LATENT","links":[2],"slot_index":0}],"properties":{"Node name for S&R":"EmptyLatentImage"},"widgets_values":[512,512,1]},{"id":8,"type":"VAEDecode","pos":[810,190],"size":{"0":280,"1":50},"flags":{},"order":13,"mode":2,"inputs":[{"name":"samples","type":"LATENT","link":7},{"name":"vae","type":"VAE","link":20}],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[10],"slot_index":0}],"properties":{"Node name for S&R":"VAEDecode"}},{"id":10,"type":"PreviewImage","pos":[810,290],"size":{"0":280,"1":270},"flags":{},"order":15,"mode":2,"inputs":[{"name":"images","type":"IMAGE","link":10}],"properties":{"Node name for S&R":"PreviewImage"}},{"id":23,"type":"PreviewImage","pos":[1510,260],"size":{"0":280,"1":300},"flags":{},"order":19,"mode":0,"inputs":[{"name":"images","type":"IMAGE","link":31}],"properties":{"Node name for S&R":"PreviewImage"}},{"id":20,"type":"KSampler","pos":[1210,30],"size":{"0":280,"1":530},"flags":{},"order":17,"mode":0,"inputs":[{"name":"model","type":"MODEL","link":27},{"name":"positive","type":"CONDITIONING","link":28},{"name":"negative","type":"CONDITIONING","link":29},{"name":"latent_image","type":"LATENT","link":40}],"outputs":[{"name":"LATENT","type":"LATENT","links":[30],"slot_index":0}],"properties":{"Node name for S&R":"KSampler"},"widgets_values":[394699392943726,"randomize",20,8,"euler","normal",0.5]},{"id":22,"type":"VAEDecode","pos":[1510,160],"size":{"0":280,"1":50},"flags":{},"order":18,"mode":0,"inputs":[{"name":"samples","type":"LATENT","link":30},{"name":"vae","type":"VAE","link":32}],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[31],"slot_index":0}],"properties":{"Node name for S&R":"VAEDecode"}},{"id":16,"type":"Reroute","pos":[1020,-80],"size":[75,26],"flags":{},"order":9,"mode":0,"inputs":[{"name":"","type":"*","link":21}],"outputs":[{"name":"","type":"VAE","links":[32],"slot_index":0}],"properties":{"showOutputText":false,"horizontal":false}},{"id":3,"type":"KSampler","pos":[510,30],"size":{"0":280,"1":530},"flags":{},"order":11,"mode":2,"inputs":[{"name":"model","type":"MODEL","link":15},{"name":"positive","type":"CONDITIONING","link":16},{"name":"negative","type":"CONDITIONING","link":17},{"name":"latent_image","type":"LATENT","link":2}],"outputs":[{"name":"LATENT","type":"LATENT","links":[7,37],"slot_index":0}],"properties":{"Node name for S&R":"KSampler"},"widgets_values":[1122941232445133,"randomize",20,8,"euler","normal",1]},{"id":25,"type":"LatentBuffer","pos":[950,-210],"size":[140,30],"flags":{},"order":14,"mode":0,"inputs":[{"name":"latent","type":"LATENT","link":37}],"outputs":[{"name":"LATENT","type":"LATENT","links":[39],"shape":3,"slot_index":0}],"properties":{"Node name for S&R":"LatentBuffer"}},{"id":21,"type":"LatentUpscaleBy","pos":[1510,30],"size":{"0":280,"1":82},"flags":{},"order":16,"mode":0,"inputs":[{"name":"samples","type":"LATENT","link":39}],"outputs":[{"name":"LATENT","type":"LATENT","links":[40],"shape":3,"slot_index":0}],"properties":{"Node name for S&R":"LatentUpscaleBy"},"widgets_values":["nearest-exact",2]}],"links":[[2,5,0,3,3,"LATENT"],[3,4,1,6,0,"CLIP"],[5,4,1,7,0,"CLIP"],[7,3,0,8,0,"LATENT"],[10,8,0,10,0,"IMAGE"],[12,4,0,12,0,"*"],[13,6,0,13,0,"*"],[14,7,0,14,0,"*"],[15,12,0,3,0,"MODEL"],[16,13,0,3,1,"CONDITIONING"],[17,14,0,3,2,"CONDITIONING"],[19,4,2,15,0,"*"],[20,15,0,8,1,"VAE"],[21,15,0,16,0,"*"],[22,12,0,17,0,"*"],[23,13,0,18,0,"*"],[24,14,0,19,0,"*"],[27,17,0,20,0,"MODEL"],[28,18,0,20,1,"CONDITIONING"],[29,19,0,20,2,"CONDITIONING"],[30,20,0,22,0,"LATENT"],[31,22,0,23,0,"IMAGE"],[32,16,0,22,1,"VAE"],[37,3,0,25,0,"LATENT"],[39,25,0,21,0,"LATENT"],[40,21,0,20,3,"LATENT"]],"groups":[{"title":"Low","bounding":[500,-44,600,614],"color":"#3f789e","font_size":24,"locked":false},{"title":"Model/Cond","bounding":[-10,-44,410,554],"color":"#3f789e","font_size":24,"locked":false},{"title":"High","bounding":[1200,-44,600,614],"color":"#3f789e","font_size":24,"locked":false}],"config":{},"extra":{"0246.VERSION":[0,0,4]},"version":0.4}

Changelog

  • 2024-01-12 - Switched to using the create_buffer function to programmatically generate the buffer classes. Added support for CONDITIONING, and STRING types. More types can easily be added by adding the type string to buffer_types.

Code

def create_buffer(value_type):
    vt_lower = value_type.lower()

    def input_types():
        return {"required": {}, "optional": {vt_lower: (value_type, )}}

    def init(self):
        self.value = None

    def buffer(self, *args, **kwargs):
        if vt_lower in kwargs:
            self.value = kwargs[vt_lower]
        return (self.value, )

    members = {
        "INPUT_TYPES": staticmethod(input_types),
        "RETURN_TYPES": (value_type, ),
        "FUNCTION": "buffer",
        "OUTPUT_NODE": True,
        "CATEGORY": "utils/buffers",
        "__init__": init,
        "buffer": buffer,
    }

    name = value_type.capitalize() + "Buffer"
    return (name, type(name, tuple(), members))

buffer_types = ["LATENT", "IMAGE", "CONDITIONING", "STRING"]
mappings = [create_buffer(value_type) for value_type in buffer_types]

NODE_CLASS_MAPPINGS = {name: type_ for name, type_ in mappings}
Edit
Pub: 23 Oct 2023 12:16 UTC
Edit: 12 Jan 2024 00:37 UTC
Views: 695