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..63a29fadc 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,11 @@ 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");
+ }
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/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) =>