Multi-Platform Package Manager for Stable Diffusion
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
5.8 KiB

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Helper.Factory;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.Api.OpenArt;
using StabilityMatrix.Core.Models.Packages.Extensions;
using StabilityMatrix.Core.Services;
namespace StabilityMatrix.Avalonia.ViewModels.Dialogs;
[View(typeof(OpenArtWorkflowDialog))]
[ManagedService]
[Transient]
public partial class OpenArtWorkflowViewModel(
ISettingsManager settingsManager,
IPackageFactory packageFactory
) : ContentDialogViewModelBase
{
public required OpenArtSearchResult Workflow { get; init; }
[ObservableProperty]
private ObservableCollection<OpenArtCustomNode> customNodes = [];
[ObservableProperty]
private string prunedDescription = string.Empty;
[ObservableProperty]
private bool installRequiredNodes = true;
[ObservableProperty]
private InstalledPackage? selectedPackage;
public PackagePair? SelectedPackagePair =>
SelectedPackage is { } package ? packageFactory.GetPackagePair(package) : null;
public List<InstalledPackage> AvailablePackages =>
settingsManager
.Settings.InstalledPackages.Where(package => package.PackageName == "ComfyUI")
.ToList();
public List<PackageExtension> MissingNodes { get; } = [];
public override async Task OnLoadedAsync()
{
if (Design.IsDesignMode)
return;
if (settingsManager.Settings.PreferredWorkflowPackage is { } preferredPackage)
{
SelectedPackage = preferredPackage;
}
else
{
SelectedPackage = AvailablePackages.FirstOrDefault();
}
if (SelectedPackage == null)
{
InstallRequiredNodes = false;
}
CustomNodes = new ObservableCollection<OpenArtCustomNode>(
await ParseNodes(Workflow.NodesIndex.ToList())
);
PrunedDescription = Utilities.RemoveHtml(Workflow.Description);
}
partial void OnSelectedPackageChanged(InstalledPackage? oldValue, InstalledPackage? newValue)
{
if (oldValue is null)
return;
settingsManager.Transaction(settings =>
{
settings.PreferredWorkflowPackage = newValue;
});
OnLoadedAsync().SafeFireAndForget();
}
[Localizable(false)]
private async Task<List<OpenArtCustomNode>> ParseNodes(List<string> nodes)
{
var indexOfFirstDot = nodes.IndexOf(".");
if (indexOfFirstDot != -1)
{
nodes = nodes[(indexOfFirstDot + 1)..];
}
var installedNodesNames = new HashSet<string>();
var nameToManifestNodes = new Dictionary<string, PackageExtension>();
var packagePair = SelectedPackagePair;
if (packagePair?.BasePackage.ExtensionManager is { } extensionManager)
{
var installedNodes = (
await extensionManager.GetInstalledExtensionsLiteAsync(packagePair.InstalledPackage)
).ToList();
var manifestExtensionsMap = await extensionManager.GetManifestExtensionsMapAsync(
extensionManager.GetManifests(packagePair.InstalledPackage)
);
// Add manifestExtensions definition to installedNodes if matching git repository url
installedNodes = installedNodes
.Select(installedNode =>
{
if (
installedNode.GitRepositoryUrl is not null
&& manifestExtensionsMap.TryGetValue(
installedNode.GitRepositoryUrl,
out var manifestExtension
)
)
{
installedNode = installedNode with { Definition = manifestExtension };
}
return installedNode;
})
.ToList();
// There may be duplicate titles, deduplicate by using the first one
nameToManifestNodes = manifestExtensionsMap
.GroupBy(x => x.Value.Title)
.ToDictionary(x => x.Key, x => x.First().Value);
installedNodesNames = installedNodes.Select(x => x.Title).ToHashSet();
}
var sections = new List<OpenArtCustomNode>();
OpenArtCustomNode? currentSection = null;
foreach (var node in nodes)
{
if (node is "." or ",")
{
currentSection = null; // End of the current section
continue;
}
if (currentSection == null)
{
currentSection = new OpenArtCustomNode
{
Title = node,
IsInstalled = installedNodesNames.Contains(node)
};
// Add missing nodes to the list
if (
!currentSection.IsInstalled && nameToManifestNodes.TryGetValue(node, out var manifestNode)
)
{
MissingNodes.Add(manifestNode);
}
sections.Add(currentSection);
}
else
{
currentSection.Children.Add(node);
}
}
if (sections.FirstOrDefault(x => x.Title == "ComfyUI") != null)
{
sections = sections.Where(x => x.Title != "ComfyUI").ToList();
}
return sections;
}
}