Add string node
This commit is contained in:
@@ -20,7 +20,7 @@ You can also get the node from comfy manager under the name of More math.
|
||||
|
||||
- functions and variables in math expressions
|
||||
- Conversion between INT and FLOAT; INT and BOOLEAN; AUDIO and IMAGE (red - real - strenght of cosine of frequency; blue - imaginary - strenght of sine of frequency; green - log1p of amplitude - just so it looks good to humans)
|
||||
- Nodes for FLOAT, CONDITIONING, LATENT, IMAGE, MASK, NOISE, AUDIO, VIDEO, MODEL, CLIP, VAE, SIGMAS and GUIDER
|
||||
- Nodes for FLOAT, STRING, CONDITIONING, LATENT, IMAGE, MASK, NOISE, AUDIO, VIDEO, MODEL, CLIP, VAE, SIGMAS and GUIDER
|
||||
- Vector Math: Support for List literals `[v1, v2, ...]` and operations between lists/scalars/tensors
|
||||
- Custom functions `funcname(variable,variable,...)->expression;` they can be used in any later defined custom function or in expression. Shadowing inbuilt functions do not work. **Be careful with recursion. There is no stack limit. Got to 700 000 iterations before I got bored.**
|
||||
- Custom variables `varname=expression;` They can be used in any later assigment or final expression.
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
from .helper_functions import (
|
||||
generate_dim_variables,
|
||||
parse_expr,
|
||||
getIndexTensorAlongDim,
|
||||
as_tensor,
|
||||
normalize_to_common_shape,
|
||||
make_zero_like,
|
||||
get_v_variable,
|
||||
get_f_variable,
|
||||
checkLazyNew
|
||||
)
|
||||
from .Parser.UnifiedMathVisitor import UnifiedMathVisitor
|
||||
from comfy_api.latest import io
|
||||
import torch
|
||||
from .Stack import MrmthStack
|
||||
import copy
|
||||
from .ParseTree import MrmthParseTree
|
||||
|
||||
class StringMathNode(io.ComfyNode):
|
||||
"""
|
||||
Enables math expressions on Audio.
|
||||
|
||||
Inputs:
|
||||
I: Autogrow image inputs (I0, I1, ...)
|
||||
F: Autogrow float inputs (F0, F1, ...)
|
||||
Image: Expression
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def define_schema(cls) -> io.Schema:
|
||||
return io.Schema(
|
||||
node_id="mrmth_ag_AudioMathNode",
|
||||
category="More math",
|
||||
display_name="Audio math",
|
||||
inputs=[
|
||||
io.Autogrow.Input(id="V",template=io.Autogrow.TemplatePrefix(io.String.Input("values", optional=True), prefix="V", min=1, max=50)),
|
||||
io.Autogrow.Input(id="F", template=io.Autogrow.TemplatePrefix(io.Float.Input("float", default=0.0, optional=True, lazy=True, force_input=True), prefix="F", min=1, max=50)),
|
||||
io.MultiType.Input(
|
||||
io.String.Input("Expression", default="", multiline=False),
|
||||
types=[io.String,MrmthParseTree],
|
||||
tooltip="3D model file or path string",
|
||||
),
|
||||
io.Int.Input(id="batching", default=0),
|
||||
io.Bool.Input(
|
||||
id="remember_stack",
|
||||
default=False,
|
||||
display_name="Remember stack across batch",
|
||||
tooltip=(
|
||||
"If enabled, stack is copied at output leading to changes being remembered during batch operations (node runs multiple times in sucession). If disabled each batch gets it's own copy of the stack."
|
||||
),
|
||||
),
|
||||
MrmthStack.Input(id="stack", tooltip="Access stack between nodes",optional=True)
|
||||
],
|
||||
outputs=[
|
||||
io.Audio.Output(is_output_list=True),
|
||||
MrmthStack.Output(),
|
||||
],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def check_lazy_status(cls, Expression, V, F,batching=0, remember_stack=False,stack={}):
|
||||
return checkLazyNew(Expression,V,F)
|
||||
|
||||
|
||||
@classmethod
|
||||
def execute(cls, V, F, Expression, batching=0, remember_stack=False, stack={}):
|
||||
|
||||
variables = {
|
||||
"a": V.get(0,""), "b": V.get(1,""), "c": V.get(2,""), "d": V.get(3,""),
|
||||
"w": F.get("F0", 0.0) if F.get("F0") is not None else 0.0,
|
||||
"x": F.get("F1", 0.0) if F.get("F1") is not None else 0.0,
|
||||
"y": F.get("F2", 0.0) if F.get("F2") is not None else 0.0,
|
||||
"z": F.get("F3", 0.0) if F.get("F3") is not None else 0.0
|
||||
}
|
||||
|
||||
v_stacked, v_cnt = get_v_variable(V, length_mismatch="do nothing")
|
||||
if v_stacked is not None:
|
||||
variables["V"] = v_stacked
|
||||
variables["Vcnt"] = float(v_cnt)
|
||||
variables["V_count"] = float(v_cnt)
|
||||
|
||||
f_stacked, f_cnt = get_f_variable(F)
|
||||
if f_stacked is not None:
|
||||
variables["F"] = f_stacked
|
||||
variables["Fcnt"] = float(f_cnt)
|
||||
variables["F_count"] = float(f_cnt)
|
||||
|
||||
for k, val in F.items():
|
||||
variables[k] = val if val is not None else 0.0
|
||||
|
||||
tree = None
|
||||
if isinstance(Expression,str):
|
||||
tree = parse_expr(Expression)
|
||||
else:
|
||||
tree = Expression
|
||||
visitor = UnifiedMathVisitor(variables, len(V[0]),torch.device("cpu"),state_storage=stack)
|
||||
result = visitor.visit(tree)
|
||||
result = str(result)
|
||||
|
||||
if batching and batching > 0:
|
||||
def chunks(s, n):
|
||||
"""Produce `n`-character chunks from `s`."""
|
||||
for start in range(0, len(s), n):
|
||||
yield s[start:start+n]
|
||||
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
return (chunks(result,batching), stack)
|
||||
else:
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
|
||||
return (result, stack)
|
||||
Reference in New Issue
Block a user