From 7ce9bf7772451bfd12f0e5d3131e4ac2c5dc6b9b Mon Sep 17 00:00:00 2001 From: xnexuzx Date: Thu, 30 Apr 2026 20:49:39 -0400 Subject: [PATCH 1/3] Feature: Implement generation queue for inference tasks This commit introduces a queuing system for inference generations, allowing users to queue multiple tasks sequentially without blocking the UI. Key changes: - Added `QueueGenerationCommand` to save the current ViewModel state into a queue. - Implemented `ProcessQueueAsync` background loop to execute queued generations sequentially while respecting active processes and user cancellations. - Updated `InferenceTextToImageView` to include a dynamic 'Queue Generation' button that expands with the count. - Added a 'Clear Queue' command with a trash icon to allow users to empty pending tasks. --- .../Base/InferenceGenerationViewModelBase.cs | 84 ++++++++++++++++++- .../Inference/InferenceTextToImageView.axaml | 23 ++++- 2 files changed, 103 insertions(+), 4 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs index 41537a3e4..ace8c2bbb 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel.DataAnnotations; @@ -13,6 +13,7 @@ using AsyncAwaitBestPractices; using Avalonia.Controls.Notifications; using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using ExifLibrary; using FluentAvalonia.UI.Controls; @@ -75,6 +76,87 @@ public abstract partial class InferenceGenerationViewModelBase [JsonIgnore] public IInferenceClientManager ClientManager { get; } + private readonly List _generationQueue = []; + private bool _isProcessingQueue; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(QueueGenerationText))] + [NotifyPropertyChangedFor(nameof(IsQueueClearable))] + [property: JsonIgnore] + private int queuedGenerationsCount; + + public string QueueGenerationText => + QueuedGenerationsCount > 0 ? $"Queue Generation ({QueuedGenerationsCount})" : "Queue Generation"; + + public bool IsQueueClearable => QueuedGenerationsCount > 0; + + [RelayCommand] + private void ClearQueue() + { + _generationQueue.Clear(); + QueuedGenerationsCount = 0; + Logger.Info("Generation queue cleared"); + } + + [RelayCommand] + private void QueueGeneration() + { + var doc = InferenceProjectDocument.FromLoadable(this); + _generationQueue.Add(doc); + QueuedGenerationsCount = _generationQueue.Count; + Logger.Info("Queued generation. Queue size: {QueueSize}", QueuedGenerationsCount); + + ProcessQueueAsync().SafeFireAndForget(ex => Logger.Error(ex, "Error processing generation queue")); + } + + private async Task ProcessQueueAsync() + { + if (_isProcessingQueue) + return; + + _isProcessingQueue = true; + + try + { + while (_generationQueue.Count > 0) + { + // Wait for any active generation to complete before starting the next + if (GenerateImageCommand.IsRunning) + { + var executionTask = GenerateImageCommand.ExecutionTask; + if (executionTask is not null) + { + await executionTask; + } + } + + // Re-check after awaiting — queue may have been cleared + if (_generationQueue.Count == 0) + break; + + // Dequeue and load state on UI thread + var nextDoc = _generationQueue[0]; + _generationQueue.RemoveAt(0); + QueuedGenerationsCount = _generationQueue.Count; + + await Dispatcher.UIThread.InvokeAsync(() => LoadStateFromJsonObject(nextDoc.State)); + + try + { + await GenerateImageCommand.ExecuteAsync(default(GenerateFlags)); + } + catch (Exception ex) + { + Logger.Error(ex, "Queued generation failed"); + } + } + } + finally + { + _isProcessingQueue = false; + } + } + /// protected InferenceGenerationViewModelBase( IServiceManager vmFactory, diff --git a/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml b/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml index 61b539e6e..1828fdea1 100644 --- a/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml +++ b/StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml @@ -1,4 +1,4 @@ -