Browse Source

now downloads & installs the required nodes & the workflow

pull/629/head
JT 9 months ago
parent
commit
be8d2cd78d
  1. 28
      StabilityMatrix.Avalonia/ViewModels/Dialogs/OpenArtWorkflowViewModel.cs
  2. 63
      StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs
  3. 34
      StabilityMatrix.Core/Models/PackageModification/DownloadOpenArtWorkflowStep.cs
  4. 1
      StabilityMatrix.Core/Services/ISettingsManager.cs
  5. 1
      StabilityMatrix.Core/Services/SettingsManager.cs

28
StabilityMatrix.Avalonia/ViewModels/Dialogs/OpenArtWorkflowViewModel.cs

@ -1,9 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.ViewModels.Base;
@ -11,7 +10,6 @@ using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
using StabilityMatrix.Core.Models.Api.OpenArt;
namespace StabilityMatrix.Avalonia.ViewModels.Dialogs;
@ -22,7 +20,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Dialogs;
public partial class OpenArtWorkflowViewModel : ContentDialogViewModelBase
{
public required OpenArtSearchResult Workflow { get; init; }
public string? InstalledComfyPath { get; init; }
public PackagePair? InstalledComfy { get; init; }
[ObservableProperty]
private ObservableCollection<OpenArtCustomNode> customNodes = [];
@ -30,14 +28,16 @@ public partial class OpenArtWorkflowViewModel : ContentDialogViewModelBase
[ObservableProperty]
private string prunedDescription = string.Empty;
public override void OnLoaded()
public override async Task OnLoadedAsync()
{
CustomNodes = new ObservableCollection<OpenArtCustomNode>(ParseNodes(Workflow.NodesIndex.ToList()));
CustomNodes = new ObservableCollection<OpenArtCustomNode>(
await ParseNodes(Workflow.NodesIndex.ToList())
);
PrunedDescription = Utilities.RemoveHtml(Workflow.Description);
}
[Localizable(false)]
private List<OpenArtCustomNode> ParseNodes(List<string> nodes)
private async Task<List<OpenArtCustomNode>> ParseNodes(List<string> nodes)
{
var indexOfFirstDot = nodes.IndexOf(".");
if (indexOfFirstDot != -1)
@ -46,14 +46,14 @@ public partial class OpenArtWorkflowViewModel : ContentDialogViewModelBase
}
var installedNodes = new List<string>();
if (!string.IsNullOrWhiteSpace(InstalledComfyPath))
if (InstalledComfy != null)
{
installedNodes = Directory
.EnumerateDirectories(InstalledComfyPath)
.Select(
x => x.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries).Last()
installedNodes = (
await InstalledComfy.BasePackage.ExtensionManager?.GetInstalledExtensionsAsync(
InstalledComfy.InstalledPackage
)
.Where(x => ComfyNodeMap.Lookup.Values.FirstOrDefault(y => y.EndsWith(x)) != null)
)
.Select(x => x.PrimaryPath?.Name)
.ToList();
}

63
StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs

@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
@ -18,11 +18,14 @@ using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Avalonia.Views;
using StabilityMatrix.Core.Api;
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.PackageModification;
using StabilityMatrix.Core.Models.Packages.Extensions;
using StabilityMatrix.Core.Processes;
using StabilityMatrix.Core.Services;
using Symbol = FluentIcons.Common.Symbol;
using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource;
namespace StabilityMatrix.Avalonia.ViewModels;
@ -31,13 +34,14 @@ namespace StabilityMatrix.Avalonia.ViewModels;
public partial class OpenArtBrowserViewModel(
IOpenArtApi openArtApi,
INotificationService notificationService,
ISettingsManager settingsManager
ISettingsManager settingsManager,
IPackageFactory packageFactory
) : PageViewModelBase, IInfinitelyScroll
{
private const int PageSize = 20;
public override string Title => Resources.Label_Workflows;
public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Whiteboard };
public override IconSource IconSource => new FASymbolIconSource { Symbol = "fa-solid fa-circle-nodes" };
private readonly SourceCache<OpenArtSearchResult, string> searchResultsCache = new(x => x.Id);
@ -135,6 +139,10 @@ public partial class OpenArtBrowserViewModel(
x => x.PackageName is "ComfyUI"
);
var comfyPair = packageFactory.GetPackagePair(existingComfy);
var vm = new OpenArtWorkflowViewModel { Workflow = workflow, InstalledComfy = comfyPair };
var dialog = new BetterContentDialog
{
IsPrimaryButtonEnabled = true,
@ -146,16 +154,47 @@ public partial class OpenArtBrowserViewModel(
MaxDialogWidth = 750,
MaxDialogHeight = 850,
CloseOnClickOutside = true,
Content = new OpenArtWorkflowViewModel
Content = vm
};
var result = await dialog.ShowAsync();
if (result != ContentDialogResult.Primary)
return;
var steps = new List<IPackageStep>();
foreach (var node in vm.CustomNodes.Where(x => x.IsInstalled is false))
{
if (ComfyNodeMap.Lookup.TryGetValue(node.Title, out var url))
{
Workflow = workflow,
InstalledComfyPath = existingComfy is null
? null
: Path.Combine(settingsManager.LibraryDir, existingComfy.LibraryPath!, "custom_nodes")
},
steps.Add(
new InstallExtensionStep(
comfyPair.BasePackage.ExtensionManager,
comfyPair.InstalledPackage,
new PackageExtension
{
Title = node.Title,
Reference = new Uri(url),
Files = [new Uri(url)],
InstallType = "git-clone",
Author = node.Title
}
)
);
}
}
steps.Add(new DownloadOpenArtWorkflowStep(openArtApi, vm.Workflow, settingsManager));
var runner = new PackageModificationRunner
{
ShowDialogOnStart = true,
ModificationCompleteTitle = "Workflow Imported",
ModificationCompleteMessage = "Finished importing workflow and custom nodes"
};
EventManager.Instance.OnPackageInstallProgressAdded(runner);
await dialog.ShowAsync();
await runner.ExecuteSteps(steps);
}
private async Task DoSearch(int page = 0)

34
StabilityMatrix.Core/Models/PackageModification/DownloadOpenArtWorkflowStep.cs

@ -0,0 +1,34 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using StabilityMatrix.Core.Api;
using StabilityMatrix.Core.Models.Api.OpenArt;
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Services;
namespace StabilityMatrix.Core.Models.PackageModification;
public class DownloadOpenArtWorkflowStep(
IOpenArtApi openArtApi,
OpenArtSearchResult workflow,
ISettingsManager settingsManager
) : IPackageStep
{
public async Task ExecuteAsync(IProgress<ProgressReport>? progress = null)
{
var workflowData = await openArtApi
.DownloadWorkflowAsync(new OpenArtDownloadRequest { WorkflowId = workflow.Id })
.ConfigureAwait(false);
Directory.CreateDirectory(settingsManager.WorkflowDirectory);
var filePath = Path.Combine(settingsManager.WorkflowDirectory, $"{workflowData.Filename}.json");
var jsonObject = JsonNode.Parse(workflowData.Payload) as JsonObject;
jsonObject?.Add("workflow_id", workflow.Id);
await File.WriteAllTextAsync(filePath, JsonSerializer.Serialize(jsonObject)).ConfigureAwait(false);
progress?.Report(new ProgressReport(1f, "Downloaded OpenArt Workflow"));
}
public string ProgressTitle => "Downloading OpenArt Workflow";
}

1
StabilityMatrix.Core/Services/ISettingsManager.cs

@ -22,6 +22,7 @@ public interface ISettingsManager
Settings Settings { get; }
List<string> PackageInstallsInProgress { get; set; }
DirectoryPath WorkflowDirectory { get; }
/// <summary>
/// Event fired when the library directory is changed

1
StabilityMatrix.Core/Services/SettingsManager.cs

@ -64,6 +64,7 @@ public class SettingsManager : ISettingsManager
private FilePath SettingsFile => LibraryDir.JoinFile("settings.json");
public string ModelsDirectory => Path.Combine(LibraryDir, "Models");
public string DownloadsDirectory => Path.Combine(LibraryDir, ".downloads");
public DirectoryPath WorkflowDirectory => LibraryDir.JoinDir("Workflows");
public DirectoryPath TagsDirectory => LibraryDir.JoinDir("Tags");
public DirectoryPath ImagesDirectory => LibraryDir.JoinDir("Images");
public DirectoryPath ImagesInferenceDirectory => ImagesDirectory.JoinDir("Inference");

Loading…
Cancel
Save