diff --git a/docs/Model Support.md b/docs/Model Support.md index adf7a4c61..0e510cf87 100644 --- a/docs/Model Support.md +++ b/docs/Model Support.md @@ -23,6 +23,7 @@ [Lens](#lens) | MMDiT | 2026 | Microsoft | 4B | Minimal | Modern, lightweight, eh quality | [Ideogram 4](#ideogram-4) | DiT | 2026 | Ideogram AI | 9B | Yes | Modern, advanced on input understanding | [Krea 2](#krea-2) | DiT | 2026 | Krea AI | 12B | Yes | Modern, extremely smart and great quality | +[Boogu](#boogu) | MMDiT | 2026 | Boogu | 10B | Minimal | Modern, fast | Old or bad options also tracked listed via [Obscure Model Support](/docs/Obscure%20Model%20Support.md): @@ -693,6 +694,24 @@ For upscaling with SD3, the `Refiner Do Tiling` parameter is highly recommended - **Scheduler:** Default is fine. - **Sigma Shift:** Defaults to `1.15` +# Boogu + +- [Boogu]() is supported in SwarmUI! +- It is a 10B model, derived from OmniGen, that comes in three separate variants - **Base**, **Edit**, and **Turbo**: + - **Base**: [Comfy-Org/Boogu-Image - Base FP8]() + - **Edit** - image editing, takes a prompt image as a reference: [Comfy-Org/Boogu-Image - Edit FP8]() + - Or the NVFP4 (6 gigs) here: [Comfy-Org/Boogu-Image - Edit nvfp4]() + - **Turbo** - very fast, low step counts: [Comfy-Org/Boogu-Image - Turbo FP8]() + - Or the NVFP4 (6 gigs) here: [Comfy-Org/Boogu-Image - Turbo nvfp4]() +- Uses the Flux.1 VAE and a Qwen3-VL8B text encoder, both downloaded and handled automatically. +- For editing, use the `Edit` model and give it a prompt image - SwarmUI automatically wires it in as the reference. +- **Parameters:** recommendations differ between the Base, Edit, and Turbo models: + - **Sampler**: For Turbo, use LCM, otherwise default is fine, DPM++ 2M is recommended as a bit better than Euler for these models. + - **Scheduler:** For Turbo, use SGM Uniform, otherwise default is fine. + - **CFG Scale:** For Turbo, `1`, otherwise normal CFG ranges (around `4`). + - **Steps:** For Turbo, `4` is recommended, otherwise `20` as normal. + - **Resolution:** Side length `1024` is the default. + - **Sigma Shift:** Default is `3.16`. # Video Models diff --git a/src/BuiltinExtensions/ComfyUIBackend/ExtraNodes/SwarmComfyCommon/SwarmTextHandling.py b/src/BuiltinExtensions/ComfyUIBackend/ExtraNodes/SwarmComfyCommon/SwarmTextHandling.py index 95e77c997..bc946bfb9 100644 --- a/src/BuiltinExtensions/ComfyUIBackend/ExtraNodes/SwarmComfyCommon/SwarmTextHandling.py +++ b/src/BuiltinExtensions/ComfyUIBackend/ExtraNodes/SwarmComfyCommon/SwarmTextHandling.py @@ -70,7 +70,7 @@ def encode(self, clip, steps: int, prompt: str, width: int, height: int, target_ def tokenize(text: str): nonlocal images if clip_vision_output is not None: - return clip.tokenize(text, llama_template=llama_template, image_embeds=clip_vision_output.mm_projected) + return clip.tokenize(text, llama_template=llama_template if llama_template else None, image_embeds=clip_vision_output.mm_projected) elif images is not None: if append_images: image_prompt = "" @@ -83,7 +83,7 @@ def tokenize(text: str): text = image_prompt + text else: text = text + image_prompt - return clip.tokenize(text, llama_template=llama_template, images=images) + return clip.tokenize(text, llama_template=llama_template if llama_template else None, images=images) else: return clip.tokenize(text) diff --git a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGenerator.cs b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGenerator.cs index 323aeae31..a0ea4dca5 100644 --- a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGenerator.cs +++ b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGenerator.cs @@ -769,9 +769,9 @@ public List LoadPromptImagesForMainRef(List images) public (JArray, JArray, JArray, JArray) BuildInputImageHandling(List images, JArray pos, JArray neg, JArray latent) { JArray imgNeg = null; - if (IsKontext() || IsOmniGen() || IsQwenImage() || IsAnyFlux2()) + if (IsKontext() || IsOmniGen() || IsQwenImage() || IsAnyFlux2() || IsBoogu()) { - if (IsOmniGen() || IsQwenImageEditPlus()) + if (IsOmniGen() || IsQwenImageEditPlus() || IsBoogu()) { imgNeg = neg; } @@ -803,7 +803,7 @@ void makeRefLatent(JArray image) } if (img is not null) { - if (IsQwenImageEditPlus()) + if (IsQwenImageEditPlus() || IsBoogu()) { neg = imgNeg; } @@ -970,6 +970,10 @@ public string CreateKSampler(JArray model, JArray pos, JArray neg, JArray latent defsampler ??= "lcm"; defscheduler ??= "simple"; } + else if (IsBoogu()) + { + defscheduler ??= "simple"; + } // TODO: Registry of model default preferences instead of this else if (IsFlux() || IsWanVideo() || IsWanVideo22() || IsOmniGen() || IsQwenImage() || IsZImage() || IsZetaChroma() || IsErnie() || IsHiDreamO1() || IsLens() || IsPixelDiT() || IsKrea2()) { @@ -1301,7 +1305,7 @@ public JArray GetPromptImage(bool fixSize, bool promptSize = false, int index = doesFit = false; } } - else if (IsQwenImageEditPlus() && promptSize) + else if ((IsBoogu() || IsQwenImageEditPlus()) && promptSize) { target = 384; doesFit = false; @@ -2345,7 +2349,7 @@ public JArray CreateConditioningDirect(string prompt, JArray clip, T2IModel mode ["text"] = prompt }, id); } - else if (IsIdeogram4() || IsKrea2()) + else if (IsIdeogram4() || IsKrea2() || (IsBoogu() && isPositive)) { JArray imageNode = GetPromptImage(true, true, 0); for (int i = 1; i < 10; i++) @@ -2373,7 +2377,7 @@ public JArray CreateConditioningDirect(string prompt, JArray clip, T2IModel mode ["target_height"] = height, ["guidance"] = UserInput.Get(T2IParamTypes.FluxGuidanceScale, defaultGuidance), ["images"] = imageNode, - ["llama_template"] = "krea2" // TODO: Ideogram preferred template? + ["llama_template"] = IsBoogu() ? null : "krea2" // TODO: Ideogram preferred template? }, id); } else if (IsQwenImageEdit() && (isPositive || IsQwenImageEditPlus()) && (qwenImage = GetPromptImage(true, true)) is not null) diff --git a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs index 8c2e3c1e8..97ba2aa02 100644 --- a/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs +++ b/src/BuiltinExtensions/ComfyUIBackend/WorkflowGeneratorModelSupport.cs @@ -157,6 +157,9 @@ public bool IsQwenImageEditPlus() /// Returns true if the current model is Krea 2. public bool IsKrea2() => IsModelCompatClass(T2IModelClassSorter.CompatKrea2); + /// Returns true if the current model is Boogu. + public bool IsBoogu() => IsModelCompatClass(T2IModelClassSorter.CompatBoogu); + /// Returns true if the current model is Hunyuan Video (original / v1). public bool IsHunyuanVideo() => IsModelCompatClass(T2IModelClassSorter.CompatHunyuanVideo); @@ -1136,6 +1139,11 @@ public void LoadClip3(string type, string modelA, string modelB, string modelC) helpers.LoadClip("krea2", helpers.GetQwen3vl_4bModel()); helpers.DoVaeLoader(UserInput.SourceSession?.User?.Settings?.VAEs?.DefaultQwenVAE, "qwen-image", "qwen-image-vae"); } + else if (IsBoogu()) + { + helpers.LoadClip("boogu", helpers.GetQwen3vl_8bModel()); + helpers.DoVaeLoader(UserInput.SourceSession?.User?.Settings?.VAEs?.DefaultFluxVAE, "flux-1", "flux-ae"); + } 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()); @@ -1419,7 +1427,7 @@ public void LoadClip3(string type, string modelA, string modelB, string modelC) }); LoadingModel = [samplingNode, 0]; } - else if (IsZImage() || IsAceStep15() || IsAnima() || IsKrea2()) + else if (IsZImage() || IsAceStep15() || IsAnima() || IsKrea2() || IsBoogu()) { string samplingNode = CreateNode("ModelSamplingAuraFlow", new JObject() { diff --git a/src/Text2Image/T2IModelClassSorter.cs b/src/Text2Image/T2IModelClassSorter.cs index fbe554bdf..fdf807f59 100644 --- a/src/Text2Image/T2IModelClassSorter.cs +++ b/src/Text2Image/T2IModelClassSorter.cs @@ -94,6 +94,7 @@ public static T2IModelCompatClass CompatPixelDiT = RegisterCompat(new() { ID = "pixeldit", ShortCode = "PixDiT", LorasTargetTextEnc = false }), CompatIdeogram4 = RegisterCompat(new() { ID = "ideogram-4", ShortCode = "Ideo4", LorasTargetTextEnc = false, VaeFamily = VaeFlux2 }), CompatKrea2 = RegisterCompat(new() { ID = "krea-2", ShortCode = "Krea2", LorasTargetTextEnc = false, VaeFamily = VaeQwenImage }), + CompatBoogu = RegisterCompat(new() { ID = "boogu", ShortCode = "Boogu", LorasTargetTextEnc = false, VaeFamily = VaeFlux1 }), // Audio models CompatAceStep15 = RegisterCompat(new() { ID = "ace-step-1_5", ShortCode = "Ace15", IsAudioModel = true }), // Obscure old random ones @@ -236,7 +237,8 @@ bool isZImageLora(JObject h) => (hasLoraKey(h, "layers.0.adaLN_modulation.0") && bool isChromaRadiance(JObject h) => hasKey(h, "nerf_image_embedder.embedder.0.bias"); bool isPiD(JObject h) => h.ContainsKey("net.lq_proj.latent_proj.0.weight") && h.ContainsKey("net.pixel_blocks.0.attn.q_norm.weight") && h.ContainsKey("net.pixel_blocks.0.compress_to_attn.weight"); bool isPixelDiT(JObject h) => h.ContainsKey("core.pixel_embedder.proj.weight") && h.ContainsKey("core.pixel_blocks.0.attn.q_norm.weight") && h.ContainsKey("core.pixel_blocks.0.compress_to_attn.weight") && !isPiD(h); - bool isOmniGen(JObject h) => h.ContainsKey("time_caption_embed.timestep_embedder.linear_2.weight") && h.ContainsKey("context_refiner.0.attn.norm_k.weight"); + bool isOmniGen(JObject h) => h.ContainsKey("time_caption_embed.timestep_embedder.linear_2.weight") && h.ContainsKey("context_refiner.0.attn.norm_k.weight") && !isBoogu(h); + bool isBoogu(JObject h) => hasKey(h, "double_stream_layers.0.img_instruct_attn.processor.img_to_q.weight") && hasKey(h, "double_stream_layers.0.img_instruct_attn.processor.instruct_to_q.weight"); bool isQwenImage(JObject h) => (h.ContainsKey("time_text_embed.timestep_embedder.linear_1.bias") && h.ContainsKey("img_in.bias") && (h.ContainsKey("transformer_blocks.0.attn.add_k_proj.bias") || h.ContainsKey("transformer_blocks.0.attn.add_qkv_proj.bias"))) || (h.ContainsKey("model.diffusion_model.time_text_embed.timestep_embedder.linear_1.bias") && h.ContainsKey("model.diffusion_model.img_in.bias") && (h.ContainsKey("model.diffusion_model.transformer_blocks.0.attn.add_k_proj.bias") || h.ContainsKey("model.diffusion_model.transformer_blocks.0.attn.add_qkv_proj.bias"))); bool isQwenImageEdit2511(JObject h) => h.ContainsKey("__index_timestep_zero__"); @@ -865,6 +867,11 @@ JToken GetEmbeddingKey(JObject h) { return isLongcat(h); }}); + // ====================== Boogu ====================== + Register(new() { ID = "boogu", CompatClass = CompatBoogu, Name = "Boogu", StandardWidth = 1024, StandardHeight = 1024, IsThisModelOfClass = (m, h) => + { + return isBoogu(h); + }}); // ====================== Audio Models ====================== Register(new() { ID = "ace-step-1_5", CompatClass = CompatAceStep15, Name = "Ace Step 1.5", IsThisModelOfClass = (m, h) => {