diff --git a/README.md b/README.md index 5d28eef..61d757d 100644 --- a/README.md +++ b/README.md @@ -1 +1,14 @@ -# DTAIComfyVariables \ No newline at end of file +# Variables for Comfy UI +This script provides variable nodes and shared global variables for the Comfy UI stable diffusion client. + +## Description +This Python script is an optional add-on to the Comfy UI stable diffusion client. It introduces quality of life improvements by providing variable nodes and shared global variables. + +## Getting Started +Import into the custom nodes directory of your Comfy UI client. + +## Dependencies +ComfyUI + +## License +This project is licensed under the MIT License. \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..905900b --- /dev/null +++ b/__init__.py @@ -0,0 +1,195 @@ +import requests + +from custom_nodes.DTGlobalVariables import variables + +class DTCLIPTextEncode: + @classmethod + def INPUT_TYPES(s): + return {"required": {"text": ("STRING", {"multiline": True}), "clip": ("CLIP", )}} + RETURN_TYPES = ("CONDITIONING",) + FUNCTION = "encode" + + CATEGORY = "DoubTech/Conditioning" + + def encode(self, clip, text): + print("DTCLIPTextEncode: " + text) + return ([[clip.encode(variables.apply(text)), {}]], ) + +class StringFormat: + @classmethod + def INPUT_TYPES(s): + return {"required": { + "string": ("STRING", {"multiline": False}), + "format": ("STRING", {"multiline": True}), + }} + + RETURN_TYPES = (["STRING"]) + FUNCTION = "encode" + + CATEGORY = "DoubTech/Variables" + + + @classmethod + def IS_CHANGED(s, clip, text): + return True + + def encode(self, string, format): + result = format.replace("$(string)", string) + return (result,) + +class StringFormatSingleLine: + @classmethod + def INPUT_TYPES(s): + return {"required": { + "string": ("STRING", {"multiline": False}), + "format": ("STRING", {"multiline": False, "default": "$(string)"}), + }} + + RETURN_TYPES = ("STRING") + FUNCTION = "encode" + + CATEGORY = "DoubTech/Variables" + + + @classmethod + def IS_CHANGED(s, clip, text): + return True + + def encode(self, string, format): + string = format.replace("$(string)", string) + return (string,) + +class IntVariable: + @classmethod + def INPUT_TYPES(s): + return {"required": { + "variable": ("STRING", {"multiline": False}), + "value": ("INT", ), + "clip": ("CLIP", )} + } + RETURN_TYPES = ("CLIP","INT") + FUNCTION = "encode" + + CATEGORY = "DoubTech/Variables" + + + @classmethod + def IS_CHANGED(s, variable, value): + return True + + def encode(self, clip, variable, value): + variables.state[variable] = value + return (clip,value,) + +class FloatVariable: + @classmethod + def INPUT_TYPES(s): + return {"required": { + "variable": ("STRING", {"multiline": False}), + "value": ("FLOAT", ), + "clip": ("CLIP", )} + } + RETURN_TYPES = ("CLIP","FLOAT") + FUNCTION = "encode" + + CATEGORY = "DoubTech/Variables" + + + @classmethod + def IS_CHANGED(s, variable, value): + return True + + def encode(self, clip, variable, value): + variables.state[variable] = value + return (clip,value,) + +class StringVariable: + @classmethod + def INPUT_TYPES(s): + return {"required": { + "variable": ("STRING", {"multiline": False}), + "value": ("STRING", {"multiline": True}), + "clip": ("CLIP", )} + } + RETURN_TYPES = ("CLIP","STRING") + FUNCTION = "encode" + + CATEGORY = "DoubTech/Variables" + + + @classmethod + def IS_CHANGED(s, variable, value): + return True + + def encode(self, clip, variable, value): + variables.state[variable] = value + return (clip,value,) + +class DTSingleLineStringVariable: + @classmethod + def INPUT_TYPES(s): + return {"required": { + "variable": ("STRING", {"multiline": False}), + "value": ("STRING", {"multiline": False}), + "clip": ("CLIP",)} + } + + RETURN_TYPES = ("CLIP","STRING") + FUNCTION = "encode" + + CATEGORY = "DoubTech/Variables" + + + @classmethod + def IS_CHANGED(s, variable, value): + return True + + def encode(self, clip, variable, value): + variables.state[variable] = value + return (clip, value) +class DTSingleLineStringVariableNoClip: + @classmethod + def INPUT_TYPES(s): + return {"required": { + "variable": ("STRING", {"multiline": False}), + "value": ("STRING", {"multiline": False})} + } + + + @classmethod + def IS_CHANGED(s, variable, value): + return True + + RETURN_TYPES = () + FUNCTION = "encode" + + CATEGORY = "DoubTech/Variables" + + def encode(self, clip, variable, value): + variables.state[variable] = value + return (clip,) + +# A dictionary that contains all nodes you want to export with their names +# NOTE: names should be globally unique +NODE_CLASS_MAPPINGS = { + "StringVariable": StringVariable, + "DTSingleLineStringVariable": DTSingleLineStringVariable, + "DTCLIPTextEncode": DTCLIPTextEncode, + "DTSingleLineStringVariableNoClip": DTSingleLineStringVariableNoClip, + "StringFormat": StringFormat, + "StringFormatSingleLine": StringFormatSingleLine, + "IntVariable": IntVariable, + "FloatVariable": FloatVariable, +} + +# A dictionary that contains the friendly/humanly readable titles for the nodes +NODE_DISPLAY_NAME_MAPPINGS = { + "StringVariable": "String", + "IntVariable": "Int", + "FloatVariable": "Float", + "DTSingleLineStringVariable": "Short String", + "DTCLIPTextEncode": "CLIP Text Encode (With Variables)", + + "StringFormat": "String Format", + "StringFormatSingleLine": "Short String Format", +} diff --git a/variables.py b/variables.py new file mode 100644 index 0000000..025f48d --- /dev/null +++ b/variables.py @@ -0,0 +1,36 @@ +state = dict() +generated_prompt = None + + +def apply(text, defaultStateField=None): + global state + + def replace_variable(match): + variable = match.group(0) # Get the full variable text, e.g., "$(name)" or "$(name:default_value)" + variable = variable[2:-1] # Remove the "$( ... )" surrounding parentheses + + parts = variable.split(":") + name = parts[0] + default_value = parts[1] if len(parts) > 1 else None + + if name in state: + return str(state[name]) # Replace with the value from the state dictionary + elif default_value is not None: + return default_value # Replace with the default value + + if variable == "undefined" or variable == None: + return "" + return variable # No replacement, return the original variable text + + import re + pattern = r"\$\(.*?\)" # Regular expression pattern to match the variable text + + try: + text = re.sub(pattern, replace_variable, text) + except Exception as e: + print(e) + + if (text == '' or text is None) and defaultStateField is not None and defaultStateField in state: + text = state[defaultStateField] + + return text