Browse Source

Merge pull request #297 from ionite34/new-package-and-fix-inference-install

New Package & Bug Fixes
pull/240/head
JT 1 year ago committed by GitHub
parent
commit
6b9c2f4c65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      CHANGELOG.md
  2. 7
      StabilityMatrix.Avalonia/App.axaml.cs
  3. 28
      StabilityMatrix.Avalonia/ViewModels/Dialogs/OneClickInstallViewModel.cs
  4. 2
      StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs
  5. 41
      StabilityMatrix.Avalonia/Views/Dialogs/InstallerDialog.axaml
  6. 64
      StabilityMatrix.Avalonia/Views/Dialogs/OneClickInstallDialog.axaml
  7. 7
      StabilityMatrix.Avalonia/Views/Dialogs/OneClickInstallDialog.axaml.cs
  8. 2
      StabilityMatrix.Core/Models/Packages/BasePackage.cs
  9. 289
      StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs

4
CHANGELOG.md

@ -11,8 +11,12 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
- This will link the package's output folders to the relevant subfolders in the "Outputs" directory
- When a package only has a generic "outputs" folder, all generated images from that package will be linked to the "Outputs\Text2Img" folder when this option is enabled
- Added "Outputs" page for viewing generated images from any package, or the shared output folder
- Added [Stable Diffusion WebUI/UX](https://github.com/anapnoe/stable-diffusion-webui-ux) package
### Changed
- If ComfyUI for Inference is chosen during the One-Click Installer, the Inference page will be opened after installation instead of the Launch page
### Fixed
- Fixed crash when clicking Inference gallery image after the image is deleted externally in file explorer
- Fixed Inference popup Install button not working on One-Click Installer
## v2.5.3
### Added

7
StabilityMatrix.Avalonia/App.axaml.cs

@ -433,12 +433,13 @@ public sealed class App : Application
internal static void ConfigurePackages(IServiceCollection services)
{
services.AddSingleton<BasePackage, A3WebUI>();
services.AddSingleton<BasePackage, Fooocus>();
services.AddSingleton<BasePackage, StableDiffusionUx>();
services.AddSingleton<BasePackage, VladAutomatic>();
services.AddSingleton<BasePackage, InvokeAI>();
services.AddSingleton<BasePackage, Fooocus>();
services.AddSingleton<BasePackage, FooocusMre>();
services.AddSingleton<BasePackage, ComfyUI>();
services.AddSingleton<BasePackage, VoltaML>();
services.AddSingleton<BasePackage, FooocusMre>();
services.AddSingleton<BasePackage, InvokeAI>();
}
private static IServiceCollection ConfigureServices()

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

@ -7,6 +7,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging;
using StabilityMatrix.Avalonia.Languages;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Helper.Factory;
@ -26,6 +27,7 @@ public partial class OneClickInstallViewModel : ViewModelBase
private readonly ILogger<OneClickInstallViewModel> logger;
private readonly IPyRunner pyRunner;
private readonly ISharedFolders sharedFolders;
private readonly INavigationService navigationService;
private const string DefaultPackageName = "stable-diffusion-webui";
[ObservableProperty]
@ -55,13 +57,16 @@ public partial class OneClickInstallViewModel : ViewModelBase
public bool IsProgressBarVisible => OneClickInstallProgress > 0 || IsIndeterminate;
private bool isInferenceInstall;
public OneClickInstallViewModel(
ISettingsManager settingsManager,
IPackageFactory packageFactory,
IPrerequisiteHelper prerequisiteHelper,
ILogger<OneClickInstallViewModel> logger,
IPyRunner pyRunner,
ISharedFolders sharedFolders
ISharedFolders sharedFolders,
INavigationService navigationService
)
{
this.settingsManager = settingsManager;
@ -70,6 +75,7 @@ public partial class OneClickInstallViewModel : ViewModelBase
this.logger = logger;
this.pyRunner = pyRunner;
this.sharedFolders = sharedFolders;
this.navigationService = navigationService;
HeaderText = Resources.Text_WelcomeToStabilityMatrix;
SubHeaderText = Resources.Text_OneClickInstaller_SubHeader;
@ -95,6 +101,18 @@ public partial class OneClickInstallViewModel : ViewModelBase
return Task.CompletedTask;
}
[RelayCommand]
private async Task InstallComfyForInference()
{
var comfyPackage = AllPackages.FirstOrDefault(x => x is ComfyUI);
if (comfyPackage != null)
{
SelectedPackage = comfyPackage;
isInferenceInstall = true;
await InstallCommand.ExecuteAsync(null);
}
}
private async Task DoInstall()
{
HeaderText = $"{Resources.Label_Installing} {SelectedPackage.DisplayName}";
@ -171,14 +189,18 @@ public partial class OneClickInstallViewModel : ViewModelBase
SubSubHeaderText = string.Empty;
OneClickInstallProgress = 100;
for (var i = 0; i < 3; i++)
for (var i = 3; i > 0; i--)
{
SubHeaderText = $"{Resources.Text_ProceedingToLaunchPage} ({i + 1}s)";
SubHeaderText = $"{Resources.Text_ProceedingToLaunchPage} ({i}s)";
await Task.Delay(1000);
}
// should close dialog
EventManager.Instance.OnOneClickInstallFinished(false);
if (isInferenceInstall)
{
navigationService.NavigateTo<InferenceViewModel>();
}
}
private async Task DownloadPackage(

2
StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs

@ -108,7 +108,7 @@ public partial class MainWindowViewModel : ViewModelBase
var startupTime = CodeTimer.FormatTime(Program.StartupTimer.Elapsed);
Logger.Info($"App started ({startupTime})");
if (Program.Args.DebugOneClickInstall || !settingsManager.Settings.InstalledPackages.Any())
if (Program.Args.DebugOneClickInstall || settingsManager.Settings.InstalledPackages.Any())
{
var viewModel = dialogFactory.Get<OneClickInstallViewModel>();
var dialog = new BetterContentDialog

41
StabilityMatrix.Avalonia/Views/Dialogs/InstallerDialog.axaml

@ -26,6 +26,7 @@
FontSize="24"
Margin="0, 16, 0, 4" />
<TextBlock Grid.Row="1" Text="{Binding SelectedPackage.Blurb}"
TextWrapping="Wrap"
Margin="0, 0, 0, 4" />
<TextBlock Grid.Row="2" Text="{Binding SelectedPackage.Disclaimer}"
Margin="0, 0, 0, 4"
@ -206,24 +207,28 @@
</UniformGrid>
<!-- Available Packages -->
<ListBox Grid.Column="1" Grid.Row="0"
Margin="8, 16"
ItemsSource="{Binding AvailablePackages}"
SelectedItem="{Binding SelectedPackage}">
<ListBox.Template>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type packages:BasePackage}">
<StackPanel Margin="8">
<TextBlock Text="{Binding DisplayName}" />
<TextBlock Text="{Binding ByAuthor}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ScrollViewer Grid.Column="1" Grid.Row="0"
Margin="8, 16"
MaxHeight="400"
VerticalScrollBarVisibility="Visible">
<ListBox
ItemsSource="{Binding AvailablePackages}"
SelectedItem="{Binding SelectedPackage}">
<ListBox.Template>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type packages:BasePackage}">
<StackPanel Margin="8">
<TextBlock Text="{Binding DisplayName}" />
<TextBlock Text="{Binding ByAuthor}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</Grid>
</controls:UserControlBase>

64
StabilityMatrix.Avalonia/Views/Dialogs/OneClickInstallDialog.axaml

@ -37,8 +37,10 @@
Title="Use ComfyUI with Inference"
Subtitle="A new built-in native Stable Diffusion experience, powered by ComfyUI"
ActionButtonContent="{x:Static lang:Resources.Action_Install}"
ActionButtonCommand="{Binding InstallComfyForInferenceCommand}"
CloseButtonContent="{x:Static lang:Resources.Action_Close}"
PreferredPlacement="RightTop"
Margin="8,0,0,0"
PlacementMargin="0,0,0,0"
TailVisibility="Auto">
<ui:TeachingTip.HeroContent>
@ -68,6 +70,7 @@
FontSize="24"
Margin="16, 16, 0, 4"/>
<TextBlock Text="{Binding SelectedPackage.Blurb}"
TextWrapping="Wrap"
Margin="16, 0, 0, 8"/>
<TextBlock Text="{Binding SelectedPackage.Disclaimer}"
Padding="4"
@ -124,34 +127,39 @@
</StackPanel>
<ListBox Grid.Column="1" Grid.Row="1"
Name="PackagesListBox"
Margin="8, 16"
IsVisible="{Binding ShowInstallButton}"
ItemsSource="{Binding AllPackages}"
SelectedItem="{Binding SelectedPackage}">
<ListBox.Template>
<ControlTemplate>
<ItemsPresenter/>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type packages:BasePackage}">
<Grid ColumnDefinitions="*,Auto">
<StackPanel Margin="8">
<TextBlock Text="{Binding DisplayName}"/>
<TextBlock Text="{Binding ByAuthor}"/>
</StackPanel>
<ui:InfoBadge
IsVisible="{Binding IsInferenceCompatible}"
Grid.Column="1"
Margin="16,0,0,0"
Classes="Success Dot"
VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ScrollViewer Grid.Column="1" Grid.Row="1"
MaxHeight="400"
VerticalScrollBarVisibility="Visible"
Margin="0, 16">
<ListBox
Name="PackagesListBox"
Margin="8,0"
IsVisible="{Binding ShowInstallButton}"
ItemsSource="{Binding AllPackages}"
SelectedItem="{Binding SelectedPackage}">
<ListBox.Template>
<ControlTemplate>
<ItemsPresenter/>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type packages:BasePackage}">
<Grid ColumnDefinitions="*,Auto">
<StackPanel Margin="8">
<TextBlock Text="{Binding DisplayName}"/>
<TextBlock Text="{Binding ByAuthor}"/>
</StackPanel>
<ui:InfoBadge
IsVisible="{Binding IsInferenceCompatible}"
Grid.Column="1"
Margin="8,0,0,0"
Classes="Success Dot"
VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</Grid>
</UserControl>

7
StabilityMatrix.Avalonia/Views/Dialogs/OneClickInstallDialog.axaml.cs

@ -30,7 +30,12 @@ public partial class OneClickInstallDialog : UserControl
var teachingTip =
this.FindControl<TeachingTip>("InferenceTeachingTip")
?? throw new InvalidOperationException("TeachingTip not found");
;
teachingTip.ActionButtonClick += (_, _) =>
{
teachingTip.IsOpen = false;
};
// Find ComfyUI listbox item
var listBox = this.FindControl<ListBox>("PackagesListBox");

2
StabilityMatrix.Core/Models/Packages/BasePackage.cs

@ -187,7 +187,7 @@ public abstract class BasePackage
await venvRunner
.PipInstall(PyVenvRunner.TorchPipInstallArgsCuda, onConsoleOutput)
.ConfigureAwait(false);
await venvRunner.PipInstall("xformers", onConsoleOutput).ConfigureAwait(false);
await venvRunner.PipInstall("xformers==0.0.20", onConsoleOutput).ConfigureAwait(false);
}
protected Task InstallDirectMlTorch(

289
StabilityMatrix.Core/Models/Packages/StableDiffusionUx.cs

@ -0,0 +1,289 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
using NLog;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Helper.Cache;
using StabilityMatrix.Core.Models.FileInterfaces;
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Processes;
using StabilityMatrix.Core.Python;
using StabilityMatrix.Core.Services;
namespace StabilityMatrix.Core.Models.Packages;
public class StableDiffusionUx : BaseGitPackage
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public override string Name => "stable-diffusion-webui-ux";
public override string DisplayName { get; set; } = "Stable Diffusion Web UI-UX";
public override string Author => "anapnoe";
public override string LicenseType => "AGPL-3.0";
public override string LicenseUrl =>
"https://github.com/anapnoe/stable-diffusion-webui-ux/blob/master/LICENSE.txt";
public override string Blurb =>
"A pixel perfect design, mobile friendly, customizable interface that adds accessibility, "
+ "ease of use and extended functionallity to the stable diffusion web ui.";
public override string LaunchCommand => "launch.py";
public override Uri PreviewImageUri =>
new(
"https://user-images.githubusercontent.com/124302297/227973574-6003142d-0c7c-41c6-9966-0792a94549e9.png"
);
public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.Symlink;
public StableDiffusionUx(
IGithubApiCache githubApi,
ISettingsManager settingsManager,
IDownloadService downloadService,
IPrerequisiteHelper prerequisiteHelper
)
: base(githubApi, settingsManager, downloadService, prerequisiteHelper) { }
public override Dictionary<SharedFolderType, IReadOnlyList<string>> SharedFolders =>
new()
{
[SharedFolderType.StableDiffusion] = new[] { "models/Stable-diffusion" },
[SharedFolderType.ESRGAN] = new[] { "models/ESRGAN" },
[SharedFolderType.RealESRGAN] = new[] { "models/RealESRGAN" },
[SharedFolderType.SwinIR] = new[] { "models/SwinIR" },
[SharedFolderType.Lora] = new[] { "models/Lora" },
[SharedFolderType.LyCORIS] = new[] { "models/LyCORIS" },
[SharedFolderType.ApproxVAE] = new[] { "models/VAE-approx" },
[SharedFolderType.VAE] = new[] { "models/VAE" },
[SharedFolderType.DeepDanbooru] = new[] { "models/deepbooru" },
[SharedFolderType.Karlo] = new[] { "models/karlo" },
[SharedFolderType.TextualInversion] = new[] { "embeddings" },
[SharedFolderType.Hypernetwork] = new[] { "models/hypernetworks" },
[SharedFolderType.ControlNet] = new[] { "models/ControlNet" },
[SharedFolderType.Codeformer] = new[] { "models/Codeformer" },
[SharedFolderType.LDSR] = new[] { "models/LDSR" },
[SharedFolderType.AfterDetailer] = new[] { "models/adetailer" }
};
public override Dictionary<SharedOutputType, IReadOnlyList<string>>? SharedOutputFolders =>
new()
{
[SharedOutputType.Extras] = new[] { "outputs/extras-images" },
[SharedOutputType.Saved] = new[] { "log/images" },
[SharedOutputType.Img2Img] = new[] { "outputs/img2img-images" },
[SharedOutputType.Text2Img] = new[] { "outputs/text2img-images" },
[SharedOutputType.Img2ImgGrids] = new[] { "outputs/img2img-grids" },
[SharedOutputType.Text2ImgGrids] = new[] { "outputs/text2img-grids" }
};
[SuppressMessage("ReSharper", "ArrangeObjectCreationWhenTypeNotEvident")]
public override List<LaunchOptionDefinition> LaunchOptions =>
new()
{
new()
{
Name = "Host",
Type = LaunchOptionType.String,
DefaultValue = "localhost",
Options = new() { "--server-name" }
},
new()
{
Name = "Port",
Type = LaunchOptionType.String,
DefaultValue = "7860",
Options = new() { "--port" }
},
new()
{
Name = "VRAM",
Type = LaunchOptionType.Bool,
InitialValue = HardwareHelper
.IterGpuInfo()
.Select(gpu => gpu.MemoryLevel)
.Max() switch
{
Level.Low => "--lowvram",
Level.Medium => "--medvram",
_ => null
},
Options = new() { "--lowvram", "--medvram", "--medvram-sdxl" }
},
new()
{
Name = "Xformers",
Type = LaunchOptionType.Bool,
InitialValue = HardwareHelper.HasNvidiaGpu(),
Options = new() { "--xformers" }
},
new()
{
Name = "API",
Type = LaunchOptionType.Bool,
InitialValue = true,
Options = new() { "--api" }
},
new()
{
Name = "Auto Launch Web UI",
Type = LaunchOptionType.Bool,
InitialValue = false,
Options = new() { "--autolaunch" }
},
new()
{
Name = "Skip Torch CUDA Check",
Type = LaunchOptionType.Bool,
InitialValue = !HardwareHelper.HasNvidiaGpu(),
Options = new() { "--skip-torch-cuda-test" }
},
new()
{
Name = "Skip Python Version Check",
Type = LaunchOptionType.Bool,
InitialValue = true,
Options = new() { "--skip-python-version-check" }
},
new()
{
Name = "No Half",
Type = LaunchOptionType.Bool,
Description = "Do not switch the model to 16-bit floats",
InitialValue = HardwareHelper.HasAmdGpu(),
Options = new() { "--no-half" }
},
new()
{
Name = "Skip SD Model Download",
Type = LaunchOptionType.Bool,
InitialValue = false,
Options = new() { "--no-download-sd-model" }
},
new()
{
Name = "Skip Install",
Type = LaunchOptionType.Bool,
Options = new() { "--skip-install" }
},
LaunchOptionDefinition.Extras
};
public override IEnumerable<SharedFolderMethod> AvailableSharedFolderMethods =>
new[] { SharedFolderMethod.Symlink, SharedFolderMethod.None };
public override IEnumerable<TorchVersion> AvailableTorchVersions =>
new[] { TorchVersion.Cpu, TorchVersion.Cuda, TorchVersion.DirectMl, TorchVersion.Rocm };
public override Task<string> GetLatestVersion() => Task.FromResult("master");
public override bool ShouldIgnoreReleases => true;
public override string OutputFolderName => "outputs";
public override async Task InstallPackage(
string installLocation,
TorchVersion torchVersion,
IProgress<ProgressReport>? progress = null,
Action<ProcessOutput>? onConsoleOutput = null
)
{
await base.InstallPackage(installLocation, torchVersion, progress).ConfigureAwait(false);
progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true));
// Setup venv
await using var venvRunner = new PyVenvRunner(Path.Combine(installLocation, "venv"));
venvRunner.WorkingDirectory = installLocation;
await venvRunner.Setup(true, onConsoleOutput).ConfigureAwait(false);
switch (torchVersion)
{
case TorchVersion.Cpu:
await InstallCpuTorch(venvRunner, progress, onConsoleOutput).ConfigureAwait(false);
break;
case TorchVersion.Cuda:
await InstallCudaTorch(venvRunner, progress, onConsoleOutput).ConfigureAwait(false);
break;
case TorchVersion.Rocm:
await InstallRocmTorch(venvRunner, progress, onConsoleOutput).ConfigureAwait(false);
break;
case TorchVersion.DirectMl:
await InstallDirectMlTorch(venvRunner, progress, onConsoleOutput)
.ConfigureAwait(false);
break;
default:
throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null);
}
// Install requirements file
progress?.Report(
new ProgressReport(-1f, "Installing Package Requirements", isIndeterminate: true)
);
Logger.Info("Installing requirements_versions.txt");
var requirements = new FilePath(installLocation, "requirements_versions.txt");
await venvRunner
.PipInstallFromRequirements(requirements, onConsoleOutput, excludes: "torch")
.ConfigureAwait(false);
progress?.Report(
new ProgressReport(1f, "Installing Package Requirements", isIndeterminate: false)
);
progress?.Report(new ProgressReport(-1f, "Updating configuration", isIndeterminate: true));
// // Create and add {"show_progress_type": "TAESD"} to config.json
// // Only add if the file doesn't exist
// var configPath = Path.Combine(installLocation, "config.json");
// if (!File.Exists(configPath))
// {
// var config = new JsonObject { { "show_progress_type", "TAESD" } };
// await File.WriteAllTextAsync(configPath, config.ToString()).ConfigureAwait(false);
// }
progress?.Report(new ProgressReport(1f, "Install complete", isIndeterminate: false));
}
public override async Task RunPackage(
string installedPackagePath,
string command,
string arguments,
Action<ProcessOutput>? onConsoleOutput
)
{
await SetupVenv(installedPackagePath).ConfigureAwait(false);
void HandleConsoleOutput(ProcessOutput s)
{
onConsoleOutput?.Invoke(s);
if (!s.Text.Contains("Running on", StringComparison.OrdinalIgnoreCase))
return;
var regex = new Regex(@"(https?:\/\/)([^:\s]+):(\d+)");
var match = regex.Match(s.Text);
if (!match.Success)
return;
WebUrl = match.Value;
OnStartupComplete(WebUrl);
}
var args = $"\"{Path.Combine(installedPackagePath, command)}\" {arguments}";
VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, OnExit);
}
private async Task InstallRocmTorch(
PyVenvRunner venvRunner,
IProgress<ProgressReport>? progress = null,
Action<ProcessOutput>? onConsoleOutput = null
)
{
progress?.Report(
new ProgressReport(-1f, "Installing PyTorch for ROCm", isIndeterminate: true)
);
await venvRunner.PipInstall("--upgrade pip wheel", onConsoleOutput).ConfigureAwait(false);
await venvRunner
.PipInstall(PyVenvRunner.TorchPipInstallArgsRocm511, onConsoleOutput)
.ConfigureAwait(false);
}
}
Loading…
Cancel
Save