Browse Source

Merge branch 'main' of https://github.com/ionite34/StabilityMatrix into release-notes

pull/5/head
JT 1 year ago
parent
commit
e1866494a3
  1. 1
      .gitignore
  2. 3
      StabilityMatrix.Tests/StabilityMatrix.Tests.csproj
  3. 37
      StabilityMatrix/App.xaml.cs
  4. 253
      StabilityMatrix/Models/Packages/A3WebUI.cs
  5. 266
      StabilityMatrix/Models/Packages/BaseGitPackage.cs
  6. 0
      StabilityMatrix/Models/Packages/BasePackage.cs
  7. 90
      StabilityMatrix/Models/Packages/VladAutomatic.cs
  8. 4
      StabilityMatrix/Python/IPyRunner.cs
  9. 2
      StabilityMatrix/Python/Interop/PyIOStream.cs
  10. 15
      StabilityMatrix/Python/PyRunner.cs
  11. 2
      StabilityMatrix/Python/PyVenvRunner.cs
  12. 3
      StabilityMatrix/StabilityMatrix.csproj
  13. 1
      StabilityMatrix/ViewModels/InstallerViewModel.cs
  14. 1
      StabilityMatrix/ViewModels/LaunchViewModel.cs
  15. 1
      StabilityMatrix/ViewModels/SettingsViewModel.cs

1
.gitignore vendored

@ -198,6 +198,7 @@ PublishScripts/
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
!**/Models/Packages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed

3
StabilityMatrix.Tests/StabilityMatrix.Tests.csproj

@ -11,11 +11,14 @@
<ItemGroup>
<PackageReference Include="DotNext" Version="4.12.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.0.16" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="Polly.Contrib.WaitAndRetry" Version="1.1.1" />
</ItemGroup>
<ItemGroup>

37
StabilityMatrix/App.xaml.cs

@ -2,6 +2,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Windows;
@ -9,11 +10,16 @@ using Windows.ApplicationModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using Polly;
using Polly.Contrib.WaitAndRetry;
using Polly.Extensions.Http;
using Polly.Timeout;
using Refit;
using StabilityMatrix.Api;
using StabilityMatrix.Helper;
using StabilityMatrix.Models;
using StabilityMatrix.Models.Packages;
using StabilityMatrix.Python;
using StabilityMatrix.Services;
using StabilityMatrix.ViewModels;
using Wpf.Ui.Contracts;
@ -74,14 +80,29 @@ namespace StabilityMatrix
})
};
serviceCollection.AddRefitClient<IGithubApi>(defaultRefitSettings).ConfigureHttpClient(client =>
{
client.BaseAddress = new Uri("https://api.github.com");
});
serviceCollection.AddRefitClient<IA3WebApi>(defaultRefitSettings).ConfigureHttpClient(client =>
{
client.BaseAddress = new Uri("http://localhost:7860");
});
// Polly retry policy for Refit
var delay = Backoff
.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(1), retryCount: 5);
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.Or<TimeoutRejectedException>()
.WaitAndRetryAsync(delay);
// Add Refit clients
serviceCollection.AddRefitClient<IGithubApi>(defaultRefitSettings)
.ConfigureHttpClient(c =>
{
c.BaseAddress = new Uri("https://api.github.com");
c.Timeout = TimeSpan.FromSeconds(5);
})
.AddPolicyHandler(retryPolicy);
serviceCollection.AddRefitClient<IA3WebApi>(defaultRefitSettings)
.ConfigureHttpClient(c =>
{
c.BaseAddress = new Uri("http://localhost:7860");
c.Timeout = TimeSpan.FromSeconds(2);
})
.AddPolicyHandler(retryPolicy);
// Logging configuration
var logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log.txt");

253
StabilityMatrix/Models/Packages/A3WebUI.cs

@ -2,191 +2,58 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using NLog;
using Refit;
using StabilityMatrix.Api;
using StabilityMatrix.Helper;
using StabilityMatrix.Models.Api;
using StabilityMatrix.Python;
namespace StabilityMatrix.Models.Packages;
public class A3WebUI : BasePackage
public class A3WebUI : BaseGitPackage
{
private readonly IGithubApi githubApi;
private readonly ISettingsManager settingsManager;
private PyVenvRunner? venvRunner;
public A3WebUI(IGithubApi githubApi, ISettingsManager settingsManager)
{
this.githubApi = githubApi;
this.settingsManager = settingsManager;
}
public override string Name => "stable-diffusion-webui";
public override string DisplayName { get; set; } = "stable-diffusion-webui";
public override string Author => "AUTOMATIC1111";
public override string GithubUrl => "https://github.com/AUTOMATIC1111/stable-diffusion-webui";
public override string LaunchCommand => "launch.py";
public override string DefaultLaunchArguments => $"{GetVramOption()} {GetXformersOption()}";
public override bool UpdateAvailable { get; set; } = false;
public override async Task<IEnumerable<GithubRelease>> GetVersions()
{
var allReleases = await githubApi.GetAllReleases(Author, Name);
return allReleases;
}
public A3WebUI(IGithubApi githubApi, ISettingsManager settingsManager) : base(githubApi, settingsManager) { }
public override List<LaunchOptionDefinition> LaunchOptions => new()
{
new LaunchOptionDefinition
new()
{
Name = "API",
Options = new List<string> { "--api" }
Options = new() { "--api" }
},
new LaunchOptionDefinition
new()
{
Name = "VRAM",
Options = new List<string> { "--lowvram", "--medvram" }
Options = new() { "--lowvram", "--medvram" }
},
new LaunchOptionDefinition
new()
{
Name = "Xformers",
Options = new List<string> { "--xformers" }
Options = new() { "--xformers" }
}
};
public override string DownloadLocation =>
$"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\StabilityMatrix\\Packages\\{Name}.zip";
public override string InstallLocation { get; set; } =
$"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\StabilityMatrix\\Packages";
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private string webUrl = string.Empty;
public A3WebUI(ISettingsManager settingsManager)
{
this.settingsManager = settingsManager;
}
public override async Task<string?> DownloadPackage(bool isUpdate = false, string? version = null)
{
var latestRelease = await githubApi.GetLatestRelease("AUTOMATIC1111", "stable-diffusion-webui");
var tagName = string.IsNullOrWhiteSpace(version) ? latestRelease.TagName : version;
var downloadUrl = $"https://api.github.com/repos/AUTOMATIC1111/stable-diffusion-webui/zipball/{tagName}";
if (!Directory.Exists(DownloadLocation.Replace($"{Name}.zip", "")))
{
Directory.CreateDirectory(DownloadLocation.Replace($"{Name}.zip", ""));
}
using var client = new HttpClient { Timeout = TimeSpan.FromMinutes(5) };
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("StabilityMatrix", "1.0"));
await using var file = new FileStream(DownloadLocation, FileMode.Create, FileAccess.Write, FileShare.None);
long contentLength = 0;
var retryCount = 0;
var response = await client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);
while (contentLength == 0 && retryCount++ < 5)
{
response = await client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);
contentLength = response.Content.Headers.ContentLength ?? 0;
Logger.Debug("Retrying get-headers for content-length");
Thread.Sleep(50);
}
var isIndeterminate = contentLength == 0;
await using var stream = await response.Content.ReadAsStreamAsync();
var totalBytesRead = 0;
while (true)
{
var buffer = new byte[1024];
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
await file.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
if (isIndeterminate)
{
if (isUpdate)
{
OnUpdateProgressChanged(-1);
}
else
{
OnDownloadProgressChanged(-1);
}
}
else
{
var progress = (int)(totalBytesRead * 100d / contentLength);
Logger.Debug($"Progress; {progress}");
if (isUpdate)
{
OnUpdateProgressChanged(progress);
}
else
{
OnDownloadProgressChanged(progress);
}
}
}
await file.FlushAsync();
OnDownloadComplete(DownloadLocation);
return tagName;
}
public override Task InstallPackage(bool isUpdate = false)
{
UnzipPackage(isUpdate);
if (isUpdate)
{
OnUpdateComplete("Update complete");
}
else
{
OnInstallComplete("Installation complete");
}
return Task.CompletedTask;
}
public override async Task RunPackage(string installedPackagePath, string arguments)
{
var venvPath = Path.Combine(installedPackagePath, "venv");
// Setup venv
venvRunner?.Dispose();
venvRunner = new PyVenvRunner(venvPath);
if (!venvRunner.Exists())
{
await venvRunner.Setup();
}
await SetupVenv(installedPackagePath);
void HandleConsoleOutput(string? s)
{
if (s == null) return;
if (s.Contains("model loaded", StringComparison.OrdinalIgnoreCase))
{
OnStartupComplete(webUrl);
OnStartupComplete(WebUrl);
}
if (s.Contains("Running on", StringComparison.OrdinalIgnoreCase))
{
webUrl = s.Split(" ")[5];
WebUrl = s.Split(" ")[5];
}
Debug.WriteLine($"process stdout: {s}");
OnConsoleOutput($"{s}\n");
@ -200,97 +67,7 @@ public class A3WebUI : BasePackage
var args = $"\"{Path.Combine(installedPackagePath, LaunchCommand)}\" {arguments}";
venvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, HandleExit, workingDirectory: installedPackagePath);
}
public override Task Shutdown()
{
venvRunner?.Dispose();
venvRunner?.Process?.WaitForExitAsync();
return Task.CompletedTask;
}
public override async Task<bool> CheckForUpdates(string installedPackageName)
{
var currentVersion = settingsManager.Settings.InstalledPackages.FirstOrDefault(x => x.Name == installedPackageName)
?.PackageVersion;
if (string.IsNullOrWhiteSpace(currentVersion))
{
return false;
}
try
{
var latestRelease = await githubApi.GetLatestRelease("AUTOMATIC1111", "stable-diffusion-webui");
UpdateAvailable = latestRelease.TagName != currentVersion;
return latestRelease.TagName != currentVersion;
}
catch (ApiException e)
{
Logger.Error(e, "Failed to check for updates");
return false;
}
}
public override async Task<string?> Update()
{
var version = await DownloadPackage(true);
await InstallPackage(true);
return version;
}
private void UnzipPackage(bool isUpdate = false)
{
if (isUpdate)
{
OnInstallProgressChanged(0);
}
else
{
OnUpdateProgressChanged(0);
}
Directory.CreateDirectory(InstallLocation);
using var zip = ZipFile.OpenRead(DownloadLocation);
var zipDirName = string.Empty;
var totalEntries = zip.Entries.Count;
var currentEntry = 0;
foreach (var entry in zip.Entries)
{
if (string.IsNullOrWhiteSpace(entry.Name) && entry.FullName.EndsWith("/"))
{
if (string.IsNullOrWhiteSpace(zipDirName))
{
zipDirName = entry.FullName;
continue;
}
var folderPath = Path.Combine(InstallLocation,
entry.FullName.Replace(zipDirName, string.Empty));
Directory.CreateDirectory(folderPath);
continue;
}
var destinationPath = Path.GetFullPath(Path.Combine(InstallLocation,
entry.FullName.Replace(zipDirName, string.Empty)));
entry.ExtractToFile(destinationPath, true);
currentEntry++;
var progressValue = (int)((double)currentEntry / totalEntries * 100);
if (isUpdate)
{
OnUpdateProgressChanged(progressValue);
}
else
{
OnInstallProgressChanged(progressValue);
}
}
VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, HandleExit, workingDirectory: installedPackagePath);
}
private static string GetVramOption()

266
StabilityMatrix/Models/Packages/BaseGitPackage.cs

@ -0,0 +1,266 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using NLog;
using Refit;
using StabilityMatrix.Api;
using StabilityMatrix.Helper;
using StabilityMatrix.Models.Api;
using StabilityMatrix.Python;
namespace StabilityMatrix.Models.Packages;
/// <summary>
/// Base class for packages that are hosted on Github.
/// Author and Name should be the Github username and repository name respectively.
/// </summary>
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public abstract class BaseGitPackage : BasePackage
{
protected static readonly Logger Logger = LogManager.GetCurrentClassLogger();
protected readonly IGithubApi GithubApi;
protected readonly ISettingsManager SettingsManager;
protected PyVenvRunner? VenvRunner;
/// <summary>
/// URL of the hosted web page on launch
/// </summary>
protected string WebUrl = string.Empty;
public override string GithubUrl => $"https://github.com/{Author}/{Name}";
public override string DownloadLocation =>
$"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\StabilityMatrix\\Packages\\{Name}.zip";
public override string InstallLocation { get; set; } =
$"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\StabilityMatrix\\Packages";
protected string GetDownloadUrl(string tagName) => $"https://api.github.com/repos/{Author}/{Name}/zipball/{tagName}";
protected BaseGitPackage(IGithubApi githubApi, ISettingsManager settingsManager)
{
this.GithubApi = githubApi;
this.SettingsManager = settingsManager;
}
protected Task<GithubRelease> GetLatestRelease()
{
return GithubApi.GetLatestRelease(Author, Name);
}
/// <summary>
/// Setup the virtual environment for the package.
/// </summary>
/// <param name="installedPackagePath"></param>
/// <param name="venvName"></param>
/// <returns></returns>
protected async Task<PyVenvRunner> SetupVenv(string installedPackagePath, string venvName = "venv")
{
var venvPath = Path.Combine(installedPackagePath, "venv");
VenvRunner?.Dispose();
VenvRunner = new PyVenvRunner(venvPath);
if (!VenvRunner.Exists())
{
await VenvRunner.Setup();
}
return VenvRunner;
}
public override async Task<IEnumerable<string>> GetVersions()
{
var allReleases = await GithubApi.GetAllReleases(Author, Name);
return allReleases.Select(release => release.TagName!);
}
public override async Task<string?> DownloadPackage(bool isUpdate = false, string? version = null)
{
var latestRelease = await GetLatestRelease();
var latestTagName = latestRelease.TagName;
if (string.IsNullOrWhiteSpace(latestTagName) && string.IsNullOrWhiteSpace(version))
{
throw new Exception("Could not find latest release. Both latest release and version are null or empty.");
}
var tagName = version ?? latestTagName!;
var downloadUrl = GetDownloadUrl(tagName);
if (!Directory.Exists(DownloadLocation.Replace($"{Name}.zip", "")))
{
Directory.CreateDirectory(DownloadLocation.Replace($"{Name}.zip", ""));
}
using var client = new HttpClient { Timeout = TimeSpan.FromMinutes(5) };
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("StabilityMatrix", "1.0"));
await using var file = new FileStream(DownloadLocation, FileMode.Create, FileAccess.Write, FileShare.None);
long contentLength = 0;
var retryCount = 0;
var response = await client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);
while (contentLength == 0 && retryCount++ < 5)
{
response = await client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);
contentLength = response.Content.Headers.ContentLength ?? 0;
Logger.Debug("Retrying get-headers for content-length");
Thread.Sleep(50);
}
var isIndeterminate = contentLength == 0;
await using var stream = await response.Content.ReadAsStreamAsync();
var totalBytesRead = 0;
while (true)
{
var buffer = new byte[1024];
var bytesRead = await stream.ReadAsync(buffer);
if (bytesRead == 0) break;
await file.WriteAsync(buffer.AsMemory(0, bytesRead));
totalBytesRead += bytesRead;
if (isIndeterminate)
{
if (isUpdate)
{
OnUpdateProgressChanged(-1);
}
else
{
OnDownloadProgressChanged(-1);
}
}
else
{
var progress = (int)(totalBytesRead * 100d / contentLength);
Logger.Debug($"Progress; {progress}");
if (isUpdate)
{
OnUpdateProgressChanged(progress);
}
else
{
OnDownloadProgressChanged(progress);
}
}
}
await file.FlushAsync();
OnDownloadComplete(DownloadLocation);
return tagName;
}
private void UnzipPackage(bool isUpdate = false)
{
if (isUpdate)
{
OnInstallProgressChanged(0);
}
else
{
OnUpdateProgressChanged(0);
}
Directory.CreateDirectory(InstallLocation);
using var zip = ZipFile.OpenRead(DownloadLocation);
var zipDirName = string.Empty;
var totalEntries = zip.Entries.Count;
var currentEntry = 0;
foreach (var entry in zip.Entries)
{
if (string.IsNullOrWhiteSpace(entry.Name) && entry.FullName.EndsWith("/"))
{
if (string.IsNullOrWhiteSpace(zipDirName))
{
zipDirName = entry.FullName;
continue;
}
var folderPath = Path.Combine(InstallLocation,
entry.FullName.Replace(zipDirName, string.Empty));
Directory.CreateDirectory(folderPath);
continue;
}
var destinationPath = Path.GetFullPath(Path.Combine(InstallLocation,
entry.FullName.Replace(zipDirName, string.Empty)));
entry.ExtractToFile(destinationPath, true);
currentEntry++;
var progressValue = (int)((double)currentEntry / totalEntries * 100);
if (isUpdate)
{
OnUpdateProgressChanged(progressValue);
}
else
{
OnInstallProgressChanged(progressValue);
}
}
}
public override Task InstallPackage(bool isUpdate = false)
{
UnzipPackage(isUpdate);
if (isUpdate)
{
OnUpdateComplete("Update complete");
}
else
{
OnInstallComplete("Installation complete");
}
return Task.CompletedTask;
}
public override async Task<bool> CheckForUpdates(string installedPackageName)
{
var currentVersion = SettingsManager.Settings.InstalledPackages.FirstOrDefault(x => x.Name == installedPackageName)
?.PackageVersion;
if (string.IsNullOrWhiteSpace(currentVersion))
{
return false;
}
try
{
var latestRelease = await GetLatestRelease();
UpdateAvailable = latestRelease.TagName != currentVersion;
return latestRelease.TagName != currentVersion;
}
catch (ApiException e)
{
Logger.Error(e, "Failed to check for updates");
return false;
}
}
public override async Task<string?> Update()
{
var version = await DownloadPackage(true);
await InstallPackage(true);
return version;
}
public override Task Shutdown()
{
VenvRunner?.Dispose();
VenvRunner?.Process?.WaitForExitAsync();
return Task.CompletedTask;
}
}

0
StabilityMatrix/Models/BasePackage.cs → StabilityMatrix/Models/Packages/BasePackage.cs

90
StabilityMatrix/Models/Packages/VladAutomatic.cs

@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using StabilityMatrix.Api;
using StabilityMatrix.Helper;
using StabilityMatrix.Python;
namespace StabilityMatrix.Models.Packages;
public class VladAutomatic : BaseGitPackage
{
public override string Name => "automatic";
public override string DisplayName { get; set; } = "SD.Next Web UI";
public override string Author => "vladmandic";
public override string LaunchCommand => "launch.py";
public override string DefaultLaunchArguments => $"{GetVramOption()} {GetXformersOption()}";
public VladAutomatic(IGithubApi githubApi, ISettingsManager settingsManager) : base(githubApi, settingsManager)
{
}
public override List<LaunchOptionDefinition> LaunchOptions => new()
{
new()
{
Name = "API",
Options = new() { "--api" }
},
new()
{
Name = "VRAM",
Options = new() { "--lowvram", "--medvram" }
},
new()
{
Name = "Xformers",
Options = new() { "--xformers" }
}
};
public override async Task RunPackage(string installedPackagePath, string arguments)
{
await SetupVenv(installedPackagePath);
void HandleConsoleOutput(string? s)
{
if (s == null) return;
if (s.Contains("model loaded", StringComparison.OrdinalIgnoreCase))
{
OnStartupComplete(WebUrl);
}
if (s.Contains("Running on", StringComparison.OrdinalIgnoreCase))
{
WebUrl = s.Split(" ")[5];
}
Debug.WriteLine($"process stdout: {s}");
OnConsoleOutput($"{s}\n");
}
void HandleExit(int i)
{
Debug.WriteLine($"Venv process exited with code {i}");
OnConsoleOutput($"Venv process exited with code {i}");
}
var args = $"\"{Path.Combine(installedPackagePath, LaunchCommand)}\" {arguments}";
VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, HandleExit, workingDirectory: installedPackagePath);
}
private static string GetVramOption()
{
var vramGb = HardwareHelper.GetGpuMemoryBytes() / 1024 / 1024 / 1024;
return vramGb switch
{
< 4 => "--lowvram",
< 8 => "--medvram",
_ => string.Empty
};
}
private static string GetXformersOption()
{
var gpuName = HardwareHelper.GetGpuChipName();
return gpuName.Contains("NVIDIA", StringComparison.OrdinalIgnoreCase) ? "--xformers" : string.Empty;
}
}

4
StabilityMatrix/IPyRunner.cs → StabilityMatrix/Python/IPyRunner.cs

@ -1,7 +1,7 @@
using System.IO;
using System.Threading.Tasks;
namespace StabilityMatrix;
namespace StabilityMatrix.Python;
public interface IPyRunner
{
@ -44,4 +44,4 @@ public interface IPyRunner
/// Return the Python version as a PyVersionInfo struct
/// </summary>
Task<PyVersionInfo> GetVersionInfo();
}
}

2
StabilityMatrix/PyIOStream.cs → StabilityMatrix/Python/Interop/PyIOStream.cs

@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
namespace StabilityMatrix;
namespace StabilityMatrix.Python.Interop;
/// <summary>
/// Implement the interface of the sys.stdout redirection

15
StabilityMatrix/PyRunner.cs → StabilityMatrix/Python/PyRunner.cs

@ -3,12 +3,11 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using NLog;
using Python.Runtime;
using StabilityMatrix.Helper;
using ILogger = NLog.ILogger;
using StabilityMatrix.Python.Interop;
namespace StabilityMatrix;
namespace StabilityMatrix.Python;
public record struct PyVersionInfo(int Major, int Minor, int Micro, string ReleaseLevel, int Serial);
@ -105,7 +104,7 @@ public class PyRunner : IPyRunner
/// <param name="waitTimeout">Time limit for waiting on PyRunning lock.</param>
/// <param name="cancelToken">Cancellation token.</param>
/// <exception cref="OperationCanceledException">cancelToken was canceled, or waitTimeout expired.</exception>
private async Task<T> RunInThreadWithLock<T>(Func<T> func, TimeSpan? waitTimeout = null, CancellationToken cancelToken = default)
public async Task<T> RunInThreadWithLock<T>(Func<T> func, TimeSpan? waitTimeout = null, CancellationToken cancelToken = default)
{
// Wait to acquire PyRunning lock
await PyRunning.WaitAsync(cancelToken).ConfigureAwait(false);
@ -132,7 +131,7 @@ public class PyRunner : IPyRunner
/// <param name="waitTimeout">Time limit for waiting on PyRunning lock.</param>
/// <param name="cancelToken">Cancellation token.</param>
/// <exception cref="OperationCanceledException">cancelToken was canceled, or waitTimeout expired.</exception>
private async Task RunInThreadWithLock(Action action, TimeSpan? waitTimeout = null, CancellationToken cancelToken = default)
public async Task RunInThreadWithLock(Action action, TimeSpan? waitTimeout = null, CancellationToken cancelToken = default)
{
// Wait to acquire PyRunning lock
await PyRunning.WaitAsync(cancelToken).ConfigureAwait(false);
@ -169,7 +168,8 @@ public class PyRunner : IPyRunner
{
return RunInThreadWithLock(() =>
{
var result = PythonEngine.Eval(expression);
using var scope = Py.CreateScope();
var result = scope.Eval(expression);
return result.As<T>();
});
}
@ -182,7 +182,8 @@ public class PyRunner : IPyRunner
{
return RunInThreadWithLock(() =>
{
PythonEngine.Exec(code);
using var scope = Py.CreateScope();
scope.Exec(code);
});
}

2
StabilityMatrix/PyVenvRunner.cs → StabilityMatrix/Python/PyVenvRunner.cs

@ -5,7 +5,7 @@ using System.Threading.Tasks;
using NLog;
using StabilityMatrix.Helper;
namespace StabilityMatrix;
namespace StabilityMatrix.Python;
/// <summary>
/// Python runner using a subprocess, mainly for venv support.

3
StabilityMatrix/StabilityMatrix.csproj

@ -14,11 +14,14 @@
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.0" />
<PackageReference Include="Markdown.Xaml" Version="1.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.0.16" />
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageReference Include="NLog" Version="5.1.4" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.3" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="Polly.Contrib.WaitAndRetry" Version="1.1.1" />
<PackageReference Include="Refit" Version="6.3.2" />
<PackageReference Include="Refit.HttpClientFactory" Version="6.3.2" />
<PackageReference Include="WPF-UI" Version="3.0.0-preview.2" />

1
StabilityMatrix/ViewModels/InstallerViewModel.cs

@ -11,6 +11,7 @@ using Microsoft.Extensions.Logging;
using StabilityMatrix.Helper;
using StabilityMatrix.Models;
using StabilityMatrix.Models.Api;
using StabilityMatrix.Python;
using EventManager = StabilityMatrix.Helper.EventManager;
namespace StabilityMatrix.ViewModels;

1
StabilityMatrix/ViewModels/LaunchViewModel.cs

@ -11,6 +11,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Toolkit.Uwp.Notifications;
using StabilityMatrix.Helper;
using StabilityMatrix.Models;
using StabilityMatrix.Python;
using Wpf.Ui.Contracts;
using Wpf.Ui.Controls.ContentDialogControl;

1
StabilityMatrix/ViewModels/SettingsViewModel.cs

@ -9,6 +9,7 @@ using Ookii.Dialogs.Wpf;
using StabilityMatrix.Api;
using StabilityMatrix.Helper;
using StabilityMatrix.Models;
using StabilityMatrix.Python;
using Wpf.Ui.Appearance;
using Wpf.Ui.Contracts;

Loading…
Cancel
Save