diff --git a/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs b/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs
index f90baa4b..ad7e945b 100644
--- a/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs
+++ b/StabilityMatrix.Avalonia/Models/Inference/ModuleApplyStepEventArgs.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
-using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes;
+using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
namespace StabilityMatrix.Avalonia.Models.Inference;
@@ -29,18 +29,14 @@ public class ModuleApplyStepEventArgs : EventArgs
///
/// Generation overrides (like hires fix generate, current seed generate, etc.)
///
- public IReadOnlyDictionary IsEnabledOverrides { get; init; } =
- new Dictionary();
+ public IReadOnlyDictionary IsEnabledOverrides { get; init; } = new Dictionary();
public class ModuleApplyStepTemporaryArgs
{
///
/// Temporary conditioning apply step, used by samplers to apply control net.
///
- public (
- ConditioningNodeConnection Positive,
- ConditioningNodeConnection Negative
- )? Conditioning { get; set; }
+ public (ConditioningNodeConnection Positive, ConditioningNodeConnection Negative)? Conditioning { get; set; }
///
/// Temporary refiner conditioning apply step, used by samplers to apply control net.
diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
index 5da35214..6ce72dff 100644
--- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
+++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
@@ -100,6 +100,7 @@
+
diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs
index 3515089c..e49fe303 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs
@@ -23,6 +23,7 @@ using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Avalonia.ViewModels.Inference;
using StabilityMatrix.Avalonia.ViewModels.Inference.Modules;
+using StabilityMatrix.Core.Animation;
using StabilityMatrix.Core.Exceptions;
using StabilityMatrix.Core.Extensions;
using StabilityMatrix.Core.Helper;
@@ -41,9 +42,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Base;
/// This includes a progress reporter, image output view model, and generation virtual methods.
///
[SuppressMessage("ReSharper", "VirtualMemberNeverOverridden.Global")]
-public abstract partial class InferenceGenerationViewModelBase
- : InferenceTabViewModelBase,
- IImageGalleryComponent
+public abstract partial class InferenceGenerationViewModelBase : InferenceTabViewModelBase, IImageGalleryComponent
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
@@ -92,20 +91,14 @@ public abstract partial class InferenceGenerationViewModelBase
ImageGenerationEventArgs args,
int batchNum = 0,
int batchTotal = 0,
- bool isGrid = false
+ bool isGrid = false,
+ string fileExtension = "png"
)
{
var defaultOutputDir = settingsManager.ImagesInferenceDirectory;
defaultOutputDir.Create();
- return WriteOutputImageAsync(
- imageStream,
- defaultOutputDir,
- args,
- batchNum,
- batchTotal,
- isGrid
- );
+ return WriteOutputImageAsync(imageStream, defaultOutputDir, args, batchNum, batchTotal, isGrid, fileExtension);
}
///
@@ -117,7 +110,8 @@ public abstract partial class InferenceGenerationViewModelBase
ImageGenerationEventArgs args,
int batchNum = 0,
int batchTotal = 0,
- bool isGrid = false
+ bool isGrid = false,
+ string fileExtension = "png"
)
{
var formatTemplateStr = settingsManager.Settings.InferenceOutputImageFileNameFormat;
@@ -136,10 +130,7 @@ public abstract partial class InferenceGenerationViewModelBase
)
{
// Fallback to default
- Logger.Warn(
- "Failed to parse format template: {FormatTemplate}, using default",
- formatTemplateStr
- );
+ Logger.Warn("Failed to parse format template: {FormatTemplate}, using default", formatTemplateStr);
format = FileNameFormat.Parse(FileNameFormat.DefaultTemplate, formatProvider);
}
@@ -155,7 +146,7 @@ public abstract partial class InferenceGenerationViewModelBase
}
var fileName = format.GetFileName();
- var file = outputDir.JoinFile($"{fileName}.png");
+ var file = outputDir.JoinFile($"{fileName}.{fileExtension}");
// Until the file is free, keep adding _{i} to the end
for (var i = 0; i < 100; i++)
@@ -163,14 +154,14 @@ public abstract partial class InferenceGenerationViewModelBase
if (!file.Exists)
break;
- file = outputDir.JoinFile($"{fileName}_{i + 1}.png");
+ file = outputDir.JoinFile($"{fileName}_{i + 1}.{fileExtension}");
}
// If that fails, append an 7-char uuid
if (file.Exists)
{
var uuid = Guid.NewGuid().ToString("N")[..7];
- file = outputDir.JoinFile($"{fileName}_{uuid}.png");
+ file = outputDir.JoinFile($"{fileName}_{uuid}.{fileExtension}");
}
await using var fileStream = file.Info.OpenWrite();
@@ -200,11 +191,7 @@ public abstract partial class InferenceGenerationViewModelBase
{
var uploadName = await image.GetHashGuidFileNameAsync();
- Logger.Debug(
- "Uploading image {FileName} as {UploadName}",
- localFile.Name,
- uploadName
- );
+ Logger.Debug("Uploading image {FileName} as {UploadName}", localFile.Name, uploadName);
// For pngs, strip metadata since Pillow can't handle some valid files?
if (localFile.Info.Extension.Equals(".png", StringComparison.OrdinalIgnoreCase))
@@ -228,10 +215,7 @@ public abstract partial class InferenceGenerationViewModelBase
/// Runs a generation task
///
/// Thrown if args.Parameters or args.Project are null
- protected async Task RunGeneration(
- ImageGenerationEventArgs args,
- CancellationToken cancellationToken
- )
+ protected async Task RunGeneration(ImageGenerationEventArgs args, CancellationToken cancellationToken)
{
var client = args.Client;
var nodes = args.Nodes;
@@ -311,32 +295,18 @@ public abstract partial class InferenceGenerationViewModelBase
{
Logger.Warn(e, "Comfy node exception while queuing prompt");
await DialogHelper
- .CreateJsonDialog(
- e.JsonData,
- "Comfy Error",
- "Node execution encountered an error"
- )
+ .CreateJsonDialog(e.JsonData, "Comfy Error", "Node execution encountered an error")
.ShowAsync();
return;
}
// Get output images
- var imageOutputs = await client.GetImagesForExecutedPromptAsync(
- promptTask.Id,
- cancellationToken
- );
-
- if (
- !imageOutputs.TryGetValue(args.OutputNodeNames[0], out var images)
- || images is not { Count: > 0 }
- )
+ var imageOutputs = await client.GetImagesForExecutedPromptAsync(promptTask.Id, cancellationToken);
+
+ if (!imageOutputs.TryGetValue(args.OutputNodeNames[0], out var images) || images is not { Count: > 0 })
{
// No images match
- notificationService.Show(
- "No output",
- "Did not receive any output images",
- NotificationType.Warning
- );
+ notificationService.Show("No output", "Did not receive any output images", NotificationType.Warning);
return;
}
@@ -369,10 +339,7 @@ public abstract partial class InferenceGenerationViewModelBase
///
/// Handles image output metadata for generation runs
///
- private async Task ProcessOutputImages(
- IReadOnlyCollection images,
- ImageGenerationEventArgs args
- )
+ private async Task ProcessOutputImages(IReadOnlyCollection images, ImageGenerationEventArgs args)
{
var client = args.Client;
@@ -395,10 +362,7 @@ public abstract partial class InferenceGenerationViewModelBase
var project = args.Project!;
// Lock seed
- project.TryUpdateModel(
- "Seed",
- model => model with { IsRandomizeEnabled = false }
- );
+ project.TryUpdateModel("Seed", model => model with { IsRandomizeEnabled = false });
// Seed and batch override for batches
if (images.Count > 1 && project.ProjectType is InferenceProjectType.TextToImage)
@@ -433,6 +397,29 @@ public abstract partial class InferenceGenerationViewModelBase
outputImages.Add(new ImageSource(filePath));
EventManager.Instance.OnImageFileAdded(filePath);
}
+ else if (comfyImage.FileName.EndsWith(".webp"))
+ {
+ // Write using generated name
+ var webpFilePath = await WriteOutputImageAsync(
+ new MemoryStream(imageArray),
+ args,
+ i + 1,
+ images.Count,
+ fileExtension: Path.GetExtension(comfyImage.FileName).Replace(".", "")
+ );
+
+ // convert to gif
+ await GifConverter.ConvertWebpToGif(webpFilePath);
+ var gifFilePath = webpFilePath.ToString().Replace(".webp", ".gif");
+ if (File.Exists(gifFilePath))
+ {
+ // delete webp
+ File.Delete(webpFilePath);
+ }
+
+ outputImages.Add(new ImageSource(gifFilePath));
+ EventManager.Instance.OnImageFileAdded(gifFilePath);
+ }
else
{
// Write using generated name
@@ -440,7 +427,8 @@ public abstract partial class InferenceGenerationViewModelBase
new MemoryStream(imageArray),
args,
i + 1,
- images.Count
+ images.Count,
+ fileExtension: Path.GetExtension(comfyImage.FileName).Replace(".", "")
);
outputImages.Add(new ImageSource(filePath));
@@ -456,25 +444,14 @@ public abstract partial class InferenceGenerationViewModelBase
var project = args.Project!;
// Lock seed
- project.TryUpdateModel(
- "Seed",
- model => model with { IsRandomizeEnabled = false }
- );
+ project.TryUpdateModel("Seed", model => model with { IsRandomizeEnabled = false });
var grid = ImageProcessor.CreateImageGrid(loadedImages);
var gridBytes = grid.Encode().ToArray();
- var gridBytesWithMetadata = PngDataHelper.AddMetadata(
- gridBytes,
- args.Parameters!,
- args.Project!
- );
+ var gridBytesWithMetadata = PngDataHelper.AddMetadata(gridBytes, args.Parameters!, args.Project!);
// Save to disk
- var gridPath = await WriteOutputImageAsync(
- new MemoryStream(gridBytesWithMetadata),
- args,
- isGrid: true
- );
+ var gridPath = await WriteOutputImageAsync(new MemoryStream(gridBytesWithMetadata), args, isGrid: true);
// Insert to start of images
var gridImage = new ImageSource(gridPath);
@@ -497,10 +474,7 @@ public abstract partial class InferenceGenerationViewModelBase
///
/// Implementation for Generate Image
///
- protected virtual Task GenerateImageImpl(
- GenerateOverrides overrides,
- CancellationToken cancellationToken
- )
+ protected virtual Task GenerateImageImpl(GenerateOverrides overrides, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
@@ -511,10 +485,7 @@ public abstract partial class InferenceGenerationViewModelBase
/// Optional overrides (side buttons)
/// Cancellation token
[RelayCommand(IncludeCancelCommand = true, FlowExceptionsToTaskScheduler = true)]
- private async Task GenerateImage(
- GenerateFlags options = default,
- CancellationToken cancellationToken = default
- )
+ private async Task GenerateImage(GenerateFlags options = default, CancellationToken cancellationToken = default)
{
var overrides = GenerateOverrides.FromFlags(options);
@@ -555,21 +526,19 @@ public abstract partial class InferenceGenerationViewModelBase
/// Handles the progress update received event from the websocket.
/// Updates the progress view model.
///
- protected virtual void OnProgressUpdateReceived(
- object? sender,
- ComfyProgressUpdateEventArgs args
- )
+ protected virtual void OnProgressUpdateReceived(object? sender, ComfyProgressUpdateEventArgs args)
{
- Dispatcher.UIThread.Post(() =>
- {
- OutputProgress.Value = args.Value;
- OutputProgress.Maximum = args.Maximum;
- OutputProgress.IsIndeterminate = false;
+ Dispatcher
+ .UIThread
+ .Post(() =>
+ {
+ OutputProgress.Value = args.Value;
+ OutputProgress.Maximum = args.Maximum;
+ OutputProgress.IsIndeterminate = false;
- OutputProgress.Text =
- $"({args.Value} / {args.Maximum})"
- + (args.RunningNode != null ? $" {args.RunningNode}" : "");
- });
+ OutputProgress.Text =
+ $"({args.Value} / {args.Maximum})" + (args.RunningNode != null ? $" {args.RunningNode}" : "");
+ });
}
private void AttachRunningNodeChangedHandler(ComfyTask comfyTask)
@@ -594,13 +563,15 @@ public abstract partial class InferenceGenerationViewModelBase
return;
}
- Dispatcher.UIThread.Post(() =>
- {
- OutputProgress.IsIndeterminate = true;
- OutputProgress.Value = 100;
- OutputProgress.Maximum = 100;
- OutputProgress.Text = nodeName;
- });
+ Dispatcher
+ .UIThread
+ .Post(() =>
+ {
+ OutputProgress.IsIndeterminate = true;
+ OutputProgress.Value = 100;
+ OutputProgress.Maximum = 100;
+ OutputProgress.Text = nodeName;
+ });
}
public class ImageGenerationEventArgs : EventArgs
@@ -628,11 +599,7 @@ public abstract partial class InferenceGenerationViewModelBase
overrides[typeof(HiresFixModule)] = args.Overrides.IsHiresFixEnabled.Value;
}
- return new ModuleApplyStepEventArgs
- {
- Builder = args.Builder,
- IsEnabledOverrides = overrides
- };
+ return new ModuleApplyStepEventArgs { Builder = args.Builder, IsEnabledOverrides = overrides };
}
}
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs
index 965b787f..fdd9a520 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Base/LoadableViewModelBase.cs
@@ -28,24 +28,16 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
- private static readonly Type[] SerializerIgnoredTypes =
- {
- typeof(ICommand),
- typeof(IRelayCommand)
- };
+ private static readonly Type[] SerializerIgnoredTypes = { typeof(ICommand), typeof(IRelayCommand) };
private static readonly string[] SerializerIgnoredNames = { nameof(HasErrors) };
- private static readonly JsonSerializerOptions SerializerOptions =
- new() { IgnoreReadOnlyProperties = true };
+ private static readonly JsonSerializerOptions SerializerOptions = new() { IgnoreReadOnlyProperties = true };
private static bool ShouldIgnoreProperty(PropertyInfo property)
{
// Skip if read-only and not IJsonLoadableState
- if (
- property.SetMethod is null
- && !typeof(IJsonLoadableState).IsAssignableFrom(property.PropertyType)
- )
+ if (property.SetMethod is null && !typeof(IJsonLoadableState).IsAssignableFrom(property.PropertyType))
{
Logger.ConditionalTrace("Skipping {Property} - read-only", property.Name);
return true;
@@ -107,11 +99,7 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState
{
// Get all of our properties using reflection
var properties = GetType().GetProperties();
- Logger.ConditionalTrace(
- "Serializing {Type} with {Count} properties",
- GetType(),
- properties.Length
- );
+ Logger.ConditionalTrace("Serializing {Type} with {Count} properties", GetType(), properties.Length);
foreach (var property in properties)
{
@@ -119,9 +107,7 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState
// If JsonPropertyName provided, use that as the key
if (
- property
- .GetCustomAttributes(typeof(JsonPropertyNameAttribute), true)
- .FirstOrDefault()
+ property.GetCustomAttributes(typeof(JsonPropertyNameAttribute), true).FirstOrDefault()
is JsonPropertyNameAttribute jsonPropertyName
)
{
@@ -168,10 +154,7 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState
if (property.GetValue(this) is not IJsonLoadableState propertyValue)
{
// If null, it must have a default constructor
- if (
- property.PropertyType.GetConstructor(Type.EmptyTypes)
- is not { } constructorInfo
- )
+ if (property.PropertyType.GetConstructor(Type.EmptyTypes) is not { } constructorInfo)
{
throw new InvalidOperationException(
$"Property {property.Name} is IJsonLoadableState but current object is null and has no default constructor"
@@ -188,11 +171,7 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState
}
else
{
- Logger.ConditionalTrace(
- "Loading {Property} ({Type})",
- property.Name,
- property.PropertyType
- );
+ Logger.ConditionalTrace("Loading {Property} ({Type})", property.Name, property.PropertyType);
var propertyValue = value.Deserialize(property.PropertyType, SerializerOptions);
property.SetValue(this, propertyValue);
@@ -216,11 +195,7 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState
{
// Get all of our properties using reflection.
var properties = GetType().GetProperties();
- Logger.ConditionalTrace(
- "Serializing {Type} with {Count} properties",
- GetType(),
- properties.Length
- );
+ Logger.ConditionalTrace("Serializing {Type} with {Count} properties", GetType(), properties.Length);
// Create a JSON object to store the state.
var state = new JsonObject();
@@ -237,9 +212,7 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState
// If JsonPropertyName provided, use that as the key.
if (
- property
- .GetCustomAttributes(typeof(JsonPropertyNameAttribute), true)
- .FirstOrDefault()
+ property.GetCustomAttributes(typeof(JsonPropertyNameAttribute), true).FirstOrDefault()
is JsonPropertyNameAttribute jsonPropertyName
)
{
@@ -270,11 +243,7 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState
}
else
{
- Logger.ConditionalTrace(
- "Serializing {Property} ({Type})",
- property.Name,
- property.PropertyType
- );
+ Logger.ConditionalTrace("Serializing {Property} ({Type})", property.Name, property.PropertyType);
var value = property.GetValue(this);
if (value is not null)
{
@@ -297,8 +266,7 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState
protected static JsonObject SerializeModel(T model)
{
var node = JsonSerializer.SerializeToNode(model);
- return node?.AsObject()
- ?? throw new NullReferenceException("Failed to serialize state to JSON object.");
+ return node?.AsObject() ?? throw new NullReferenceException("Failed to serialize state to JSON object.");
}
///
diff --git a/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs
index 34253d7b..f6893400 100644
--- a/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/ConsoleViewModel.cs
@@ -7,9 +7,9 @@ using System.Threading.Tasks.Dataflow;
using Avalonia.Threading;
using AvaloniaEdit.Document;
using CommunityToolkit.Mvvm.ComponentModel;
+using NLog;
using Nito.AsyncEx;
using Nito.AsyncEx.Synchronous;
-using NLog;
using StabilityMatrix.Core.Extensions;
using StabilityMatrix.Core.Processes;
diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs
index 5cab55c2..8a5dae66 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs
@@ -126,10 +126,7 @@ public partial class UpdateViewModel : ContentDialogViewModelBase
ShowProgressBar = true;
IsProgressIndeterminate = true;
- UpdateText = string.Format(
- Resources.TextTemplate_UpdatingPackage,
- Resources.Label_StabilityMatrix
- );
+ UpdateText = string.Format(Resources.TextTemplate_UpdatingPackage, Resources.Label_StabilityMatrix);
try
{
@@ -173,10 +170,7 @@ public partial class UpdateViewModel : ContentDialogViewModelBase
UpdateText = "Getting a few things ready...";
await using (new MinimumDelay(500, 1000))
{
- Process.Start(
- UpdateHelper.ExecutablePath,
- $"--wait-for-exit-pid {Environment.ProcessId}"
- );
+ Process.Start(UpdateHelper.ExecutablePath, $"--wait-for-exit-pid {Environment.ProcessId}");
}
UpdateText = "Update complete. Restarting Stability Matrix in 3 seconds...";
@@ -189,7 +183,7 @@ public partial class UpdateViewModel : ContentDialogViewModelBase
App.Shutdown();
}
-
+
internal async Task GetReleaseNotes(string changelogUrl)
{
using var client = httpClientFactory.CreateClient();
@@ -262,15 +256,10 @@ public partial class UpdateViewModel : ContentDialogViewModelBase
// Join all blocks until and excluding the current version
// If we're on a pre-release, include the current release
- var currentVersionBlock = results.FindIndex(
- x => x.Version == currentVersion.WithoutMetadata()
- );
+ var currentVersionBlock = results.FindIndex(x => x.Version == currentVersion.WithoutMetadata());
// For mismatching build metadata, add one
- if (
- currentVersionBlock != -1
- && results[currentVersionBlock].Version?.Metadata != currentVersion.Metadata
- )
+ if (currentVersionBlock != -1 && results[currentVersionBlock].Version?.Metadata != currentVersion.Metadata)
{
currentVersionBlock++;
}
@@ -278,9 +267,7 @@ public partial class UpdateViewModel : ContentDialogViewModelBase
// Support for previous pre-release without changelogs
if (currentVersionBlock == -1)
{
- currentVersionBlock = results.FindIndex(
- x => x.Version == currentVersion.WithoutPrereleaseOrMetadata()
- );
+ currentVersionBlock = results.FindIndex(x => x.Version == currentVersion.WithoutPrereleaseOrMetadata());
// Add 1 if found to include the current release
if (currentVersionBlock != -1)
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs
index 3a6c5f5d..13183691 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs
@@ -7,18 +7,20 @@ using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
using NLog;
-using StabilityMatrix.Avalonia.Extensions;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.Models.Inference;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
-using StabilityMatrix.Avalonia.ViewModels.Inference.Modules;
using StabilityMatrix.Avalonia.ViewModels.Inference.Video;
using StabilityMatrix.Avalonia.Views.Inference;
using StabilityMatrix.Core.Attributes;
+using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models;
+using StabilityMatrix.Core.Models.Api.Comfy;
using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
+using StabilityMatrix.Core.Models.FileInterfaces;
using StabilityMatrix.Core.Services;
#pragma warning disable CS0657 // Not a valid attribute location for this declaration
@@ -28,9 +30,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Inference;
[View(typeof(InferenceImageToVideoView), persistent: true)]
[ManagedService]
[Transient]
-public class InferenceImageToVideoViewModel
- : InferenceGenerationViewModelBase,
- IParametersLoadableState
+public partial class InferenceImageToVideoViewModel : InferenceGenerationViewModelBase, IParametersLoadableState
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
@@ -61,6 +61,10 @@ public class InferenceImageToVideoViewModel
[JsonPropertyName("VideoOutput")]
public VideoOutputSettingsCardViewModel VideoOutputSettingsCardViewModel { get; }
+ [ObservableProperty]
+ [JsonIgnore]
+ private string outputUri;
+
public InferenceImageToVideoViewModel(
INotificationService notificationService,
IInferenceClientManager inferenceClientManager,
@@ -86,6 +90,10 @@ public class InferenceImageToVideoViewModel
samplerCard.IsCfgScaleEnabled = true;
samplerCard.IsSamplerSelectionEnabled = true;
samplerCard.IsSchedulerSelectionEnabled = true;
+ samplerCard.CfgScale = 2.5d;
+ samplerCard.SelectedSampler = ComfySampler.Euler;
+ samplerCard.SelectedScheduler = ComfyScheduler.Karras;
+ samplerCard.IsDenoiseStrengthEnabled = true;
});
BatchSizeCardViewModel = vmFactory.Get();
@@ -105,6 +113,19 @@ public class InferenceImageToVideoViewModel
);
}
+ public override void OnLoaded()
+ {
+ EventManager.Instance.ImageFileAdded += OnImageFileAdded;
+ }
+
+ private void OnImageFileAdded(object? sender, FilePath e)
+ {
+ if (!e.Extension.Contains("gif"))
+ return;
+
+ OutputUri = e;
+ }
+
///
protected override void BuildPrompt(BuildPromptEventArgs args)
{
@@ -122,19 +143,19 @@ public class InferenceImageToVideoViewModel
ModelCardViewModel.ApplyStep(args);
// Setup latent from image
- var imageLoad = builder.Nodes.AddTypedNode(
- new ComfyNodeBuilder.LoadImage
- {
- Name = builder.Nodes.GetUniqueName("ControlNet_LoadImage"),
- Image =
- SelectImageCardViewModel.ImageSource?.GetHashGuidFileNameCached("Inference")
- ?? throw new ValidationException()
- }
- );
+ var imageLoad = builder
+ .Nodes
+ .AddTypedNode(
+ new ComfyNodeBuilder.LoadImage
+ {
+ Name = builder.Nodes.GetUniqueName("ControlNet_LoadImage"),
+ Image =
+ SelectImageCardViewModel.ImageSource?.GetHashGuidFileNameCached("Inference")
+ ?? throw new ValidationException()
+ }
+ );
builder.Connections.Primary = imageLoad.Output1;
- builder.Connections.PrimarySize =
- SelectImageCardViewModel.CurrentBitmapSize
- ?? new Size(SamplerCardViewModel.Width, SamplerCardViewModel.Height);
+ builder.Connections.PrimarySize = SelectImageCardViewModel.CurrentBitmapSize;
// Setup img2vid stuff
// Set width & height from SamplerCard
@@ -159,10 +180,7 @@ public class InferenceImageToVideoViewModel
}
///
- protected override async Task GenerateImageImpl(
- GenerateOverrides overrides,
- CancellationToken cancellationToken
- )
+ protected override async Task GenerateImageImpl(GenerateOverrides overrides, CancellationToken cancellationToken)
{
if (!await CheckClientConnectedWithPrompt() || !ClientManager.IsConnected)
{
@@ -184,11 +202,7 @@ public class InferenceImageToVideoViewModel
{
var seed = seedCard.Seed + i;
- var buildPromptArgs = new BuildPromptEventArgs
- {
- Overrides = overrides,
- SeedOverride = seed
- };
+ var buildPromptArgs = new BuildPromptEventArgs { Overrides = overrides, SeedOverride = seed };
BuildPrompt(buildPromptArgs);
var generationArgs = new ImageGenerationEventArgs
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageUpscaleViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageUpscaleViewModel.cs
index 4531d1b0..2ca1dbd8 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageUpscaleViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageUpscaleViewModel.cs
@@ -107,9 +107,7 @@ public class InferenceImageUpscaleViewModel : InferenceGenerationViewModelBase
// If upscale is enabled, add another upscale group
if (IsUpscaleEnabled)
{
- var upscaleSize = builder.Connections.PrimarySize.WithScale(
- UpscalerCardViewModel.Scale
- );
+ var upscaleSize = builder.Connections.PrimarySize.WithScale(UpscalerCardViewModel.Scale);
// Build group
builder.Connections.Primary = builder
@@ -144,10 +142,7 @@ public class InferenceImageUpscaleViewModel : InferenceGenerationViewModelBase
}
///
- protected override async Task GenerateImageImpl(
- GenerateOverrides overrides,
- CancellationToken cancellationToken
- )
+ protected override async Task GenerateImageImpl(GenerateOverrides overrides, CancellationToken cancellationToken)
{
if (!ClientManager.IsConnected)
{
@@ -174,10 +169,7 @@ public class InferenceImageUpscaleViewModel : InferenceGenerationViewModelBase
Client = ClientManager.Client,
Nodes = buildPromptArgs.Builder.ToNodeDictionary(),
OutputNodeNames = buildPromptArgs.Builder.Connections.OutputNodeNames.ToArray(),
- Parameters = new GenerationParameters
- {
- ModelName = UpscalerCardViewModel.SelectedUpscaler?.Name,
- },
+ Parameters = new GenerationParameters { ModelName = UpscalerCardViewModel.SelectedUpscaler?.Name, },
Project = InferenceProjectDocument.FromLoadable(this)
};
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
index 31ce9843..764f7a07 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
@@ -26,9 +26,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Inference;
[View(typeof(InferenceTextToImageView), IsPersistent = true)]
[ManagedService]
[Transient]
-public class InferenceTextToImageViewModel
- : InferenceGenerationViewModelBase,
- IParametersLoadableState
+public class InferenceTextToImageViewModel : InferenceGenerationViewModelBase, IParametersLoadableState
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
@@ -162,22 +160,19 @@ public class InferenceTextToImageViewModel
///
protected override IEnumerable GetInputImages()
{
- var samplerImages = SamplerCardViewModel.ModulesCardViewModel.Cards
+ var samplerImages = SamplerCardViewModel
+ .ModulesCardViewModel
+ .Cards
.OfType()
.SelectMany(m => m.GetInputImages());
- var moduleImages = ModulesCardViewModel.Cards
- .OfType()
- .SelectMany(m => m.GetInputImages());
+ var moduleImages = ModulesCardViewModel.Cards.OfType().SelectMany(m => m.GetInputImages());
return samplerImages.Concat(moduleImages);
}
///
- protected override async Task GenerateImageImpl(
- GenerateOverrides overrides,
- CancellationToken cancellationToken
- )
+ protected override async Task GenerateImageImpl(GenerateOverrides overrides, CancellationToken cancellationToken)
{
// Validate the prompts
if (!await PromptCardViewModel.ValidatePrompts())
@@ -205,11 +200,7 @@ public class InferenceTextToImageViewModel
{
var seed = seedCard.Seed + i;
- var buildPromptArgs = new BuildPromptEventArgs
- {
- Overrides = overrides,
- SeedOverride = seed
- };
+ var buildPromptArgs = new BuildPromptEventArgs { Overrides = overrides, SeedOverride = seed };
BuildPrompt(buildPromptArgs);
var generationArgs = new ImageGenerationEventArgs
@@ -270,16 +261,12 @@ public class InferenceTextToImageViewModel
if (state.TryGetPropertyValue("HiresSampler", out var hiresSamplerState))
{
- module
- .GetCard()
- .LoadStateFromJsonObject(hiresSamplerState!.AsObject());
+ module.GetCard().LoadStateFromJsonObject(hiresSamplerState!.AsObject());
}
if (state.TryGetPropertyValue("HiresUpscaler", out var hiresUpscalerState))
{
- module
- .GetCard()
- .LoadStateFromJsonObject(hiresUpscalerState!.AsObject());
+ module.GetCard().LoadStateFromJsonObject(hiresUpscalerState!.AsObject());
}
});
@@ -289,17 +276,17 @@ public class InferenceTextToImageViewModel
if (state.TryGetPropertyValue("Upscaler", out var upscalerState))
{
- module
- .GetCard()
- .LoadStateFromJsonObject(upscalerState!.AsObject());
+ module.GetCard().LoadStateFromJsonObject(upscalerState!.AsObject());
}
});
// Add FreeU to sampler
- SamplerCardViewModel.ModulesCardViewModel.AddModule(module =>
- {
- module.IsEnabled = state.GetPropertyValueOrDefault("IsFreeUEnabled");
- });
+ SamplerCardViewModel
+ .ModulesCardViewModel
+ .AddModule(module =>
+ {
+ module.IsEnabled = state.GetPropertyValueOrDefault("IsFreeUEnabled");
+ });
}
base.LoadStateFromJsonObject(state);
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs
index 51a99498..2a4f652f 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs
@@ -10,8 +10,8 @@ using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Models;
-using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes;
+using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
namespace StabilityMatrix.Avalonia.ViewModels.Inference;
@@ -42,6 +42,7 @@ public partial class ModelCardViewModel(IInferenceClientManager clientManager)
private bool disableSettings;
public IInferenceClientManager ClientManager { get; } = clientManager;
+
///
public virtual void ApplyStep(ModuleApplyStepEventArgs e)
{
@@ -50,9 +51,7 @@ public partial class ModelCardViewModel(IInferenceClientManager clientManager)
new ComfyNodeBuilder.CheckpointLoaderSimple
{
Name = "CheckpointLoader",
- CkptName =
- SelectedModel?.RelativePath
- ?? throw new ValidationException("Model not selected")
+ CkptName = SelectedModel?.RelativePath ?? throw new ValidationException("Model not selected")
}
);
@@ -85,9 +84,7 @@ public partial class ModelCardViewModel(IInferenceClientManager clientManager)
new ComfyNodeBuilder.VAELoader
{
Name = "VAELoader",
- VaeName =
- SelectedVae?.RelativePath
- ?? throw new ValidationException("VAE enabled but not selected")
+ VaeName = SelectedVae?.RelativePath ?? throw new ValidationException("VAE enabled but not selected")
}
);
@@ -147,19 +144,14 @@ public partial class ModelCardViewModel(IInferenceClientManager clientManager)
model = currentModels.FirstOrDefault(
m =>
m.Local?.ConnectedModelInfo?.Hashes.SHA256 is { } sha256
- && sha256.StartsWith(
- parameters.ModelHash,
- StringComparison.InvariantCultureIgnoreCase
- )
+ && sha256.StartsWith(parameters.ModelHash, StringComparison.InvariantCultureIgnoreCase)
);
}
else
{
// Name matches
model = currentModels.FirstOrDefault(m => m.RelativePath.EndsWith(paramsModelName));
- model ??= currentModels.FirstOrDefault(
- m => m.ShortDisplayName.StartsWith(paramsModelName)
- );
+ model ??= currentModels.FirstOrDefault(m => m.ShortDisplayName.StartsWith(paramsModelName));
}
if (model is not null)
diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs
index 4f4e7191..2433debc 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs
@@ -42,9 +42,8 @@ public class ControlNetModule : ModuleBase
{
Name = e.Nodes.GetUniqueName("ControlNet_LoadImage"),
Image =
- card.SelectImageCardViewModel.ImageSource?.GetHashGuidFileNameCached(
- "Inference"
- ) ?? throw new ValidationException("No ImageSource")
+ card.SelectImageCardViewModel.ImageSource?.GetHashGuidFileNameCached("Inference")
+ ?? throw new ValidationException("No ImageSource")
}
);
@@ -52,9 +51,7 @@ public class ControlNetModule : ModuleBase
new ComfyNodeBuilder.ControlNetLoader
{
Name = e.Nodes.GetUniqueName("ControlNetLoader"),
- ControlNetName =
- card.SelectedModel?.FileName
- ?? throw new ValidationException("No SelectedModel"),
+ ControlNetName = card.SelectedModel?.FileName ?? throw new ValidationException("No SelectedModel"),
}
);
@@ -64,10 +61,8 @@ public class ControlNetModule : ModuleBase
Name = e.Nodes.GetUniqueName("ControlNetApply"),
Image = imageLoad.Output1,
ControlNet = controlNetLoader.Output,
- Positive =
- e.Temp.Conditioning?.Positive ?? throw new ArgumentException("No Conditioning"),
- Negative =
- e.Temp.Conditioning?.Negative ?? throw new ArgumentException("No Conditioning"),
+ Positive = e.Temp.Conditioning?.Positive ?? throw new ArgumentException("No Conditioning"),
+ Negative = e.Temp.Conditioning?.Negative ?? throw new ArgumentException("No Conditioning"),
Strength = card.Strength,
StartPercent = card.StartPercent,
EndPercent = card.EndPercent,
@@ -93,10 +88,7 @@ public class ControlNetModule : ModuleBase
}
);
- e.Temp.RefinerConditioning = (
- controlNetRefinerApply.Output1,
- controlNetRefinerApply.Output2
- );
+ e.Temp.RefinerConditioning = (controlNetRefinerApply.Output1, controlNetRefinerApply.Output2);
}
}
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
index c1c66a72..912a34f1 100644
--- a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs
@@ -54,11 +54,9 @@ public partial class OutputsPageViewModel : PageViewModelBase
private readonly ILogger logger;
public override string Title => Resources.Label_OutputsPageTitle;
- public override IconSource IconSource =>
- new SymbolIconSource { Symbol = Symbol.Grid, IsFilled = true };
+ public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Grid, IsFilled = true };
- public SourceCache OutputsCache { get; } =
- new(file => file.AbsolutePath);
+ public SourceCache OutputsCache { get; } = new(file => file.AbsolutePath);
public IObservableCollection Outputs { get; set; } =
new ObservableCollectionExtended();
@@ -88,8 +86,7 @@ public partial class OutputsPageViewModel : PageViewModelBase
[ObservableProperty]
private bool isConsolidating;
- public bool CanShowOutputTypes =>
- SelectedCategory?.Name?.Equals("Shared Output Folder") ?? false;
+ public bool CanShowOutputTypes => SelectedCategory?.Name?.Equals("Shared Output Folder") ?? false;
public string NumImagesSelected =>
NumItemsSelected == 1
@@ -163,10 +160,7 @@ public partial class OutputsPageViewModel : PageViewModelBase
GetOutputs(path);
}
- partial void OnSelectedCategoryChanged(
- PackageOutputCategory? oldValue,
- PackageOutputCategory? newValue
- )
+ partial void OnSelectedCategoryChanged(PackageOutputCategory? oldValue, PackageOutputCategory? newValue)
{
if (oldValue == newValue || newValue == null)
return;
@@ -217,13 +211,11 @@ public partial class OutputsPageViewModel : PageViewModelBase
var vm = new ImageViewerViewModel { ImageSource = image, LocalImageFile = item.ImageFile };
using var onNext = Observable
- .FromEventPattern(
- vm,
- nameof(ImageViewerViewModel.NavigationRequested)
- )
+ .FromEventPattern(vm, nameof(ImageViewerViewModel.NavigationRequested))
.Subscribe(ctx =>
{
- Dispatcher.UIThread
+ Dispatcher
+ .UIThread
.InvokeAsync(async () =>
{
var sender = (ImageViewerViewModel)ctx.Sender!;
@@ -232,9 +224,7 @@ public partial class OutputsPageViewModel : PageViewModelBase
if (newIndex >= 0 && newIndex < Outputs.Count)
{
var newImage = Outputs[newIndex];
- var newImageSource = new ImageSource(
- new FilePath(newImage.ImageFile.AbsolutePath)
- );
+ var newImageSource = new ImageSource(new FilePath(newImage.ImageFile.AbsolutePath));
// Preload
await newImageSource.GetBitmapAsync();
@@ -386,14 +376,16 @@ public partial class OutputsPageViewModel : PageViewModelBase
public async Task ConsolidateImages()
{
var stackPanel = new StackPanel();
- stackPanel.Children.Add(
- new TextBlock
- {
- Text = Resources.Label_ConsolidateExplanation,
- TextWrapping = TextWrapping.Wrap,
- Margin = new Thickness(0, 8, 0, 16)
- }
- );
+ stackPanel
+ .Children
+ .Add(
+ new TextBlock
+ {
+ Text = Resources.Label_ConsolidateExplanation,
+ TextWrapping = TextWrapping.Wrap,
+ Margin = new Thickness(0, 8, 0, 16)
+ }
+ );
foreach (var category in Categories)
{
if (category.Name == "Shared Output Folder")
@@ -401,15 +393,17 @@ public partial class OutputsPageViewModel : PageViewModelBase
continue;
}
- stackPanel.Children.Add(
- new CheckBox
- {
- Content = $"{category.Name} ({category.Path})",
- IsChecked = true,
- Margin = new Thickness(0, 8, 0, 0),
- Tag = category.Path
- }
- );
+ stackPanel
+ .Children
+ .Add(
+ new CheckBox
+ {
+ Content = $"{category.Name} ({category.Path})",
+ IsChecked = true,
+ Margin = new Thickness(0, 8, 0, 0),
+ Tag = category.Path
+ }
+ );
}
var confirmationDialog = new BetterContentDialog
@@ -430,25 +424,14 @@ public partial class OutputsPageViewModel : PageViewModelBase
Directory.CreateDirectory(settingsManager.ConsolidatedImagesDirectory);
- foreach (
- var category in stackPanel.Children.OfType().Where(c => c.IsChecked == true)
- )
+ foreach (var category in stackPanel.Children.OfType().Where(c => c.IsChecked == true))
{
- if (
- string.IsNullOrWhiteSpace(category.Tag?.ToString())
- || !Directory.Exists(category.Tag?.ToString())
- )
+ if (string.IsNullOrWhiteSpace(category.Tag?.ToString()) || !Directory.Exists(category.Tag?.ToString()))
continue;
var directory = category.Tag.ToString();
- foreach (
- var path in Directory.EnumerateFiles(
- directory,
- "*.png",
- SearchOption.AllDirectories
- )
- )
+ foreach (var path in Directory.EnumerateFiles(directory, "*.png", SearchOption.AllDirectories))
{
try
{
@@ -499,10 +482,7 @@ public partial class OutputsPageViewModel : PageViewModelBase
if (
!Directory.Exists(directory)
- && (
- SelectedCategory.Path != settingsManager.ImagesDirectory
- || SelectedOutputType != SharedOutputType.All
- )
+ && (SelectedCategory.Path != settingsManager.ImagesDirectory || SelectedOutputType != SharedOutputType.All)
)
{
Directory.CreateDirectory(directory);
@@ -534,23 +514,18 @@ public partial class OutputsPageViewModel : PageViewModelBase
var previouslySelectedCategory = SelectedCategory;
- var packageCategories = settingsManager.Settings.InstalledPackages
+ var packageCategories = settingsManager
+ .Settings
+ .InstalledPackages
.Where(x => !x.UseSharedOutputFolder)
.Select(packageFactory.GetPackagePair)
.WhereNotNull()
- .Where(
- p =>
- p.BasePackage.SharedOutputFolders != null
- && p.BasePackage.SharedOutputFolders.Any()
- )
+ .Where(p => p.BasePackage.SharedOutputFolders != null && p.BasePackage.SharedOutputFolders.Any())
.Select(
pair =>
new PackageOutputCategory
{
- Path = Path.Combine(
- pair.InstalledPackage.FullPath!,
- pair.BasePackage.OutputFolderName
- ),
+ Path = Path.Combine(pair.InstalledPackage.FullPath!, pair.BasePackage.OutputFolderName),
Name = pair.InstalledPackage.DisplayName ?? ""
}
)
@@ -558,25 +533,16 @@ public partial class OutputsPageViewModel : PageViewModelBase
packageCategories.Insert(
0,
- new PackageOutputCategory
- {
- Path = settingsManager.ImagesDirectory,
- Name = "Shared Output Folder"
- }
+ new PackageOutputCategory { Path = settingsManager.ImagesDirectory, Name = "Shared Output Folder" }
);
packageCategories.Insert(
1,
- new PackageOutputCategory
- {
- Path = settingsManager.ImagesInferenceDirectory,
- Name = "Inference"
- }
+ new PackageOutputCategory { Path = settingsManager.ImagesInferenceDirectory, Name = "Inference" }
);
Categories = new ObservableCollection(packageCategories);
SelectedCategory =
- Categories.FirstOrDefault(x => x.Name == previouslySelectedCategory?.Name)
- ?? Categories.First();
+ Categories.FirstOrDefault(x => x.Name == previouslySelectedCategory?.Name) ?? Categories.First();
}
}
diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs
index f88d17f7..6f3c3c4c 100644
--- a/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs
+++ b/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs
@@ -169,7 +169,7 @@ public partial class InferenceSettingsViewModel : PageViewModelBase
var files = await storage.OpenFilePickerAsync(
new FilePickerOpenOptions
{
- FileTypeFilter = new List { new("CSV") { Patterns = ["*.csv"] } }
+ FileTypeFilter = new List { new("CSV") { Patterns = ["*.csv"] } }
}
);
diff --git a/StabilityMatrix.Avalonia/Views/Inference/InferenceImageToVideoView.axaml b/StabilityMatrix.Avalonia/Views/Inference/InferenceImageToVideoView.axaml
index 02a2fd50..92a5866c 100644
--- a/StabilityMatrix.Avalonia/Views/Inference/InferenceImageToVideoView.axaml
+++ b/StabilityMatrix.Avalonia/Views/Inference/InferenceImageToVideoView.axaml
@@ -10,6 +10,7 @@
xmlns:vmInference="using:StabilityMatrix.Avalonia.ViewModels.Inference"
xmlns:dock="clr-namespace:StabilityMatrix.Avalonia.Controls.Dock"
xmlns:modelsInference="clr-namespace:StabilityMatrix.Avalonia.Models.Inference"
+ xmlns:gif="clr-namespace:Avalonia.Gif;assembly=Avalonia.Gif"
d:DataContext="{x:Static mocks:DesignData.InferenceImageToVideoViewModel}"
d:DesignHeight="800"
d:DesignWidth="1000"
@@ -93,9 +94,9 @@
-
+ SourceUri="{Binding OutputUri}" />
+
diff --git a/StabilityMatrix.sln b/StabilityMatrix.sln
index 77cf2c6d..ff5b52a4 100644
--- a/StabilityMatrix.sln
+++ b/StabilityMatrix.sln
@@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StabilityMatrix.Avalonia.Di
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StabilityMatrix.UITests", "StabilityMatrix.UITests\StabilityMatrix.UITests.csproj", "{8C7EDDD1-7FC1-4A15-B379-910A8DA7BCA6}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Gif", "Avalonia.Gif\Avalonia.Gif.csproj", "{72A73F1E-024B-4A25-AD34-626198D9527F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -43,6 +45,10 @@ Global
{8C7EDDD1-7FC1-4A15-B379-910A8DA7BCA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C7EDDD1-7FC1-4A15-B379-910A8DA7BCA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C7EDDD1-7FC1-4A15-B379-910A8DA7BCA6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {72A73F1E-024B-4A25-AD34-626198D9527F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {72A73F1E-024B-4A25-AD34-626198D9527F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {72A73F1E-024B-4A25-AD34-626198D9527F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {72A73F1E-024B-4A25-AD34-626198D9527F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE