Files
YMC-GitHub-ymc-node-suite-c…/modules/text/node_prompt.py
T

615 lines
18 KiB
Python

import re
import random
from yors_pano_list_util import ListDelExclude,ListFillOne,ListToTupe,ListShuffle
# use current_category and current_function from con.py in current directory
# from .conf import CURRENT_CATEGORY,CURRENT_FUNCTION
# docs(core): use current_category and current_function in this file
CURRENT_CATEGORY="ymc suite/text"
CURRENT_FUNCTION="exec"
def tags_listify(s:str):
ls = s.split(",")
ls = list(filter(None, ls))
return ls
def tags_strify(l:list[str]):
return ','.join(l)
def tag_trim(s:str):
trimedtag=s
trimedtag=re.sub(r'^ *', '', trimedtag,0)
trimedtag=re.sub(r' *$', '', trimedtag,0)
return trimedtag
def tag_ms2os(s:str):
return re.sub(re.compile(r' {1,}'), ' ', s,0)
def tag_unweight(s:str):
# unweight,trim,
unwdtag=s.replace("(","").replace(")","")
unwdtag=re.sub(r':\d.*', '', unwdtag,0)
unwdtag=tag_trim(unwdtag)
unwdtag=tag_ms2os(unwdtag)
return unwdtag
def tags_unweight(s:str):
ls=tags_listify(s)
nls=[]
for tag in ls:
stdedtag=tag_unweight(tag)
if stdedtag !="":
nls.append(stdedtag)
return ",".join(nls)
def tags_onelineify(s:str):
return re.sub(r'\n', ',', s,0)
def tag_std(s:str):
# trim,ms2os
stdedtag=s
stdedtag=tag_trim(stdedtag)
stdedtag=tag_ms2os(stdedtag)
return stdedtag
def tags_dup(s:str):
nls=tags_listify(s)
nls=list(dict.fromkeys(nls))
return ",".join(nls)
def tags_std(s:str):
ls=tags_listify(s)
nls=[]
for tag in ls:
stdedtag=tag_std(tag)
if stdedtag !="":
nls.append(stdedtag)
return ",".join(nls)
def tags_ignore(s:str,i:str):
ls=tags_listify(s)
li=tags_listify(i)
nls=[]
for tag in ls:
stdedtag=tag_unweight(tag)
if stdedtag !="" and not(stdedtag in li):
nls.append(tag)
return ",".join(nls)
def tags_replace(s:str,i:str,r:str):
ls=tags_listify(s)
li=tags_listify(i)
# lr=tags_listify(r)
nls=[]
for tag in ls:
stdedtag=tag_unweight(tag)
if stdedtag !="":
if stdedtag in li:
# replace found with r
nls.append(r)
else:
nls.append(tag)
return ",".join(nls)
def tags_search(s:str,i:str):
ls=tags_listify(s)
li=tags_listify(i)
nls=[]
for tag in ls:
stdedtag=tag_unweight(tag)
if stdedtag !="" :
for pattern in li:
if pattern in stdedtag:
nls.append(tag)
return ",".join(nls)
def tags_head(s:str,i:str):
"""
move some tags to head
"""
head=tags_listify(i)
tails=tags_listify(tags_ignore(s,i))
return ",".join(head+tails)
def tags_tail(s:str,i:str):
"""
move some tags to head
"""
tails=tags_listify(i)
head=tags_listify(tags_ignore(s,i))
return ",".join(head+tails)
# feat(core): NodePromptAdd - prompt add some text
class NodePromptAdd:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING",{"forceInput":False}),
"toadd": ("STRING",{"forceInput":False}),
"action": (["add2head",'add2tail','del|add2head','del|add2tail','none'],),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ('STRING',)
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - add"
OUTPUT_NODE = True
def exec(self, text='',toadd='',action='add2head'):
# if action =="add2head":
# return list_2_tupe([tags_head(text,prev)])
# if action =="add2tail":
# return list_2_tupe([tags_tail(text,prev)])
if 'none' in action:
return ListToTupe([text])
prev=toadd
if 'del' in action:
prev=tags_ignore(text,toadd)
if 'add2head' in action:
prev=tags_head(text,prev)
if 'add2tail' in action:
prev=tags_tail(text,prev)
return ListToTupe([prev])
# feat(core): NodePromptAdvAdd - prompt add some text (adv)
class NodePromptAdvSearch:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING",{"forceInput":False}),
"search": ("STRING",{"forceInput":False}),
"action": (['none',"del", "move2head",'move2tail',"replace","search"],),
"replace": ("STRING",{"forceInput":False}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ('STRING',)
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - search (adv)"
OUTPUT_NODE = True
def exec(self, text='',search='',action='none',replace=''):
if action == "none":
return ListToTupe([text])
if action == "search":
return ListToTupe([tags_search(text,search)])
searchedtags=tags_search(text,search)
if action =="replace":
return ListToTupe([tags_replace(text,searchedtags,replace)])
if action =="del":
return ListToTupe([tags_ignore(text,searchedtags)])
if action =="move2head":
return ListToTupe([tags_head(text,searchedtags)])
if action =="move2tail":
return ListToTupe([tags_tail(text,searchedtags)])
# feat(core): NodePromptSearch - prompt search some text
class NodePromptSearch:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING",{"forceInput":False}),
"search": ("STRING",{"forceInput":False}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ('STRING',)
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - search"
OUTPUT_NODE = True
def exec(self, text='',search=''):
return ListToTupe([tags_search(text,search)])
# feat(core): NodePromptDup - prompt dup some text
class NodePromptDup:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING",{"forceInput":False}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ('STRING',)
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - dup"
OUTPUT_NODE = True
def exec(self, text):
return ListToTupe([tags_dup(text)])
# feat(core): NodePromptAdvDup - prompt dup some text (adv)
class NodePromptAdvDup:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING",{"forceInput":False}),
# "mode": (["alline", "in-each-line"],),
}
}
RETURN_TYPES = ("STRING","STRING",)
RETURN_NAMES = ('STRING',"STRING",)
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - dup (adv)"
OUTPUT_NODE = True
def exec(self, text):
a=''
res=[]
textl=text.split("\n")
for line in textl:
res.append(tags_dup(line))
a='\n'.join(res)
tags_dup(tags_onelineify(text))
return ListToTupe([tags_dup(tags_onelineify(a)),a])
# feat(core): NodePromptShuffle - prompt shuffle some text
class NodePromptShuffle:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING",{"forceInput":False}),
"keep_n_token": ("STRING", {"default": "0", "multiline": False}),
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ('STRING',)
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - shuffle"
OUTPUT_NODE = True
def exec(self, text='',keep_n_token='0',seed=0):
random.seed(seed)
textl=tags_listify(tags_onelineify(text))
el=ListShuffle(textl,int(keep_n_token))
return ListToTupe([','.join(el)])
# feat(core): NodePromptDel - prompt del some text
class NodePromptDel:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"search": ("STRING",{"forceInput":False}),
"todel": ("STRING",{"forceInput":False}),
"action": (["yes",'no'],),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ('STRING',)
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - del"
OUTPUT_NODE = True
def exec(self, search='',todel='',action='yes'):
# https://www.geeksforgeeks.org/python-remove-empty-strings-from-list-of-strings/
if 'no' in action:
return ListToTupe([search])
ca=tags_ignore(search,tags_unweight(todel))
return ListToTupe([ca])
# feat(core): NodePromptStd - prompt std
class NodePromptStd:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING",{"forceInput":False}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ('STRING',)
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - std"
OUTPUT_NODE = True
def exec(self, text):
return ListToTupe([tags_std(text)])
# feat(core): NodePromptInput - prompt input
class NodePromptInput:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING",{"default": "","multiline":True}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ('text',)
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - input"
OUTPUT_NODE = True
def exec(self, text=''):
return ListToTupe([tags_std(text)])
# feat(core): NodePromptUnweight - prompt unweight
class NodePromptUnweight:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING",{"forceInput":False}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ('STRING',)
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - unweight"
OUTPUT_NODE = True
def exec(self, text):
return ListToTupe([tags_unweight(text)])
# feat(core): NodePromptJoin - prompt join
class NodePromptJoin:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"a": ("STRING",{"forceInput":False}),
"b": ("STRING",{"forceInput":False}),
"c": ("STRING",{"forceInput":False}),
"d": ("STRING",{"forceInput":False}),
"e": ("STRING",{"forceInput":False}),
"f": ("STRING",{"forceInput":False}),
"g": ("STRING",{"forceInput":False}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ('STRING',)
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - join"
OUTPUT_NODE = True
def exec(self, a,b,c,d,e,f,g):
vl=[a,b,c,d,e,f,g]
vs = (",").join(vl)
vs=tags_std(vs)
# vs = vs.replace(" ", " ").replace(" ,", ",").replace(", ", ",").replace(",,", ",").replace(",,", ",")
return {"ui": {"text": (vs,)}, "result": (vs,)}
class AnyType(str):
"""A special class that is always equal in not equal comparisons. Credit to pythongosssss"""
def __ne__(self, __value: object) -> bool:
return False
any_type = AnyType("*")
default_prompt1='''Swing
Slide
Climbing frame
Sandbox
See-saw
Merry-go-round
Jungle gym
Trampoline
Monkey bars
Rocking horse
Playhouse
Hopscotch
Balance beam
Spring rider
Water play area
Ball pit
Tunnel
Zip line
Basketball hoop
Bicycle rack
Spinner
Climbing wall
Rope ladder
Tetherball
Flying fox
Swinging bridge
Spiral slide
Water sprinkler
Pedal go-kart
Miniature golf course
'''
default_prompt1="\n".join([p.strip() for p in default_prompt1.split('\n') if p.strip()!=''])
# refer comfyui-mixlab-nodes
# feat(core): NodePromptRandom - prompt random
class NodePromptRandom:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"max_count": ("INT", {"default": 9, "min": 1, "max": 1000}),
# "image_field": ("IMAGE",),
"mutable_prompt": ("STRING",
{
"multiline": True,
"default": default_prompt1
}),
"immutable_prompt": ("STRING",
{
"multiline": True,
"default": 'sticker, Cartoon, ``'
}),
"random_sample": (["enable", "disable"],),
# "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff, "step": 1}),
},
"optional":{
"seed": (any_type, {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
}
}
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - random"
RETURN_TYPES = ("STRING",)
# CATEGORY = "♾️Mixlab/Prompt"
OUTPUT_IS_LIST = (True,)
OUTPUT_NODE = True
def exec(self,max_count,mutable_prompt,immutable_prompt,random_sample,seed=0):
# Split the text into an array of words
words1 = mutable_prompt.split("\n")
# Split the text into an array of words
words2 = immutable_prompt.split("\n")
# progress bar
# pbar = comfy.utils.ProgressBar(len(words1)*len(words2))
# Select a random word from the array
# random_word = random.choice(words)
prompts=[]
for w1 in words1:
w1=w1.strip()
for w2 in words2:
w2=w2.strip()
if '``' not in w2:
if w2=="":
w2='``'
else:
w2=w2+',``'
if w1!='' and w2!='':
prompts.append(w2.replace('``', w1))
# pbar.update(1)
if len(prompts)==0:
prompts.append(immutable_prompt)
if random_sample=='enable':
# random - get x-count element in array
prompts = random.sample(prompts, min(max_count,len(prompts)))
else:
prompts = prompts[:min(max_count,len(prompts))]
prompts= [elem.strip() for elem in prompts if elem.strip()]
# return (new_prompt)
return {"ui": {"prompts": prompts}, "result": (prompts,)}
def addWeight(text, weight=1):
if weight == 1:
return text
else:
return f"({text}:{round(weight,3)})"
# feat(core): NodePromptWeight - prompt add weight
class NodePromptWeight:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"prompt_keyword": ("STRING",
{
"multiline": False,
"default": '',
"dynamicPrompts": False
}),
"weight":("FLOAT", {"default": 1, "min": -3,"max": 3,"step": 0.01,"display": "slider"}),
# "min_value":("FLOAT", {
# "default": -2,
# "min": -10,
# "max": 0xffffffffffffffff,
# "step": 0.01,
# "display": "number"
# }),
# "max_value":("FLOAT", {
# "default": 2,
# "min": -10,
# "max": 0xffffffffffffffff,
# "step": 0.01,
# "display": "number"
# }),
}
}
FUNCTION = CURRENT_FUNCTION
CATEGORY = CURRENT_CATEGORY
NODE_DESC = "prompt - add weight"
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("prompt",)
# FUNCTION = "run"
# CATEGORY = "♾️Mixlab/Prompt"
INPUT_IS_LIST = False
OUTPUT_IS_LIST = (False,)
OUTPUT_NODE = False
def exec(self,prompt_keyword,weight):
# if weight < min_value:
# weight= min_value
# elif weight > max_value:
# weight= max_value
p=addWeight(prompt_keyword,weight)
return (p,)