@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis ;
using System.ComponentModel.DataAnnotations ;
using System.Diagnostics.CodeAnalysis ;
using System.Drawing ;
using System.Drawing ;
using System.Runtime.Serialization ;
using System.Runtime.Serialization ;
using System.Text.Json.Serialization ;
using System.Text.Json.Serialization ;
@ -26,9 +27,7 @@ public class ComfyNodeBuilder
{
{
if ( i > 1 _ 0 0 0 _ 0 0 0 )
if ( i > 1 _ 0 0 0 _ 0 0 0 )
{
{
throw new InvalidOperationException (
throw new InvalidOperationException ( $"Could not find unique name for base {nameBase}" ) ;
$"Could not find unique name for base {nameBase}"
) ;
}
}
name = $"{nameBase}_{i + 1}" ;
name = $"{nameBase}_{i + 1}" ;
@ -63,39 +62,6 @@ public class ComfyNodeBuilder
public required double Denoise { get ; init ; }
public required double Denoise { get ; init ; }
}
}
/ * public static NamedComfyNode < LatentNodeConnection > KSampler (
string name ,
ModelNodeConnection model ,
ulong seed ,
int steps ,
double cfg ,
ComfySampler sampler ,
ComfyScheduler scheduler ,
ConditioningNodeConnection positive ,
ConditioningNodeConnection negative ,
LatentNodeConnection latentImage ,
double denoise
)
{
return new NamedComfyNode < LatentNodeConnection > ( name )
{
ClassType = "KSampler" ,
Inputs = new Dictionary < string , object? >
{
["model"] = model . Data ,
["seed"] = seed ,
["steps"] = steps ,
["cfg"] = cfg ,
["sampler_name"] = sampler . Name ,
["scheduler"] = scheduler . Name ,
["positive"] = positive . Data ,
["negative"] = negative . Data ,
["latent_image"] = latentImage . Data ,
["denoise"] = denoise
}
} ;
} * /
public record KSamplerAdvanced : ComfyTypedNodeBase < LatentNodeConnection >
public record KSamplerAdvanced : ComfyTypedNodeBase < LatentNodeConnection >
{
{
public required ModelNodeConnection Model { get ; init ; }
public required ModelNodeConnection Model { get ; init ; }
@ -117,44 +83,34 @@ public class ComfyNodeBuilder
public bool ReturnWithLeftoverNoise { get ; init ; }
public bool ReturnWithLeftoverNoise { get ; init ; }
}
}
/ * public static NamedComfyNode < LatentNodeConnection > KSamplerAdvanced (
public record SamplerCustom : ComfyTypedNodeBase < LatentNodeConnection , LatentNodeConnection >
string name ,
ModelNodeConnection model ,
bool addNoise ,
ulong noiseSeed ,
int steps ,
double cfg ,
ComfySampler sampler ,
ComfyScheduler scheduler ,
ConditioningNodeConnection positive ,
ConditioningNodeConnection negative ,
LatentNodeConnection latentImage ,
int startAtStep ,
int endAtStep ,
bool returnWithLeftoverNoise
)
{
{
return new NamedComfyNode < LatentNodeConnection > ( name )
public required ModelNodeConnection Model { get ; init ; }
{
public required bool AddNoise { get ; init ; }
ClassType = "KSamplerAdvanced" ,
public required ulong NoiseSeed { get ; init ; }
Inputs = new Dictionary < string , object? >
{
[Range(0d, 100d)]
["model"] = model . Data ,
public required double Cfg { get ; init ; }
["add_noise"] = addNoise ? "enable" : "disable" ,
["noise_seed"] = noiseSeed ,
public required ConditioningNodeConnection Positive { get ; init ; }
["steps"] = steps ,
public required ConditioningNodeConnection Negative { get ; init ; }
["cfg"] = cfg ,
public required SamplerNodeConnection Sampler { get ; init ; }
["sampler_name"] = sampler . Name ,
public required SigmasNodeConnection Sigmas { get ; init ; }
["scheduler"] = scheduler . Name ,
public required LatentNodeConnection LatentImage { get ; init ; }
["positive"] = positive . Data ,
}
["negative"] = negative . Data ,
["latent_image"] = latentImage . Data ,
public record KSamplerSelect : ComfyTypedNodeBase < SamplerNodeConnection >
["start_at_step"] = startAtStep ,
{
["end_at_step"] = endAtStep ,
public required string SamplerName { get ; init ; }
["return_with_leftover_noise"] = returnWithLeftoverNoise ? "enable" : "disable"
}
}
} ;
public record SDTurboScheduler : ComfyTypedNodeBase < SigmasNodeConnection >
} * /
{
public required ModelNodeConnection Model { get ; init ; }
[Range(1, 10)]
public required int Steps { get ; init ; }
}
public record EmptyLatentImage : ComfyTypedNodeBase < LatentNodeConnection >
public record EmptyLatentImage : ComfyTypedNodeBase < LatentNodeConnection >
{
{
@ -191,18 +147,11 @@ public class ComfyNodeBuilder
return new NamedComfyNode < ImageNodeConnection > ( name )
return new NamedComfyNode < ImageNodeConnection > ( name )
{
{
ClassType = "ImageUpscaleWithModel" ,
ClassType = "ImageUpscaleWithModel" ,
Inputs = new Dictionary < string , object? >
Inputs = new Dictionary < string , object? > { [ "upscale_model" ] = upscaleModel . Data , [ "image" ] = image . Data }
{
["upscale_model"] = upscaleModel . Data ,
["image"] = image . Data
}
} ;
} ;
}
}
public static NamedComfyNode < UpscaleModelNodeConnection > UpscaleModelLoader (
public static NamedComfyNode < UpscaleModelNodeConnection > UpscaleModelLoader ( string name , string modelName )
string name ,
string modelName
)
{
{
return new NamedComfyNode < UpscaleModelNodeConnection > ( name )
return new NamedComfyNode < UpscaleModelNodeConnection > ( name )
{
{
@ -323,8 +272,7 @@ public class ComfyNodeBuilder
public required string ControlNetName { get ; init ; }
public required string ControlNetName { get ; init ; }
}
}
public record ControlNetApplyAdvanced
public record ControlNetApplyAdvanced : ComfyTypedNodeBase < ConditioningNodeConnection , ConditioningNodeConnection >
: ComfyTypedNodeBase < ConditioningNodeConnection , ConditioningNodeConnection >
{
{
public required ConditioningNodeConnection Positive { get ; init ; }
public required ConditioningNodeConnection Positive { get ; init ; }
public required ConditioningNodeConnection Negative { get ; init ; }
public required ConditioningNodeConnection Negative { get ; init ; }
@ -335,10 +283,7 @@ public class ComfyNodeBuilder
public required double EndPercent { get ; init ; }
public required double EndPercent { get ; init ; }
}
}
public ImageNodeConnection Lambda_LatentToImage (
public ImageNodeConnection Lambda_LatentToImage ( LatentNodeConnection latent , VAENodeConnection vae )
LatentNodeConnection latent ,
VAENodeConnection vae
)
{
{
var name = GetUniqueName ( "VAEDecode" ) ;
var name = GetUniqueName ( "VAEDecode" ) ;
return Nodes
return Nodes
@ -353,10 +298,7 @@ public class ComfyNodeBuilder
. Output ;
. Output ;
}
}
public LatentNodeConnection Lambda_ImageToLatent (
public LatentNodeConnection Lambda_ImageToLatent ( ImageNodeConnection pixels , VAENodeConnection vae )
ImageNodeConnection pixels ,
VAENodeConnection vae
)
{
{
var name = GetUniqueName ( "VAEEncode" ) ;
var name = GetUniqueName ( "VAEEncode" ) ;
return Nodes
return Nodes
@ -380,9 +322,7 @@ public class ComfyNodeBuilder
ImageNodeConnection image
ImageNodeConnection image
)
)
{
{
var modelLoader = Nodes . AddNamedNode (
var modelLoader = Nodes . AddNamedNode ( UpscaleModelLoader ( $"{name}_UpscaleModelLoader" , modelName ) ) ;
UpscaleModelLoader ( $"{name}_UpscaleModelLoader" , modelName )
) ;
var upscaler = Nodes . AddNamedNode (
var upscaler = Nodes . AddNamedNode (
ImageUpscaleWithModel ( $"{name}_ImageUpscaleWithModel" , modelLoader . Output , image )
ImageUpscaleWithModel ( $"{name}_ImageUpscaleWithModel" , modelLoader . Output , image )
@ -425,16 +365,7 @@ public class ComfyNodeBuilder
. Output ,
. Output ,
image = >
image = >
Nodes
Nodes
. AddNamedNode (
. AddNamedNode ( ImageScale ( $"{name}_ImageUpscale" , image , upscaleInfo . Name , height , width , false ) )
ImageScale (
$"{name}_ImageUpscale" ,
image ,
upscaleInfo . Name ,
height ,
width ,
false
)
)
. Output
. Output
) ;
) ;
}
}
@ -445,22 +376,11 @@ public class ComfyNodeBuilder
var samplerImage = GetPrimaryAsImage ( primary , vae ) ;
var samplerImage = GetPrimaryAsImage ( primary , vae ) ;
// Do group upscale
// Do group upscale
var modelUpscaler = Group_UpscaleWithModel (
var modelUpscaler = Group_UpscaleWithModel ( $"{name}_ModelUpscale" , upscaleInfo . Name , samplerImage ) ;
$"{name}_ModelUpscale" ,
upscaleInfo . Name ,
samplerImage
) ;
// Since the model upscale is fixed to model (2x/4x), scale it again to the requested size
// Since the model upscale is fixed to model (2x/4x), scale it again to the requested size
var resizedScaled = Nodes . AddNamedNode (
var resizedScaled = Nodes . AddNamedNode (
ImageScale (
ImageScale ( $"{name}_ImageScale" , modelUpscaler . Output , "bilinear" , height , width , false )
$"{name}_ImageScale" ,
modelUpscaler . Output ,
"bilinear" ,
height ,
width ,
false
)
) ;
) ;
return resizedScaled . Output ;
return resizedScaled . Output ;
@ -512,22 +432,11 @@ public class ComfyNodeBuilder
) ;
) ;
// Do group upscale
// Do group upscale
var modelUpscaler = Group_UpscaleWithModel (
var modelUpscaler = Group_UpscaleWithModel ( $"{name}_ModelUpscale" , upscaleInfo . Name , samplerImage . Output ) ;
$"{name}_ModelUpscale" ,
upscaleInfo . Name ,
samplerImage . Output
) ;
// Since the model upscale is fixed to model (2x/4x), scale it again to the requested size
// Since the model upscale is fixed to model (2x/4x), scale it again to the requested size
var resizedScaled = Nodes . AddNamedNode (
var resizedScaled = Nodes . AddNamedNode (
ImageScale (
ImageScale ( $"{name}_ImageScale" , modelUpscaler . Output , "bilinear" , height , width , false )
$"{name}_ImageScale" ,
modelUpscaler . Output ,
"bilinear" ,
height ,
width ,
false
)
) ;
) ;
// Convert back to latent space
// Convert back to latent space
@ -597,22 +506,11 @@ public class ComfyNodeBuilder
) ;
) ;
// Do group upscale
// Do group upscale
var modelUpscaler = Group_UpscaleWithModel (
var modelUpscaler = Group_UpscaleWithModel ( $"{name}_ModelUpscale" , upscaleInfo . Name , samplerImage . Output ) ;
$"{name}_ModelUpscale" ,
upscaleInfo . Name ,
samplerImage . Output
) ;
// Since the model upscale is fixed to model (2x/4x), scale it again to the requested size
// Since the model upscale is fixed to model (2x/4x), scale it again to the requested size
var resizedScaled = Nodes . AddNamedNode (
var resizedScaled = Nodes . AddNamedNode (
ImageScale (
ImageScale ( $"{name}_ImageScale" , modelUpscaler . Output , "bilinear" , height , width , false )
$"{name}_ImageScale" ,
modelUpscaler . Output ,
"bilinear" ,
height ,
width ,
false
)
) ;
) ;
// No need to convert back to latent space
// No need to convert back to latent space
@ -654,22 +552,11 @@ public class ComfyNodeBuilder
if ( upscaleInfo . Type = = ComfyUpscalerType . ESRGAN )
if ( upscaleInfo . Type = = ComfyUpscalerType . ESRGAN )
{
{
// Do group upscale
// Do group upscale
var modelUpscaler = Group_UpscaleWithModel (
var modelUpscaler = Group_UpscaleWithModel ( $"{name}_ModelUpscale" , upscaleInfo . Name , image ) ;
$"{name}_ModelUpscale" ,
upscaleInfo . Name ,
image
) ;
// Since the model upscale is fixed to model (2x/4x), scale it again to the requested size
// Since the model upscale is fixed to model (2x/4x), scale it again to the requested size
var resizedScaled = Nodes . AddNamedNode (
var resizedScaled = Nodes . AddNamedNode (
ImageScale (
ImageScale ( $"{name}_ImageScale" , modelUpscaler . Output , "bilinear" , height , width , false )
$"{name}_ImageScale" ,
modelUpscaler . Output ,
"bilinear" ,
height ,
width ,
false
)
) ;
) ;
// No need to convert back to latent space
// No need to convert back to latent space
@ -764,10 +651,7 @@ public class ComfyNodeBuilder
/// <summary>
/// <summary>
/// Get or convert latest primary connection to latent
/// Get or convert latest primary connection to latent
/// </summary>
/// </summary>
public LatentNodeConnection GetPrimaryAsLatent (
public LatentNodeConnection GetPrimaryAsLatent ( PrimaryNodeConnection primary , VAENodeConnection vae )
PrimaryNodeConnection primary ,
VAENodeConnection vae
)
{
{
return primary . Match ( latent = > latent , image = > Lambda_ImageToLatent ( image , vae ) ) ;
return primary . Match ( latent = > latent , image = > Lambda_ImageToLatent ( image , vae ) ) ;
}
}
@ -807,10 +691,7 @@ public class ComfyNodeBuilder
/// <summary>
/// <summary>
/// Get or convert latest primary connection to image
/// Get or convert latest primary connection to image
/// </summary>
/// </summary>
public ImageNodeConnection GetPrimaryAsImage (
public ImageNodeConnection GetPrimaryAsImage ( PrimaryNodeConnection primary , VAENodeConnection vae )
PrimaryNodeConnection primary ,
VAENodeConnection vae
)
{
{
return primary . Match ( latent = > Lambda_LatentToImage ( latent , vae ) , image = > image ) ;
return primary . Match ( latent = > Lambda_LatentToImage ( latent , vae ) , image = > image ) ;
}
}
@ -825,10 +706,7 @@ public class ComfyNodeBuilder
return Connections . Primary . AsT1 ;
return Connections . Primary . AsT1 ;
}
}
return GetPrimaryAsImage (
return GetPrimaryAsImage ( Connections . Primary ? ? throw new NullReferenceException ( "No primary connection" ) , vae ) ;
Connections . Primary ? ? throw new NullReferenceException ( "No primary connection" ) ,
vae
) ;
}
}
/// <summary>
/// <summary>
@ -878,9 +756,7 @@ public class ComfyNodeBuilder
public ConditioningNodeConnection GetRefinerOrBaseConditioning ( )
public ConditioningNodeConnection GetRefinerOrBaseConditioning ( )
{
{
return RefinerConditioning
return RefinerConditioning ? ? BaseConditioning ? ? throw new NullReferenceException ( "No Conditioning" ) ;
? ? BaseConditioning
? ? throw new NullReferenceException ( "No Conditioning" ) ;
}
}
public ConditioningNodeConnection GetRefinerOrBaseNegativeConditioning ( )
public ConditioningNodeConnection GetRefinerOrBaseNegativeConditioning ( )
@ -892,10 +768,7 @@ public class ComfyNodeBuilder
public VAENodeConnection GetDefaultVAE ( )
public VAENodeConnection GetDefaultVAE ( )
{
{
return PrimaryVAE
return PrimaryVAE ? ? RefinerVAE ? ? BaseVAE ? ? throw new NullReferenceException ( "No VAE" ) ;
? ? RefinerVAE
? ? BaseVAE
? ? throw new NullReferenceException ( "No VAE" ) ;
}
}
}
}