Skip to content

[enhancement]: Concat ControlNet(s) for easier multiple control nets into a denoise latent #4526

Open
@c-dante

Description

@c-dante

Is there an existing issue for this?

  • I have searched the existing issues

Contact Details

No response

What should this feature add?

In workflows, the DenoiseLatents steps takes a ControlNet or a List[ControlNet], but the only way to get one (that I found) is via a collect -- this doesn't work when you're inside of an iteration, as it collects EVERY control net before passing them along. You can have an iterated control net off of, say, a video, and then have a fixed set of control nets to keep the context like a background or color palette.

Here's a more or less generic Concat node that does concat(T|T[], T|T[]): T[] (similar to JS's concat), attached in Additional Content. This node can be generalized to not just ControlNet type, but I just wanted to get going.

I'd love to have a way to coordinate indexes across graph invocations so I can grab the previous image and use that for context to make sequences, but hey, what can ya' do.

Alternatives

No response

Additional Content

from typing import Union

from .baseinvocation import BaseInvocation, BaseInvocationOutput, Input, InputField, InvocationContext, invocation, UIType, OutputField, invocation_output
from .controlnet_image_processors import ControlField


class FieldDescriptions:
    control = "An input ControlNet or List[ControlNet]"


@invocation_output("JoinControlNetsOutput")
class JoinControlNetsOutput(BaseInvocationOutput):
    collection: list[ControlField] = OutputField(
        description="The list of ControlNets for inference", title="ControlNets", ui_type=UIType.Collection
    )


@invocation("JoinControlNetsInvocation", title="Join ControlNets", tags=["collection", "controlnet", "i2i", "img2img"], category="collections")
class JoinControlNetsInvocation(BaseInvocation):
    """Concatenate 2 input ControlNet or List[ControlNet] inputs"""

    first: Union[ControlField, list[ControlField]] = InputField(
        default=None, description=FieldDescriptions.control, input=Input.Connection, ui_order=0
    )
    second: Union[ControlField, list[ControlField]] = InputField(
        default=None, description=FieldDescriptions.control, input=Input.Connection, ui_order=1
    )

    def invoke(self, context: InvocationContext) -> JoinControlNetsOutput:
        control_list = []
        self.concat_field(control_list, self.first)
        self.concat_field(control_list, self.second)
        return JoinControlNetsOutput(collection=control_list)

    def concat_field(self, control_list: list[ControlField], input: Union[ControlField, list[ControlField]]):
        if isinstance(input, ControlField):
            control_list.append(input)
        elif isinstance(input, list):
            control_list.extend(input)
        return control_list

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions