From 8a9d354943d752997de5165472993ce3e220adca Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Thu, 4 Jun 2026 14:15:18 -0600 Subject: [PATCH 1/2] Adds Ideogram4 support --- .../ComfyUIBackend/WorkflowGenerator.cs | 2 +- .../WorkflowGeneratorModelSupport.cs | 21 ++++++++++++++++++- .../ComfyUIBackend/WorkflowGeneratorSteps.cs | 8 +++++++ src/Text2Image/T2IModelClassSorter.cs | 6 ++++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGenerator.cs b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGenerator.cs index b4472813b..ed94bf9c6 100644 --- a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGenerator.cs +++ b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGenerator.cs @@ -959,7 +959,7 @@ public string CreateKSampler(JArray model, JArray pos, JArray neg, JArray latent } } // TODO: Registry of model default preferences instead of this - else if (IsFlux() || IsWanVideo() || IsWanVideo22() || IsOmniGen() || IsQwenImage() || IsZImage() || IsZetaChroma() || IsErnie() || IsHiDreamO1() || IsLens()) + else if (IsFlux() || IsWanVideo() || IsWanVideo22() || IsOmniGen() || IsQwenImage() || IsZImage() || IsZetaChroma() || IsErnie() || IsHiDreamO1() || IsLens() || IsIdeogram4()) { defscheduler ??= "simple"; } diff --git a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs index 32e7c4bb8..7f50a96e4 100644 --- a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs +++ b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs @@ -94,6 +94,9 @@ public bool IsKontext() /// Returns true if the current model is Lens. public bool IsLens() => IsModelCompatClass(T2IModelClassSorter.CompatLens); + /// Returns true if the current model is Ideogram 4. + public bool IsIdeogram4() => IsModelCompatClass(T2IModelClassSorter.CompatIdeogram4); + /// Returns true if the current model supports Flux Guidance. public bool HasFluxGuidance() { @@ -272,7 +275,7 @@ public WGNodeData EmptyImage(int width, int height, int batchSize, string id = n ["width"] = width }, id)); } - else if (IsAnyFlux2() || IsErnie() || IsLens()) + else if (IsAnyFlux2() || IsErnie() || IsLens() || IsIdeogram4()) { return resultImage(CreateNode("EmptyFlux2LatentImage", new JObject() { @@ -1088,6 +1091,22 @@ public void LoadClip3(string type, string modelA, string modelB, string modelC) }); LoadingModel = [lensCfgNormNode, 0]; } + else if (IsIdeogram4()) + { + helpers.LoadClip("ideogram4", helpers.GetQwen3_8bModel()); + helpers.DoVaeLoader(UserInput.SourceSession?.User?.Settings?.VAEs?.DefaultFlux2VAE, "flux-2", "flux2-vae"); + string ideogramRescaleNode = CreateNode("RescaleCFG", new JObject() + { + ["model"] = LoadingModel, + ["multiplier"] = 0.7 + }); + LoadingModel = [ideogramRescaleNode, 0]; + string ideogramCfgZeroStarNode = CreateNode("CFGZeroStar", new JObject() + { + ["model"] = LoadingModel + }); + LoadingModel = [ideogramCfgZeroStarNode, 0]; + } else if (IsFlux() && (LoadingClip is null || LoadingVAE is null || UserInput.Get(T2IParamTypes.T5XXLModel) is not null || UserInput.Get(T2IParamTypes.ClipLModel) is not null)) { helpers.LoadClip2("flux", helpers.GetT5XXLModel(), helpers.GetClipLModel()); diff --git a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorSteps.cs b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorSteps.cs index 067bd1ee8..5ee466d18 100644 --- a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorSteps.cs +++ b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorSteps.cs @@ -974,6 +974,14 @@ void requireLora(string name, string url, string hash) AddStep(g => { g.FinalNegativePrompt = g.CreateConditioning(g.UserInput.Get(T2IParamTypes.NegativePrompt, ""), g.CurrentTextEnc.Path, g.UserInput.Get(T2IParamTypes.Model), false, "7"); + if (g.IsIdeogram4()) + { + string zeroed = g.CreateNode("ConditioningZeroOut", new JObject() + { + ["conditioning"] = g.FinalNegativePrompt + }); + g.FinalNegativePrompt = [zeroed, 0]; + } }, -7); #endregion #region ControlNet diff --git a/src/Text2Image/T2IModelClassSorter.cs b/src/Text2Image/T2IModelClassSorter.cs index ac2f45862..0a5027c30 100644 --- a/src/Text2Image/T2IModelClassSorter.cs +++ b/src/Text2Image/T2IModelClassSorter.cs @@ -72,6 +72,7 @@ public static T2IModelCompatClass CompatAnima = RegisterCompat(new() { ID = "anima", ShortCode = "Anima", LorasTargetTextEnc = false }), CompatHiDreamO1 = RegisterCompat(new() { ID = "hidream-o1", ShortCode = "HiDrO1", LorasTargetTextEnc = false }), CompatLens = RegisterCompat(new() { ID = "lens", ShortCode = "Lens", LorasTargetTextEnc = false }), + CompatIdeogram4 = RegisterCompat(new() { ID = "ideogram-4", ShortCode = "Ideo4", LorasTargetTextEnc = false }), // Audio models CompatAceStep15 = RegisterCompat(new() { ID = "ace-step-1_5", ShortCode = "Ace15", IsAudioModel = true }), // Obscure old random ones @@ -160,6 +161,7 @@ bool isFluxLora(JObject h) bool isFlux2Klein9BLora(JObject h) => hasLoraKey(h, "single_blocks.23.linear1"); bool isFlux2DevLora(JObject h) => hasLoraKey(h, "single_blocks.47.linear2"); bool isLens(JObject h) => h.ContainsKey("transformer_blocks.0.attn.norm_added_q.weight") && h.ContainsKey("transformer_blocks.0.img_mlp.w1.weight"); + bool isIdeogram4(JObject h) => h.ContainsKey("embed_image_indicator.weight") && h.ContainsKey("llm_cond_proj.weight") && h.ContainsKey("t_embedding.mlp_in.weight") && h.ContainsKey("layers.0.attention.qkv.weight"); bool isSD35Lora(JObject h) => h.ContainsKey("transformer.transformer_blocks.0.attn.to_k.lora_A.weight") && h.ContainsKey("transformer.transformer_blocks.37.attn.to_out.0.lora_B.weight"); bool isMochi(JObject h) => hasKey(h, "blocks.0.attn.k_norm_x.weight"); bool isMochiVae(JObject h) => h.ContainsKey("encoder.layers.4.layers.1.attn_block.attn.qkv.weight") || h.ContainsKey("layers.4.layers.1.attn_block.attn.qkv.weight") || h.ContainsKey("blocks.2.blocks.3.stack.5.weight") || h.ContainsKey("decoder.blocks.2.blocks.3.stack.5.weight"); @@ -485,6 +487,10 @@ JToken GetEmbeddingKey(JObject h) { return isLens(h); }}); + Register(new() { ID = "ideogram-4", CompatClass = CompatIdeogram4, Name = "Ideogram 4", StandardWidth = 1024, StandardHeight = 1024, IsThisModelOfClass = (m, h) => + { + return isIdeogram4(h); + }}); // ====================== Wan Video ====================== Register(new() { ID = "wan-2_1-text2video/vae", CompatClass = CompatWan21, Name = "Wan 2.1 VAE", StandardWidth = 640, StandardHeight = 640, IsThisModelOfClass = (m, h) => { return false; }}); Register(new() { ID = "wan-2_1-text2video-1_3b", CompatClass = CompatWan21_1_3b, Name = "Wan 2.1 Text2Video 1.3B", StandardWidth = 640, StandardHeight = 640, IsThisModelOfClass = (m, h) => From 5dc09a4ef7b9cb0eb735b5b6313aef2341ddde8d Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Thu, 4 Jun 2026 14:23:14 -0600 Subject: [PATCH 2/2] Drop unneeded nodes --- .../ComfyUIBackend/WorkflowGeneratorModelSupport.cs | 11 ----------- .../ComfyUIBackend/WorkflowGeneratorSteps.cs | 8 -------- 2 files changed, 19 deletions(-) diff --git a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs index 7f50a96e4..63a29fadc 100644 --- a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs +++ b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs @@ -1095,17 +1095,6 @@ public void LoadClip3(string type, string modelA, string modelB, string modelC) { helpers.LoadClip("ideogram4", helpers.GetQwen3_8bModel()); helpers.DoVaeLoader(UserInput.SourceSession?.User?.Settings?.VAEs?.DefaultFlux2VAE, "flux-2", "flux2-vae"); - string ideogramRescaleNode = CreateNode("RescaleCFG", new JObject() - { - ["model"] = LoadingModel, - ["multiplier"] = 0.7 - }); - LoadingModel = [ideogramRescaleNode, 0]; - string ideogramCfgZeroStarNode = CreateNode("CFGZeroStar", new JObject() - { - ["model"] = LoadingModel - }); - LoadingModel = [ideogramCfgZeroStarNode, 0]; } else if (IsFlux() && (LoadingClip is null || LoadingVAE is null || UserInput.Get(T2IParamTypes.T5XXLModel) is not null || UserInput.Get(T2IParamTypes.ClipLModel) is not null)) { diff --git a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorSteps.cs b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorSteps.cs index 5ee466d18..067bd1ee8 100644 --- a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorSteps.cs +++ b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorSteps.cs @@ -974,14 +974,6 @@ void requireLora(string name, string url, string hash) AddStep(g => { g.FinalNegativePrompt = g.CreateConditioning(g.UserInput.Get(T2IParamTypes.NegativePrompt, ""), g.CurrentTextEnc.Path, g.UserInput.Get(T2IParamTypes.Model), false, "7"); - if (g.IsIdeogram4()) - { - string zeroed = g.CreateNode("ConditioningZeroOut", new JObject() - { - ["conditioning"] = g.FinalNegativePrompt - }); - g.FinalNegativePrompt = [zeroed, 0]; - } }, -7); #endregion #region ControlNet