Add easy promptAwait node (#818)

* Add submodule

* Set submodule branch to main

* Add PromptAwait node

* Fix loop has started for the second time, but the prompt word has not output new content

* Add input_1

* Change select widget to toolbar

* Modify some field names and displays

* Change select max-width

* Add output random seed in promptAwait
This commit is contained in:
yolain
2025-06-30 01:22:13 +08:00
committed by GitHub
parent 1616dd6602
commit e46f8a45d0
19 changed files with 177 additions and 161 deletions
-1
View File
@@ -9,7 +9,6 @@ workflow/**
autocomplete/**
web_beta/**
web_version/dev/**
ComfyUI-Easy-Use-Frontend/
docs/**
.vscode/
.idea/
+4
View File
@@ -0,0 +1,4 @@
[submodule "ComfyUI-Easy-Use-Frontend"]
path = ComfyUI-Easy-Use-Frontend
url = https://github.com/yolain/ComfyUI-Easy-Use-Frontend.git
branch = main
+1 -1
View File
@@ -1,4 +1,4 @@
__version__ = "1.3.1"
__version__ = "1.3.2"
import yaml
import json
+31 -122
View File
@@ -165,6 +165,35 @@
}
}
},
"easy promptAwait": {
"display_name": "提示词等待",
"inputs": {
"now": {
"name": "当前"
},
"prev": {
"name": "上一步"
},
"prompt": {
"name": "提示词",
"placeholder": "输入提示词或使用语音输入转文字"
}
},
"outputs": {
"0": {
"name": "输出"
},
"1": {
"name": "提示词"
},
"2": {
"name": "继续"
},
"3": {
"name": "随机种"
}
}
},
"easy promptConcat": {
"display_name": "提示词联结",
"inputs": {
@@ -6113,73 +6142,13 @@
"easy whileLoopStart": {
"display_name": "While循环-开始",
"inputs": {
"initial_value0": {
"name": "初始值0"
},
"initial_value1": {
"name": "初始值1"
},
"initial_value2": {
"name": "初始值2"
},
"initial_value3": {
"name": "初始值3"
},
"initial_value4": {
"name": "初始值4"
},
"initial_value5": {
"name": "初始值5"
},
"initial_value6": {
"name": "初始值6"
},
"initial_value7": {
"name": "初始值7"
},
"initial_value8": {
"name": "初始值8"
},
"initial_value9": {
"name": "初始值9"
},
"condition": {
"name": "条件"
"name": "开始循环"
}
},
"outputs": {
"0": {
"name": "开始"
},
"1": {
"name": "值0"
},
"2": {
"name": "值1"
},
"3": {
"name": "值2"
},
"4": {
"name": "值3"
},
"5": {
"name": "值4"
},
"6": {
"name": "值5"
},
"7": {
"name": "值6"
},
"8": {
"name": "值7"
},
"9": {
"name": "值8"
},
"10": {
"name": "值9"
}
}
},
@@ -6189,71 +6158,11 @@
"flow": {
"name": "结束"
},
"initial_value0": {
"name": "初始值0"
},
"initial_value1": {
"name": "初始值1"
},
"initial_value2": {
"name": "初始值2"
},
"initial_value3": {
"name": "初始值3"
},
"initial_value4": {
"name": "初始值4"
},
"initial_value5": {
"name": "初始值5"
},
"initial_value6": {
"name": "初始值6"
},
"initial_value7": {
"name": "初始值7"
},
"initial_value8": {
"name": "初始值8"
},
"initial_value9": {
"name": "初始值9"
},
"condition": {
"name": "条件"
"name": "继续循环"
}
},
"outputs": {
"0": {
"name": "值0"
},
"1": {
"name": "值1"
},
"2": {
"name": "值2"
},
"3": {
"name": "值3"
},
"4": {
"name": "值4"
},
"5": {
"name": "值5"
},
"6": {
"name": "值6"
},
"7": {
"name": "值7"
},
"8": {
"name": "值8"
},
"9": {
"name": "值9"
}
}
},
"easy forLoopStart": {
+55
View File
@@ -0,0 +1,55 @@
from server import PromptServer
from aiohttp import web
import time
import json
class MessageCancelled(Exception):
pass
class Message:
stash = {}
messages = {}
cancelled = False
@classmethod
def addMessage(cls, id, message):
if message == '__cancel__':
cls.messages = {}
cls.cancelled = True
elif message == '__start__':
cls.messages = {}
cls.stash = {}
cls.cancelled = False
else:
cls.messages[str(id)] = message
@classmethod
def waitForMessage(cls, id, period=0.1, asList=False):
sid = str(id)
while not (sid in cls.messages) and not ("-1" in cls.messages):
if cls.cancelled:
cls.cancelled = False
raise MessageCancelled()
time.sleep(period)
if cls.cancelled:
cls.cancelled = False
raise MessageCancelled()
message = cls.messages.pop(str(id), None) or cls.messages.pop("-1")
try:
if asList:
return [str(x.strip()) for x in message.split(",")]
else:
try:
return json.loads(message)
except ValueError:
return message
except ValueError:
print( f"ERROR IN MESSAGE - failed to parse '${message}' as ${'comma separated list of strings' if asList else 'string'}")
return [message] if asList else message
@PromptServer.instance.routes.post('/easyuse/message_callback')
async def message_callback(request):
post = await request.post()
Message.addMessage(post.get("id"), post.get("message"))
return web.json_response({})
+49 -2
View File
@@ -308,11 +308,56 @@ class promptLine:
return (rows, rows)
import comfy.utils
from server import PromptServer
from ..libs.messages import MessageCancelled, Message
any_type = AlwaysEqualProxy("*")
class promptAwait:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"now": (any_type,),
"prompt": ("STRING", {"multiline": True, "default": "", "placeholder":"Enter a prompt or use voice to enter to text"}),
"toolbar":("EASY_PROMPT_AWAIT_BAR",),
},
"optional":{
"prev": (any_type,),
},
"hidden": {"workflow_prompt": "PROMPT", "my_unique_id": "UNIQUE_ID", "extra_pnginfo": "EXTRA_PNGINFO"},
}
RETURN_TYPES = (any_type, "STRING", "BOOLEAN", "INT")
RETURN_NAMES = ("output", "prompt", "continue", "seed")
FUNCTION = "await_select"
CATEGORY = "EasyUse/Prompt"
def await_select(self, now, prompt, toolbar, prev=None, workflow_prompt=None, my_unique_id=None, extra_pnginfo=None, **kwargs):
id = my_unique_id
id = id.split('.')[len(id.split('.')) - 1] if "." in id else id
if ":" in id:
id = id.split(":")[0]
pbar = comfy.utils.ProgressBar(100)
pbar.update_absolute(30)
PromptServer.instance.send_sync('easyuse_prompt_await', {"id": id})
try:
res = Message.waitForMessage(id, asList=False)
if res is None or res == "-1":
result = (now, prompt, False, 0)
else:
input = now if res['select'] == 'now' or prev is None else prev
result = (input, res['prompt'], False if res['result'] == -1 else True, res['seed'] if res['unlock'] else res['last_seed'])
pbar.update_absolute(100)
return result
except MessageCancelled:
pbar.update_absolute(100)
raise comfy.model_management.InterruptProcessingException()
class promptConcat:
@classmethod
def INPUT_TYPES(cls):
return {"required": {
},
return {"required": {},
"optional": {
"prompt1": ("STRING", {"multiline": False, "default": "", "forceInput": True}),
"prompt2": ("STRING", {"multiline": False, "default": "", "forceInput": True}),
@@ -564,6 +609,7 @@ NODE_CLASS_MAPPINGS = {
"easy prompt": prompt,
"easy promptList": promptList,
"easy promptLine": promptLine,
"easy promptAwait": promptAwait,
"easy promptConcat": promptConcat,
"easy promptReplace": promptReplace,
"easy stylesSelector": stylesPromptSelector,
@@ -578,6 +624,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"easy prompt": "Prompt",
"easy promptList": "PromptList",
"easy promptLine": "PromptLine",
"easy promptAwait": "PromptAwait",
"easy promptConcat": "PromptConcat",
"easy promptReplace": "PromptReplace",
"easy stylesSelector": "Styles Selector",
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{v as e,x as t,i as n,o,n as i,h as l,B as r,Q as u,e as a,R as s}from"./vue-BPkYw06T.js";function v(n){return!!e()&&(t(n),!0)}const c="undefined"!=typeof window&&"undefined"!=typeof document;"undefined"!=typeof WorkerGlobalScope&&(globalThis,WorkerGlobalScope);const f=e=>null!=e,d=Object.prototype.toString,p=e=>"[object Object]"===d.call(e);function m(e){return Array.isArray(e)?e:[e]}function h(e,t=!0,n){l()?o(e,n):t?e():i(e)}const w=c?window:void 0;function b(e){var t;const n=u(e);return null!=(t=null==n?void 0:n.$el)?t:n}function y(...e){const t=[],o=()=>{t.forEach((e=>e())),t.length=0},i=r((()=>{const t=m(u(e[0])).filter((e=>null!=e));return t.every((e=>"string"!=typeof e))?t:void 0})),l=(s=([e,n,i,l])=>{if(o(),!(null==e?void 0:e.length)||!(null==n?void 0:n.length)||!(null==i?void 0:i.length))return;const r=p(l)?{...l}:l;t.push(...e.flatMap((e=>n.flatMap((t=>i.map((n=>((e,t,n,o)=>(e.addEventListener(t,n,o),()=>e.removeEventListener(t,n,o)))(e,t,n,r))))))))},c={flush:"post"},n((()=>{var t,n;return[null!=(n=null==(t=i.value)?void 0:t.map((e=>b(e))))?n:[w].filter((e=>null!=e)),m(u(i.value?e[1]:e[0])),m(a(i.value?e[2]:e[1])),u(i.value?e[3]:e[2])]}),s,{...c,immediate:!0}));var s,c;return v(o),()=>{l(),o()}}function g(e){const t=function(){const e=s(!1),t=l();return t&&o((()=>{e.value=!0}),t),e}();return r((()=>(t.value,Boolean(e()))))}function O(e,t={}){const{reset:o=!0,windowResize:i=!0,windowScroll:l=!0,immediate:a=!0,updateTiming:c="sync"}=t,d=s(0),p=s(0),O=s(0),x=s(0),z=s(0),A=s(0),R=s(0),S=s(0);function j(){const t=b(e);if(!t)return void(o&&(d.value=0,p.value=0,O.value=0,x.value=0,z.value=0,A.value=0,R.value=0,S.value=0));const n=t.getBoundingClientRect();d.value=n.height,p.value=n.bottom,O.value=n.left,x.value=n.right,z.value=n.top,A.value=n.width,R.value=n.x,S.value=n.y}function E(){"sync"===c?j():"next-frame"===c&&requestAnimationFrame((()=>j()))}return function(e,t,o={}){const{window:i=w,...l}=o;let a;const s=g((()=>i&&"ResizeObserver"in i)),c=()=>{a&&(a.disconnect(),a=void 0)},f=r((()=>{const t=u(e);return Array.isArray(t)?t.map((e=>b(e))):[b(t)]})),d=n(f,(e=>{if(c(),s.value&&i){a=new ResizeObserver(t);for(const t of e)t&&a.observe(t,l)}}),{immediate:!0,flush:"post"}),p=()=>{c(),d()};v(p)}(e,E),n((()=>b(e)),(e=>!e&&E())),function(e,t,o={}){const{window:i=w,...l}=o;let a;const s=g((()=>i&&"MutationObserver"in i)),c=()=>{a&&(a.disconnect(),a=void 0)},d=r((()=>{const t=m(u(e)).map(b).filter(f);return new Set(t)})),p=n((()=>d.value),(e=>{c(),s.value&&e.size&&(a=new MutationObserver(t),e.forEach((e=>a.observe(e,l))))}),{immediate:!0,flush:"post"}),h=()=>{p(),c()};v(h)}(e,E,{attributeFilter:["style","class"]}),l&&y("scroll",E,{capture:!0,passive:!0}),i&&y("resize",E,{passive:!0}),h((()=>{a&&E()})),{height:d,bottom:p,left:O,right:x,top:z,width:A,x:R,y:S,update:E}}export{y as a,O as u};
File diff suppressed because one or more lines are too long