From 05a418d422e806a453c8d74023944cc9b1913292 Mon Sep 17 00:00:00 2001 From: NeuralFault Date: Fri, 23 Jan 2026 19:13:21 -0500 Subject: [PATCH 1/2] Implementation of Tiled VAE Decode in Wan inference workflows and UI via addons for sampler --- .../InferenceWanImageToVideoViewModel.cs | 19 ++++++++------ .../InferenceWanTextToVideoViewModel.cs | 25 +++++++++++-------- .../Inference/WanSamplerCardViewModel.cs | 10 ++++++++ .../Api/Comfy/Nodes/ComfyNodeBuilder.cs | 13 +++++++--- 4 files changed, 44 insertions(+), 23 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceWanImageToVideoViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceWanImageToVideoViewModel.cs index e6b2ff4b..60802c56 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceWanImageToVideoViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceWanImageToVideoViewModel.cs @@ -39,16 +39,17 @@ RunningPackageService runningPackageService /// protected override void BuildPrompt(BuildPromptEventArgs args) { + var applyArgs = args.ToModuleApplyStepEventArgs(); var builder = args.Builder; builder.Connections.Seed = args.SeedOverride switch { { } seed => Convert.ToUInt64(seed), - _ => Convert.ToUInt64(SeedCardViewModel.Seed) + _ => Convert.ToUInt64(SeedCardViewModel.Seed), }; // Load models - ModelCardViewModel.ApplyStep(args); + ModelCardViewModel.ApplyStep(applyArgs); // Setup latent from image var imageLoad = builder.Nodes.AddTypedNode( @@ -57,22 +58,24 @@ protected override void BuildPrompt(BuildPromptEventArgs args) Name = builder.Nodes.GetUniqueName("ControlNet_LoadImage"), Image = SelectImageCardViewModel.ImageSource?.GetHashGuidFileNameCached("Inference") - ?? throw new ValidationException() + ?? throw new ValidationException(), } ); builder.Connections.Primary = imageLoad.Output1; builder.Connections.PrimarySize = SelectImageCardViewModel.CurrentBitmapSize; - BatchSizeCardViewModel.ApplyStep(args); + BatchSizeCardViewModel.ApplyStep(applyArgs); - SelectImageCardViewModel.ApplyStep(args); + SelectImageCardViewModel.ApplyStep(applyArgs); - PromptCardViewModel.ApplyStep(args); + PromptCardViewModel.ApplyStep(applyArgs); - SamplerCardViewModel.ApplyStep(args); + SamplerCardViewModel.ApplyStep(applyArgs); + + applyArgs.InvokeAllPreOutputActions(); // Animated webp output - VideoOutputSettingsCardViewModel.ApplyStep(args); + VideoOutputSettingsCardViewModel.ApplyStep(applyArgs); } /// diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceWanTextToVideoViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceWanTextToVideoViewModel.cs index 4b2ac181..75f88189 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceWanTextToVideoViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceWanTextToVideoViewModel.cs @@ -59,7 +59,7 @@ RunningPackageService runningPackageService samplerCard.IsSamplerSelectionEnabled = true; samplerCard.IsSchedulerSelectionEnabled = true; samplerCard.DenoiseStrength = 1.0d; - samplerCard.EnableAddons = false; + samplerCard.EnableAddons = true; samplerCard.IsLengthEnabled = true; samplerCard.Width = 832; samplerCard.Height = 480; @@ -70,8 +70,8 @@ RunningPackageService runningPackageService BatchSizeCardViewModel = vmFactory.Get(); - VideoOutputSettingsCardViewModel = vmFactory.Get( - vm => vm.Fps = 16.0d + VideoOutputSettingsCardViewModel = vmFactory.Get(vm => + vm.Fps = 16.0d ); StackCardViewModel = vmFactory.Get(); @@ -89,16 +89,17 @@ protected override void BuildPrompt(BuildPromptEventArgs args) { base.BuildPrompt(args); + var applyArgs = args.ToModuleApplyStepEventArgs(); var builder = args.Builder; builder.Connections.Seed = args.SeedOverride switch { { } seed => Convert.ToUInt64(seed), - _ => Convert.ToUInt64(SeedCardViewModel.Seed) + _ => Convert.ToUInt64(SeedCardViewModel.Seed), }; // Load models - ModelCardViewModel.ApplyStep(args); + ModelCardViewModel.ApplyStep(applyArgs); builder.SetupEmptyLatentSource( SamplerCardViewModel.Width, @@ -109,14 +110,16 @@ protected override void BuildPrompt(BuildPromptEventArgs args) LatentType.Hunyuan ); - BatchSizeCardViewModel.ApplyStep(args); + BatchSizeCardViewModel.ApplyStep(applyArgs); - PromptCardViewModel.ApplyStep(args); + PromptCardViewModel.ApplyStep(applyArgs); - SamplerCardViewModel.ApplyStep(args); + SamplerCardViewModel.ApplyStep(applyArgs); + + applyArgs.InvokeAllPreOutputActions(); // Animated webp output - VideoOutputSettingsCardViewModel.ApplyStep(args); + VideoOutputSettingsCardViewModel.ApplyStep(applyArgs); } /// @@ -165,13 +168,13 @@ CancellationToken cancellationToken OutputNodeNames = buildPromptArgs.Builder.Connections.OutputNodeNames.ToArray(), Parameters = SaveStateToParameters(new GenerationParameters()) with { - Seed = Convert.ToUInt64(seed) + Seed = Convert.ToUInt64(seed), }, Project = inferenceProject, FilesToTransfer = buildPromptArgs.FilesToTransfer, BatchIndex = i, // Only clear output images on the first batch - ClearOutputImages = i == 0 + ClearOutputImages = i == 0, }; batchArgs.Add(generationArgs); diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/WanSamplerCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/WanSamplerCardViewModel.cs index 28fff5c0..5ef3176c 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/WanSamplerCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/WanSamplerCardViewModel.cs @@ -1,9 +1,11 @@ using System.ComponentModel.DataAnnotations; +using System.Linq; using Injectio.Attributes; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Avalonia.ViewModels.Inference.Modules; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Models.Api.Comfy; @@ -34,6 +36,14 @@ TabContext tabContext public override void ApplyStep(ModuleApplyStepEventArgs e) { + if (EnableAddons) + { + foreach (var module in ModulesCardViewModel.Cards.OfType()) + { + module.ApplyStep(e); + } + } + // Set primary sampler and scheduler var primarySampler = SelectedSampler ?? throw new ValidationException("Sampler not selected"); e.Builder.Connections.PrimarySampler = primarySampler; diff --git a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs index c164a632..3a8eb7b3 100644 --- a/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs +++ b/StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs @@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.Drawing; +using System.Text.Json.Serialization; using OneOf; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Extensions; @@ -67,17 +68,21 @@ public record TiledVAEDecode : ComfyTypedNodeBase { public required LatentNodeConnection Samples { get; init; } public required VAENodeConnection Vae { get; init; } - + [Range(64, 4096)] + [JsonPropertyName("tile_size")] public int TileSize { get; init; } = 512; - + [Range(0, 4096)] + [JsonPropertyName("overlap")] public int Overlap { get; init; } = 64; - + [Range(8, 4096)] + [JsonPropertyName("temporal_size")] public int TemporalSize { get; init; } = 64; - + [Range(4, 4096)] + [JsonPropertyName("temporal_overlap")] public int TemporalOverlap { get; init; } = 8; } From 9cfbc37d4b70d5e0f199fcf11642bf79f6f09b9f Mon Sep 17 00:00:00 2001 From: NeuralFault Date: Fri, 23 Jan 2026 19:43:22 -0500 Subject: [PATCH 2/2] Refactor OnRunningNodeChanged to fix UI bug in video gen UI improve progress update handling in InferenceGenerationViewModelBase --- .../Base/InferenceGenerationViewModelBase.cs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs index da454dfc..41537a3e 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs @@ -143,7 +143,7 @@ protected async Task WriteOutputImageAsync( { GenerationParameters = args.Parameters, ProjectType = args.Project?.ProjectType, - ProjectName = ProjectFile?.NameWithoutExtension + ProjectName = ProjectFile?.NameWithoutExtension, }; // Parse to format @@ -260,7 +260,7 @@ public async Task RunCustomGeneration( Project = InferenceProjectDocument.FromLoadable(this), FilesToTransfer = args.FilesToTransfer, Parameters = new GenerationParameters(), - ClearOutputImages = true + ClearOutputImages = true, }; await RunGeneration(generationArgs, cancellationToken); @@ -410,7 +410,7 @@ await notificationService.ShowAsync( { Title = "Prompt Completed", Body = $"Prompt [{promptTask.Id[..7].ToLower()}] completed successfully", - BodyImagePath = notificationImage?.FullPath + BodyImagePath = notificationImage?.FullPath, } ); } @@ -521,14 +521,14 @@ private async Task> ProcessOutputImages( var opts = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - Converters = { new JsonStringEnumConverter() } + Converters = { new JsonStringEnumConverter() }, }; var paramsJson = JsonSerializer.Serialize(parameters, opts); var smProject = JsonSerializer.Serialize(project, opts); var metadata = new Dictionary { { ExifTag.ImageDescription, paramsJson }, - { ExifTag.Software, smProject } + { ExifTag.Software, smProject }, }; var bytesWithMetadata = ImageMetadata.AddMetadataToWebp(imageArray, metadata); @@ -779,7 +779,7 @@ out var localSemVersion { ShowDialogOnStart = true, ModificationCompleteTitle = "Extensions Installed", - ModificationCompleteMessage = "Finished installing required extensions" + ModificationCompleteMessage = "Finished installing required extensions", }; EventManager.Instance.OnPackageInstallProgressAdded(runner); @@ -859,8 +859,14 @@ private void AttachRunningNodeChangedHandler(ComfyTask comfyTask) /// protected virtual void OnRunningNodeChanged(object? sender, string? nodeName) { - // Ignore if regular progress updates started - if (sender is not ComfyTask { HasProgressUpdateStarted: false }) + var task = sender as ComfyTask; + if (task == null) + { + return; + } + + // Ignore if regular progress updates started, unless the running node is different from the one reporting progress + if (task.HasProgressUpdateStarted && task.LastProgressUpdate?.RunningNode == nodeName) { return; } @@ -906,7 +912,7 @@ public ModuleApplyStepEventArgs ToModuleApplyStepEventArgs() { Builder = Builder, IsEnabledOverrides = overrides, - FilesToTransfer = FilesToTransfer + FilesToTransfer = FilesToTransfer, }; }