From 46d38871b32e7fddce492fd27092b54460a2deed Mon Sep 17 00:00:00 2001 From: Totally Not HarroweD <46828061+NotHarroweD@users.noreply.github.com> Date: Sun, 24 Dec 2023 18:52:32 -0500 Subject: [PATCH] For Real Initial Commit add right things --- __init__.py | 22 ++++ __pycache__/__init__.cpython-310.pyc | Bin 0 -> 611 bytes __pycache__/harronode.cpython-310.pyc | Bin 0 -> 3898 bytes harronode.py | 123 ++++++++++++++++++ js/harronode.js | 176 ++++++++++++++++++++++++++ prompt_builder.py | 13 ++ words.json | 6 + 7 files changed, 340 insertions(+) create mode 100644 __init__.py create mode 100644 __pycache__/__init__.cpython-310.pyc create mode 100644 __pycache__/harronode.cpython-310.pyc create mode 100644 harronode.py create mode 100644 js/harronode.js create mode 100644 prompt_builder.py create mode 100644 words.json diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..947db62 --- /dev/null +++ b/__init__.py @@ -0,0 +1,22 @@ +""" +@author: HarroweD and quadmoon (https://github.com/traugdor) +@title: Harrlogos Prompt Builder Node +@nickname: Harronode +@description: This extension to ComfyUI will build a prompt for the Harrlogos LoRA for SDXL. +""" + + +from .harronode import Harronode + +NODE_CLASS_MAPPINGS = { + "Harronode": Harronode + +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "Harronode": "Harronode - Prompt Builder" +} + +WEB_DIRECTORY = "js" + +__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] diff --git a/__pycache__/__init__.cpython-310.pyc b/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f29b3eaa889e664d20574775f1141664eeb4c62 GIT binary patch literal 611 zcmZ8d&5qMB5KhwcFWO2--1g)nJ#5RlLa5oMf=b*&8-tSxwxiO00$znz z;6XS<;>3wNCoW*OyA@)j8EZbz%s2Bvujg6XzJL8pf7zDx!zBNjqm!|A`CJEL#TK!N z!|mLO9or%e>M%QQkOpz}>yl>NBrVe3IdO}0BCFrM|K^R8N@XBM=yf6l>}i0Kf}oF8 zLUMotJ4zf89}1y3f`rOcuu?H7Mrf5WiRdRq3#oIY08Jp@9^TB*o^g&gW*kaTd78cjfmBA1 zE1ziRu=J6Equ||q;QiEES$(_i9*;77!YFlrdCt+*f2-Ecds#mXZ-XhG%>5|BH~wNV z3tvU`Er873K`NB=^^{ek{pWf(=?A-ZWM!sVNG>sO>0TW*j-KJ?b2*EoQM0tI?#ue}6CkG;0XIko7?w;r1Uf&0ynyVBY|R13bJnR##K zy*Ka8Q&g>%H2lS1|I)K(H0@uKIsK=DxrQ&^24ET^f!30k2Bb?{lw@OiOILG7%ebL2 zof%IxW*pI0ffbnfRBM^cVm7da*&-`pwuD*RGxmymrRQbOIwsIW?r4qj3+$sc8$=kl z++?>cxzm5+^SqByPiqmTwWy~v!st`&h_no*V^;$^7Frg=zSz}fHZ&JS@l%)cD2$lb zCZ}{t2UPK`Tfc49$d;fQ{$J)9dBQ-dw02LA={?4lOJsXpn@ z)MnPA#?Gh3FSW1e746Z1lA0S!6(CjM&(gvhq%Mr5e)Gy+CZtUMr__9d)Y4e$53fjB zkh1vSQ|k>rve#lmviZ7)nfw4*Qq zC2a0J>igVd!o0I}d$V~%Xj=^`Ear9GevpV_7tjy<&=ZAEKD&8+YbU!x|Gt_N{}>Vf zxw`Z7*+1U+=iuqphQTXXCiJc!0=Q3v5hq?x=$p;07xE5r30}xc{el8CEMfL|)a@mr zns`qVCkh?E>+X1>tk?t3-`Pz>Sy|(>qdpE^Rwm_4C9^B%s=09)`@)bL%JZ}`cQ~!g z9ZoBEhtsl05)GTn0}0!4I)30e4i4sW=_n)Wd7&_rXN@3onb3EYF?Plg)VSjSBxxTe|vnlNL>suQ)Zr;AH zj&bT}GSpn1Pu_odDU{W=Mrnx{-!X_mDwNB)2{*}$Bb}_u_17Q<>nYw2IEwh%kf!9h zcC4YSefWS5^`XINYCP8XHIz1rVy5p?MH^UONC-+7BomZ(el5|T8)@NKja|`_!k)Qj zJ+~Q(HeMGqTgj|v#xY*Kj7w>%qb!!?V{iwLK~g+?NVK6zv_UN?F*`M7;XJ~_a1YM{ z!_4QVT$xb^Wbk4SaQ_y znJ6Fl3@NCBCJd=U6dt=l-y6L5vwPQXHy_sXG&)I)%k>RBg}fex^{n2M8f8)N6R#VK zk{|nFoVa1z6MCF*QOlM%+u5ZR6-79Cp)zBSKlZq&WHn@V5bx9_lJ`d}L}7l! zUexOc5YG?yA!g$`03|jt=oFa+uHpAKvYmcmep9oTi2Vh9$$yGP6W2^;;`o|<3}#>@ zT8b7!1~bjVO%C5dxG{ooBUe-MO1R1AM6N`*L8)-l=3wjpj!FGe-R&n)ZWFv#k2-m{ z>IZ%h)WayLn z1$YWR`Ia{^*v2>UC;f5_UpxyiYQVDg3r(PoI%V+dn3{0r0tRI5Q91iNym^eEvC7>k z+pBrFD220_zNjf0{Ub6I*^K<7%>2?|)>nEyV`oK?755GP6Udan8^C3m)4&yAGa;;s z%&pFAs$H2LTCA2@GC*j4=#iF6Ek*2EoY&YHsrk{5AUlQ8Qd&~F`{2)lF9S~lSCr1u zgwC1QbXK7gyXHE#A&Zu3SW9b4=WoH!fj;0loMxp9jHZ zAP4l_%L9FRwKJ$T>as1V2hmRSew{DM6|$jep{qi><*bZ|)e*7A@lS>(3Tl2pA#`4? z&w3cF&xln~Pz1jqXYIVHSs7ESV`@#9*(_g@ON*oaW#xoiJt5ar$AM&#DZ;-CAj}|Y zyFuJo$cl?04N_(*bMnS$MQ1A(*QP3Aw5*1_6PP<&7NNVAD_3$y8r+H literal 0 HcmV?d00001 diff --git a/harronode.py b/harronode.py new file mode 100644 index 0000000..59ca277 --- /dev/null +++ b/harronode.py @@ -0,0 +1,123 @@ +import json +from pathlib import Path +import torch +import server + +class Harronode: + + @classmethod + def INPUT_TYPES(cls): + words_path = Path(__file__).parent / "words.json" + with open(words_path, "r") as file: + data = json.load(file) + colors = data.get("colors", []) + styles = data.get("styles", []) + accents = data.get("accents", []) + content = data.get("content", []) + + inputs = { + "required": { + "prompt": ("STRING", {"default": "", "multiline": True}), + "text_on_image": ("STRING", {"default": "", "multiline": True}), + "text_weight": ("FLOAT", {"default": 1.0, "min":0.5, "max":1.5, "step": 0.01}), + "color_count": ("INT", {"default": 1, "min": 0, "max": 3, "step": 1}), + "style_count": ("INT", {"default": 1, "min": 1, "max": 2, "step": 1}), + "accent_count": ("INT", {"default": 1, "min": 0, "max": 3, "step": 1}), + "content_count": ("INT", {"default": 1, "min": 0, "max": 3, "step": 1}) + } + } + + for i in range (1, 4): + inputs["required"][f"color_{i}"] = (colors, {"default": colors[0] if colors else None}) + + for i in range (1, 3): + inputs["required"][f"style_{i}"] = (styles, {"default": styles[0] if styles else None}) + + for i in range (1, 4): + inputs["required"][f"accent_{i}"] = (accents, {"default": accents[0] if accents else None}) + + for i in range (1, 4): + inputs["required"][f"content_{i}"] = (content, {"default": content[0] if content else None}) + + return inputs + + RETURN_TYPES = ("STRING",) + FUNCTION = "fuck_me_up_fam" + CATEGORY = "Harronode/PromptBuilder" + + def fuck_me_up_fam(self, *args, **kwargs): + output = kwargs['prompt'] + return(output,) + + +def onprompt_populate_prompt(json_data): + try: + prompt = json_data['prompt'] + + updated_widget_values = {} + for k, v in prompt.items(): + if 'class_type' in v and (v['class_type'] == 'Harronode'): + inputs = v['inputs'] + if isinstance(inputs['prompt'], str): + inputs['prompt'] = prompt_builder.build_prompt(inputs) + + server.PromptServer.instance.send_sync("impact-node-feedback", {"node_id": k, "widget_name": "prompt", "type": "STRING", "value": inputs['prompt']}) + updated_widget_values[k] = inputs['prompt'] + except Exception as e: + print(f"[WARN] ComfyUI-Harronode: Error on prompt\n{e}") + +def harroonprompt(json_data): + try: + onprompt_populate_prompt(json_data) + except Exception as e: + print(f"[WARN] ComfyUI-Harronode: Error on prompt - autopopulation of prompt will not work.\n{e}") + + return json_data + +class prompt_builder: + def build_prompt(inputs): + text = "" + print(inputs) + text = text + "('" + text = text + inputs["text_on_image"] + text_weight = inputs["text_weight"] + text = text + f"':{text_weight:.2f}) text logo, " + color_count = inputs["color_count"] + if color_count > 0: + color1 = inputs["color_1"] + color2 = inputs["color_2"] + color3 = inputs["color_3"] + for i in range(1, color_count + 1): + variable_name = f"color{i}" + color_value = locals()[variable_name] + text = text + color_value + ", " + style_count = inputs["style_count"] + if style_count > 0: + style1 = inputs["style_1"] + style2 = inputs["style_2"] + for i in range(1, style_count + 1): + variable_name = f"style{i}" + style_value = locals()[variable_name] + text = text + style_value + ", " + accent_count = inputs["accent_count"] + if accent_count > 0: + accent1 = inputs["accent_1"] + accent2 = inputs["accent_2"] + accent3 = inputs["accent_3"] + for i in range(1, accent_count + 1): + variable_name = f"accent{i}" + accent_value = locals()[variable_name] + text = text + accent_value + ", " + content_count = inputs["content_count"] + if content_count > 0: + content1 = inputs["content_1"] + content2 = inputs["content_2"] + content3 = inputs["content_3"] + for i in range(1, content_count + 1): + variable_name = f"content{i}" + content_value = locals()[variable_name] + text = text + content_value + ", " + + return text + +server.PromptServer.instance.add_on_prompt_handler(harroonprompt) diff --git a/js/harronode.js b/js/harronode.js new file mode 100644 index 0000000..045eac2 --- /dev/null +++ b/js/harronode.js @@ -0,0 +1,176 @@ +import { app } from "../../scripts/app.js"; + +let origProps = {}; +let initialized = false; + +const harroWidgetHandlers = { + "Harronode": { + 'color_count': handleColorCount, + 'style_count': handleStyleCount, + 'accent_count': handleAccentCount, + 'content_count': handleContentCount + }, +}; + +function handleColorCount(node, widget) { + updateColorWidgets(node, widget.value); +} + +function handleStyleCount(node, widget) { + updateStyleWidgets(node, widget.value); +} + +function handleAccentCount(node, widget) { + updateAccentWidgets(node, widget.value); +} + +function handleContentCount(node, widget) { + updateContentWidgets(node, widget.value); +} + +//-------function credit to efficiency nodes for comfyUI---------// + +const findWidgetByName = (node, name) => { + return node.widgets ? node.widgets.find((w) => w.name === name) : null; +}; + +const doesInputWithNameExist = (node, name) => { + return node.inputs ? node.inputs.some((input) => input.name === name) : false; +}; + +const HIDDEN_TAG = "harrohide"; + +function toggleWidget(node, widget, show = false, suffix = "") { + if (!widget || doesInputWithNameExist(node, widget.name)) return; + + // Store the original properties of the widget if not already stored + if (!origProps[widget.name]) { + origProps[widget.name] = { origType: widget.type, origComputeSize: widget.computeSize }; + } + + const origSize = node.size; + + // Set the widget type and computeSize based on the show flag + widget.type = show ? origProps[widget.name].origType : HIDDEN_TAG + suffix; + widget.computeSize = show ? origProps[widget.name].origComputeSize : () => [0, -4]; + + // Recursively handle linked widgets if they exist + widget.linkedWidgets?.forEach(w => toggleWidget(node, w, ":" + widget.name, show)); + + // Calculate the new height for the node based on its computeSize method + const newHeight = node.computeSize()[1]; + node.setSize([node.size[0], newHeight]); +} +//--------------------------END CREDIT---------------------------// + +function updateColorWidgets(node, color_count){ + for (let i = 1; i <= 3; i++) { + //find widget + const color_picker = findWidgetByName(node, `color_${i}`) + if(i <= color_count){ + //set visible and required + toggleWidget(node, color_picker, true) + } + else { + //hide and set not required + toggleWidget(node, color_picker, false) + } + } +} + +function updateStyleWidgets(node, color_count){ + for (let i = 1; i <= 3; i++) { + //find widget + const style_picker = findWidgetByName(node, `style_${i}`) + if(i <= color_count){ + //set visible and required + toggleWidget(node, style_picker, true) + } + else { + //hide and set not required + toggleWidget(node, style_picker, false) + } + } +} +function updateAccentWidgets(node, color_count){ + for (let i = 1; i <= 3; i++) { + //find widget + const accent_picker = findWidgetByName(node, `accent_${i}`) + if(i <= color_count){ + //set visible and required + toggleWidget(node, accent_picker, true) + } + else { + //hide and set not required + toggleWidget(node, accent_picker, false) + } + } +} +function updateContentWidgets(node, color_count){ + for (let i = 1; i <= 3; i++) { + //find widget + const content_picker = findWidgetByName(node, `content_${i}`) + if(i <= color_count){ + //set visible and required + toggleWidget(node, content_picker, true) + } + else { + //hide and set not required + toggleWidget(node, content_picker, false) + } + } +} + +function startupLogic (node, widget) //change name +{ + // Retrieve the handler for the current node title and widget name + const handler = harroWidgetHandlers[node.comfyClass]?.[widget.name]; + if (handler) { + handler(node, widget); + } + prompt = findWidgetByName(node, 'prompt'); + +} + +app.registerExtension({ + name: "harronode.harronode", + nodeCreated(node) { + for (const w of node.widgets || []) { + let widgetValue = w.value; + + // Store the original descriptor if it exists + let originalDescriptor = Object.getOwnPropertyDescriptor(w, 'value'); + + startupLogic(node, w); + + Object.defineProperty(w, 'value', { + get() { + // If there's an original getter, use it. Otherwise, return widgetValue. + let valueToReturn = originalDescriptor && originalDescriptor.get + ? originalDescriptor.get.call(w) + : widgetValue; + + return valueToReturn; + }, + set(newVal) { + // If there's an original setter, use it. Otherwise, set widgetValue. + if (originalDescriptor && originalDescriptor.set) { + originalDescriptor.set.call(w, newVal); + } else { + widgetValue = newVal; + } + + startupLogic(node, w); + } + }); + } + setTimeout(() => { initialized = true; }, 500); + + if(node.comfyClass == "Harronode"){ + node.widgets[0].inputEl.placeholder = "Populated Prompt (Will be generated automatically)"; + node.widgets[1].inputEl.placeholder = "Input Text to Display on Image"; + const prompt = node.widgets.find((w) => w.name == 'prompt'); + prompt.inputEl.disabled = 1 == 1; + } + } +}); diff --git a/prompt_builder.py b/prompt_builder.py new file mode 100644 index 0000000..47d87cc --- /dev/null +++ b/prompt_builder.py @@ -0,0 +1,13 @@ +import re +import random +import os +import nodes +import folder_paths +import yaml +import threading + +def build_prompt(inputs): + print(inputs) + text = "WIP" + + return text \ No newline at end of file diff --git a/words.json b/words.json new file mode 100644 index 0000000..79af422 --- /dev/null +++ b/words.json @@ -0,0 +1,6 @@ +{ + "colors": ["blue", "teal", "gold", "rainbow", "red", "orange", "white", "cyan", "purple", "green", "yellow", "grey", "silver", "black"], + "styles": ["dripping", "colorful", "graffiti", "tattoo", "anime", "pixel art", "8-bit", "16-bit", "32-bit", "metal", "metallic", "spikey", "stone", "splattered", "comic book", "80s", "neon", "3D"], + "accents": ["smoke", "fire", "flames", "tentacles", "hell", "glow", "horns", "wings", "halo", "roots", "embossed", "blood", "digital", "ice", "frozen", "japanese", "chrome", "pastel", "robotic", "hearts", "cute", "egyptian", "viking"], + "content": ["cat", "sword", "owl", "cat ears", "cthulu", "sun", "roses", "clouds", "space", "stars", "skeletons", "demons", "fog", "trees", "moon", "skulls", "bones", "planet", "earth", "cherry blossom", "pentagram", "crosses", "lightning", "bolts", "crown", "circle", "moth"] +}