Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 57 additions & 40 deletions comfy_extras/nodes_perpneg.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import comfy.utils
import node_helpers
import math
from typing_extensions import override
from comfy_api.latest import ComfyExtension, io


def perp_neg(x, noise_pred_pos, noise_pred_neg, noise_pred_nocond, neg_scale, cond_scale):
pos = noise_pred_pos - noise_pred_nocond
Expand All @@ -16,20 +19,27 @@ def perp_neg(x, noise_pred_pos, noise_pred_neg, noise_pred_nocond, neg_scale, co
return cfg_result

#TODO: This node should be removed, it has been replaced with PerpNegGuider
class PerpNeg:
class PerpNeg(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="PerpNeg",
display_name="Perp-Neg (DEPRECATED by PerpNegGuider)",
category="_for_testing",
inputs=[
io.Model.Input("model"),
io.Conditioning.Input("empty_conditioning"),
io.Float.Input("neg_scale", default=1.0, min=0.0, max=100.0, step=0.01),
],
outputs=[
io.Model.Output(),
],
is_experimental=True,
is_deprecated=True,
)

@classmethod
def INPUT_TYPES(s):
return {"required": {"model": ("MODEL", ),
"empty_conditioning": ("CONDITIONING", ),
"neg_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}),
}}
RETURN_TYPES = ("MODEL",)
FUNCTION = "patch"

CATEGORY = "_for_testing"
DEPRECATED = True

def patch(self, model, empty_conditioning, neg_scale):
def execute(cls, model, empty_conditioning, neg_scale) -> io.NodeOutput:
m = model.clone()
nocond = comfy.sampler_helpers.convert_cond(empty_conditioning)

Expand All @@ -50,7 +60,7 @@ def cfg_function(args):

m.set_model_sampler_cfg_function(cfg_function)

return (m, )
return io.NodeOutput(m)


class Guider_PerpNeg(comfy.samplers.CFGGuider):
Expand Down Expand Up @@ -112,35 +122,42 @@ def predict_noise(self, x, timestep, model_options={}, seed=None):

return cfg_result

class PerpNegGuider:
class PerpNegGuider(io.ComfyNode):
@classmethod
def INPUT_TYPES(s):
return {"required":
{"model": ("MODEL",),
"positive": ("CONDITIONING", ),
"negative": ("CONDITIONING", ),
"empty_conditioning": ("CONDITIONING", ),
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step":0.1, "round": 0.01}),
"neg_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}),
}
}

RETURN_TYPES = ("GUIDER",)

FUNCTION = "get_guider"
CATEGORY = "_for_testing"

def get_guider(self, model, positive, negative, empty_conditioning, cfg, neg_scale):
def define_schema(cls):
return io.Schema(
node_id="PerpNegGuider",
category="_for_testing",
inputs=[
io.Model.Input("model"),
io.Conditioning.Input("positive"),
io.Conditioning.Input("negative"),
io.Conditioning.Input("empty_conditioning"),
io.Float.Input("cfg", default=8.0, min=0.0, max=100.0, step=0.1, round=0.01),
io.Float.Input("neg_scale", default=1.0, min=0.0, max=100.0, step=0.01),
],
outputs=[
io.Guider.Output(),
],
is_experimental=True,
)

@classmethod
def execute(cls, model, positive, negative, empty_conditioning, cfg, neg_scale) -> io.NodeOutput:
guider = Guider_PerpNeg(model)
guider.set_conds(positive, negative, empty_conditioning)
guider.set_cfg(cfg, neg_scale)
return (guider,)
return io.NodeOutput(guider)


class PerpNegExtension(ComfyExtension):
@override
async def get_node_list(self) -> list[type[io.ComfyNode]]:
return [
PerpNeg,
PerpNegGuider,
]

NODE_CLASS_MAPPINGS = {
"PerpNeg": PerpNeg,
"PerpNegGuider": PerpNegGuider,
}

NODE_DISPLAY_NAME_MAPPINGS = {
"PerpNeg": "Perp-Neg (DEPRECATED by PerpNegGuider)",
}
async def comfy_entrypoint() -> PerpNegExtension:
return PerpNegExtension()
Loading