Ionite
1 year ago
committed by
GitHub
47 changed files with 657 additions and 399 deletions
@ -1,12 +0,0 @@
|
||||
using System; |
||||
using StabilityMatrix.Core.Api; |
||||
|
||||
namespace StabilityMatrix.Avalonia.DesignData; |
||||
|
||||
public class MockApiFactory : IApiFactory |
||||
{ |
||||
public T CreateRefitClient<T>(Uri baseAddress) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
} |
@ -1,18 +0,0 @@
|
||||
using System; |
||||
using StabilityMatrix.Avalonia.Services; |
||||
|
||||
namespace StabilityMatrix.Avalonia.DesignData; |
||||
|
||||
public class MockDiscordRichPresenceService : IDiscordRichPresenceService |
||||
{ |
||||
/// <inheritdoc /> |
||||
public void Dispose() |
||||
{ |
||||
GC.SuppressFinalize(this); |
||||
} |
||||
|
||||
/// <inheritdoc /> |
||||
public void UpdateState() |
||||
{ |
||||
} |
||||
} |
@ -1,50 +0,0 @@
|
||||
using System; |
||||
using System.IO; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using StabilityMatrix.Core.Models.Progress; |
||||
using StabilityMatrix.Core.Services; |
||||
|
||||
namespace StabilityMatrix.Avalonia.DesignData; |
||||
|
||||
public class MockDownloadService : IDownloadService |
||||
{ |
||||
public Task DownloadToFileAsync( |
||||
string downloadUrl, |
||||
string downloadPath, |
||||
IProgress<ProgressReport>? progress = null, |
||||
string? httpClientName = null, |
||||
CancellationToken cancellationToken = default |
||||
) |
||||
{ |
||||
return Task.CompletedTask; |
||||
} |
||||
|
||||
/// <inheritdoc /> |
||||
public Task ResumeDownloadToFileAsync( |
||||
string downloadUrl, |
||||
string downloadPath, |
||||
long existingFileSize, |
||||
IProgress<ProgressReport>? progress = null, |
||||
string? httpClientName = null, |
||||
CancellationToken cancellationToken = default |
||||
) |
||||
{ |
||||
return Task.CompletedTask; |
||||
} |
||||
|
||||
/// <inheritdoc /> |
||||
public Task<long> GetFileSizeAsync( |
||||
string downloadUrl, |
||||
string? httpClientName = null, |
||||
CancellationToken cancellationToken = default |
||||
) |
||||
{ |
||||
return Task.FromResult(0L); |
||||
} |
||||
|
||||
public Task<Stream?> GetImageStreamFromUrl(string url) |
||||
{ |
||||
return Task.FromResult(new MemoryStream(new byte[24]) as Stream)!; |
||||
} |
||||
} |
@ -1,12 +0,0 @@
|
||||
using System; |
||||
using System.Net.Http; |
||||
|
||||
namespace StabilityMatrix.Avalonia.DesignData; |
||||
|
||||
public class MockHttpClientFactory : IHttpClientFactory |
||||
{ |
||||
public HttpClient CreateClient(string name) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
} |
@ -1,62 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading.Tasks; |
||||
using LiteDB.Async; |
||||
using StabilityMatrix.Core.Database; |
||||
using StabilityMatrix.Core.Models.Api; |
||||
using StabilityMatrix.Core.Models.Database; |
||||
|
||||
namespace StabilityMatrix.Avalonia.DesignData; |
||||
|
||||
public class MockLiteDbContext : ILiteDbContext |
||||
{ |
||||
public LiteDatabaseAsync Database => throw new NotImplementedException(); |
||||
public ILiteCollectionAsync<CivitModel> CivitModels => throw new NotImplementedException(); |
||||
public ILiteCollectionAsync<CivitModelVersion> CivitModelVersions => |
||||
throw new NotImplementedException(); |
||||
public ILiteCollectionAsync<CivitModelQueryCacheEntry> CivitModelQueryCache => |
||||
throw new NotImplementedException(); |
||||
public ILiteCollectionAsync<LocalModelFile> LocalModelFiles => |
||||
throw new NotImplementedException(); |
||||
public ILiteCollectionAsync<InferenceProjectEntry> InferenceProjects => |
||||
throw new NotImplementedException(); |
||||
public ILiteCollectionAsync<LocalImageFile> LocalImageFiles => |
||||
throw new NotImplementedException(); |
||||
|
||||
public Task<(CivitModel?, CivitModelVersion?)> FindCivitModelFromFileHashAsync( |
||||
string hashBlake3 |
||||
) |
||||
{ |
||||
return Task.FromResult<(CivitModel?, CivitModelVersion?)>((null, null)); |
||||
} |
||||
|
||||
public Task<bool> UpsertCivitModelAsync(CivitModel civitModel) |
||||
{ |
||||
return Task.FromResult(true); |
||||
} |
||||
|
||||
public Task<bool> UpsertCivitModelAsync(IEnumerable<CivitModel> civitModels) |
||||
{ |
||||
return Task.FromResult(true); |
||||
} |
||||
|
||||
public Task<bool> UpsertCivitModelQueryCacheEntryAsync(CivitModelQueryCacheEntry entry) |
||||
{ |
||||
return Task.FromResult(true); |
||||
} |
||||
|
||||
public Task<GithubCacheEntry?> GetGithubCacheEntry(string cacheKey) |
||||
{ |
||||
return Task.FromResult<GithubCacheEntry?>(null); |
||||
} |
||||
|
||||
public Task<bool> UpsertGithubCacheEntry(GithubCacheEntry cacheEntry) |
||||
{ |
||||
return Task.FromResult(true); |
||||
} |
||||
|
||||
public void Dispose() |
||||
{ |
||||
GC.SuppressFinalize(this); |
||||
} |
||||
} |
@ -1,47 +0,0 @@
|
||||
using System; |
||||
using System.Threading.Tasks; |
||||
using Avalonia; |
||||
using Avalonia.Controls.Notifications; |
||||
using StabilityMatrix.Avalonia.Services; |
||||
using StabilityMatrix.Core.Models; |
||||
|
||||
namespace StabilityMatrix.Avalonia.DesignData; |
||||
|
||||
public class MockNotificationService : INotificationService |
||||
{ |
||||
public void Initialize(Visual? visual, |
||||
NotificationPosition position = NotificationPosition.BottomRight, int maxItems = 3) |
||||
{ |
||||
} |
||||
|
||||
public void Show(INotification notification) |
||||
{ |
||||
} |
||||
|
||||
public Task<TaskResult<T>> TryAsync<T>(Task<T> task, string title = "Error", string? message = null, |
||||
NotificationType appearance = NotificationType.Error) |
||||
{ |
||||
return Task.FromResult(new TaskResult<T>(default!)); |
||||
} |
||||
|
||||
public Task<TaskResult<bool>> TryAsync(Task task, string title = "Error", string? message = null, |
||||
NotificationType appearance = NotificationType.Error) |
||||
{ |
||||
return Task.FromResult(new TaskResult<bool>(true)); |
||||
} |
||||
|
||||
public void Show( |
||||
string title, |
||||
string message, |
||||
NotificationType appearance = NotificationType.Information, |
||||
TimeSpan? expiration = null) |
||||
{ |
||||
} |
||||
|
||||
public void ShowPersistent( |
||||
string title, |
||||
string message, |
||||
NotificationType appearance = NotificationType.Information) |
||||
{ |
||||
} |
||||
} |
@ -1,26 +0,0 @@
|
||||
using System.Threading.Tasks; |
||||
using StabilityMatrix.Core.Helper; |
||||
using StabilityMatrix.Core.Models.FileInterfaces; |
||||
using StabilityMatrix.Core.Models.Packages; |
||||
|
||||
namespace StabilityMatrix.Avalonia.DesignData; |
||||
|
||||
public class MockSharedFolders : ISharedFolders |
||||
{ |
||||
public void SetupLinksForPackage(BasePackage basePackage, DirectoryPath installDirectory) |
||||
{ |
||||
} |
||||
|
||||
public Task UpdateLinksForPackage(BasePackage basePackage, DirectoryPath installDirectory) |
||||
{ |
||||
return Task.CompletedTask; |
||||
} |
||||
|
||||
public void RemoveLinksForAllPackages() |
||||
{ |
||||
} |
||||
|
||||
public void SetupSharedModelFolders() |
||||
{ |
||||
} |
||||
} |
@ -1,22 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using StabilityMatrix.Core.Models; |
||||
using StabilityMatrix.Core.Models.FileInterfaces; |
||||
using StabilityMatrix.Core.Services; |
||||
|
||||
namespace StabilityMatrix.Avalonia.DesignData; |
||||
|
||||
public class MockTrackedDownloadService : ITrackedDownloadService |
||||
{ |
||||
/// <inheritdoc /> |
||||
public IEnumerable<TrackedDownload> Downloads => Array.Empty<TrackedDownload>(); |
||||
|
||||
/// <inheritdoc /> |
||||
public event EventHandler<TrackedDownload>? DownloadAdded; |
||||
|
||||
/// <inheritdoc /> |
||||
public TrackedDownload NewDownload(Uri downloadUrl, FilePath downloadPath) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
} |
@ -1,16 +1,7 @@
|
||||
using System; |
||||
using System.Runtime.InteropServices; |
||||
using CSharpDiscriminatedUnion.Attributes; |
||||
using OneOf; |
||||
|
||||
namespace StabilityMatrix.Avalonia.Models.Inference; |
||||
|
||||
[GenerateDiscriminatedUnion(CaseFactoryPrefix = "From")] |
||||
[StructLayout(LayoutKind.Auto)] |
||||
public readonly partial struct FileNameFormatPart |
||||
{ |
||||
[StructCase("Constant", isDefaultValue: true)] |
||||
private readonly string constant; |
||||
|
||||
[StructCase("Substitution")] |
||||
private readonly Func<string?> substitution; |
||||
} |
||||
[GenerateOneOf] |
||||
public partial class FileNameFormatPart : OneOfBase<string, Func<string?>> { } |
||||
|
@ -0,0 +1,9 @@
|
||||
namespace StabilityMatrix.Core.Exceptions; |
||||
|
||||
/// <summary> |
||||
/// Generic runtime exception with custom handling by notification service |
||||
/// </summary> |
||||
public class AppException : ApplicationException |
||||
{ |
||||
public string? Details { get; init; } |
||||
} |
@ -0,0 +1,23 @@
|
||||
using System.Diagnostics.CodeAnalysis; |
||||
using StabilityMatrix.Core.Models.Progress; |
||||
using StabilityMatrix.Core.Processes; |
||||
|
||||
namespace StabilityMatrix.Core.Extensions; |
||||
|
||||
public static class ProgressExtensions |
||||
{ |
||||
[return: NotNullIfNotNull(nameof(progress))] |
||||
public static Action<ProcessOutput>? AsProcessOutputHandler( |
||||
this IProgress<ProgressReport>? progress |
||||
) |
||||
{ |
||||
return progress == null |
||||
? null |
||||
: output => |
||||
{ |
||||
progress.Report( |
||||
new ProgressReport { IsIndeterminate = true, Message = output.Text } |
||||
); |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,42 @@
|
||||
using StabilityMatrix.Core.Extensions; |
||||
using StabilityMatrix.Core.Models.FileInterfaces; |
||||
using StabilityMatrix.Core.Models.Progress; |
||||
using StabilityMatrix.Core.Processes; |
||||
using StabilityMatrix.Core.Python; |
||||
|
||||
namespace StabilityMatrix.Core.Models.PackageModification; |
||||
|
||||
public class PipStep : IPackageStep |
||||
{ |
||||
public required ProcessArgs Args { get; init; } |
||||
public required DirectoryPath VenvDirectory { get; init; } |
||||
|
||||
public DirectoryPath? WorkingDirectory { get; init; } |
||||
|
||||
public IReadOnlyDictionary<string, string>? EnvironmentVariables { get; init; } |
||||
|
||||
/// <inheritdoc /> |
||||
public string ProgressTitle => |
||||
Args switch |
||||
{ |
||||
_ when Args.Contains("install") => "Installing Pip Packages", |
||||
_ when Args.Contains("uninstall") => "Uninstalling Pip Packages", |
||||
_ when Args.Contains("-U") || Args.Contains("--upgrade") => "Updating Pip Packages", |
||||
_ => "Running Pip" |
||||
}; |
||||
|
||||
/// <inheritdoc /> |
||||
public async Task ExecuteAsync(IProgress<ProgressReport>? progress = null) |
||||
{ |
||||
await using var venvRunner = new PyVenvRunner(VenvDirectory) |
||||
{ |
||||
WorkingDirectory = WorkingDirectory, |
||||
EnvironmentVariables = EnvironmentVariables |
||||
}; |
||||
|
||||
var args = new List<string> { "-m", "pip" }; |
||||
args.AddRange(Args.ToArray()); |
||||
|
||||
venvRunner.RunDetached(args.ToArray(), progress.AsProcessOutputHandler()); |
||||
} |
||||
} |
@ -0,0 +1,6 @@
|
||||
using OneOf; |
||||
|
||||
namespace StabilityMatrix.Core.Processes; |
||||
|
||||
[GenerateOneOf] |
||||
public partial class Argument : OneOfBase<string, (string, string)> { } |
@ -0,0 +1,72 @@
|
||||
using System.Collections; |
||||
using System.Text.RegularExpressions; |
||||
using OneOf; |
||||
|
||||
namespace StabilityMatrix.Core.Processes; |
||||
|
||||
/// <summary> |
||||
/// Parameter type for command line arguments |
||||
/// Implicitly converts between string and string[], |
||||
/// with no parsing if the input and output types are the same. |
||||
/// </summary> |
||||
public partial class ProcessArgs : OneOfBase<string, string[]>, IEnumerable<string> |
||||
{ |
||||
/// <inheritdoc /> |
||||
public ProcessArgs(OneOf<string, string[]> input) |
||||
: base(input) { } |
||||
|
||||
/// <summary> |
||||
/// Whether the argument string contains the given substring, |
||||
/// or any of the given arguments if the input is an array. |
||||
/// </summary> |
||||
public bool Contains(string arg) => Match(str => str.Contains(arg), arr => arr.Any(Contains)); |
||||
|
||||
public ProcessArgs Concat(ProcessArgs other) => |
||||
Match( |
||||
str => new ProcessArgs(string.Join(' ', str, other.ToString())), |
||||
arr => new ProcessArgs(arr.Concat(other.ToArray()).ToArray()) |
||||
); |
||||
|
||||
public ProcessArgs Prepend(ProcessArgs other) => |
||||
Match( |
||||
str => new ProcessArgs(string.Join(' ', other.ToString(), str)), |
||||
arr => new ProcessArgs(other.ToArray().Concat(arr).ToArray()) |
||||
); |
||||
|
||||
/// <inheritdoc /> |
||||
public IEnumerator<string> GetEnumerator() |
||||
{ |
||||
return ToArray().AsEnumerable().GetEnumerator(); |
||||
} |
||||
|
||||
/// <inheritdoc /> |
||||
public override string ToString() |
||||
{ |
||||
return Match(str => str, arr => string.Join(' ', arr.Select(ProcessRunner.Quote))); |
||||
} |
||||
|
||||
/// <inheritdoc /> |
||||
IEnumerator IEnumerable.GetEnumerator() |
||||
{ |
||||
return GetEnumerator(); |
||||
} |
||||
|
||||
public string[] ToArray() => |
||||
Match( |
||||
str => ArgumentsRegex().Matches(str).Select(x => x.Value.Trim('"')).ToArray(), |
||||
arr => arr |
||||
); |
||||
|
||||
// Implicit conversions |
||||
|
||||
public static implicit operator ProcessArgs(string input) => new(input); |
||||
|
||||
public static implicit operator ProcessArgs(string[] input) => new(input); |
||||
|
||||
public static implicit operator string(ProcessArgs input) => input.ToString(); |
||||
|
||||
public static implicit operator string[](ProcessArgs input) => input.ToArray(); |
||||
|
||||
[GeneratedRegex("""[\"].+?[\"]|[^ ]+""", RegexOptions.IgnoreCase)] |
||||
private static partial Regex ArgumentsRegex(); |
||||
} |
@ -0,0 +1,75 @@
|
||||
using System.Diagnostics; |
||||
using OneOf; |
||||
|
||||
namespace StabilityMatrix.Core.Processes; |
||||
|
||||
/// <summary> |
||||
/// Builder for <see cref="ProcessArgs"/>. |
||||
/// </summary> |
||||
public record ProcessArgsBuilder |
||||
{ |
||||
protected ProcessArgsBuilder() { } |
||||
|
||||
public ProcessArgsBuilder(params Argument[] arguments) |
||||
{ |
||||
Arguments = arguments.ToList(); |
||||
} |
||||
|
||||
public List<Argument> Arguments { get; init; } = new(); |
||||
|
||||
private IEnumerable<string> ToStringArgs() |
||||
{ |
||||
foreach (var argument in Arguments) |
||||
{ |
||||
if (argument.IsT0) |
||||
{ |
||||
yield return argument.AsT0; |
||||
} |
||||
else |
||||
{ |
||||
yield return argument.AsT1.Item1; |
||||
yield return argument.AsT1.Item2; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <inheritdoc /> |
||||
public override string ToString() |
||||
{ |
||||
return ToProcessArgs().ToString(); |
||||
} |
||||
|
||||
public ProcessArgs ToProcessArgs() |
||||
{ |
||||
return ToStringArgs().ToArray(); |
||||
} |
||||
|
||||
public static implicit operator ProcessArgs(ProcessArgsBuilder builder) => |
||||
builder.ToProcessArgs(); |
||||
} |
||||
|
||||
public static class ProcessArgBuilderExtensions |
||||
{ |
||||
public static T AddArg<T>(this T builder, Argument argument) |
||||
where T : ProcessArgsBuilder |
||||
{ |
||||
return builder with { Arguments = builder.Arguments.Append(argument).ToList() }; |
||||
} |
||||
|
||||
public static T RemoveArgKey<T>(this T builder, string argumentKey) |
||||
where T : ProcessArgsBuilder |
||||
{ |
||||
return builder with |
||||
{ |
||||
Arguments = builder.Arguments |
||||
.Where( |
||||
x => |
||||
x.Match( |
||||
stringArg => stringArg != argumentKey, |
||||
tupleArg => tupleArg.Item1 != argumentKey |
||||
) |
||||
) |
||||
.ToList() |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,31 @@
|
||||
using StabilityMatrix.Core.Processes; |
||||
|
||||
namespace StabilityMatrix.Core.Python; |
||||
|
||||
public record PipInstallArgs : ProcessArgsBuilder |
||||
{ |
||||
public PipInstallArgs(params Argument[] arguments) |
||||
: base(arguments) { } |
||||
|
||||
public PipInstallArgs WithTorch(string version = "") => this.AddArg($"torch{version}"); |
||||
|
||||
public PipInstallArgs WithTorchDirectML(string version = "") => |
||||
this.AddArg($"torch-directml{version}"); |
||||
|
||||
public PipInstallArgs WithTorchVision(string version = "") => |
||||
this.AddArg($"torchvision{version}"); |
||||
|
||||
public PipInstallArgs WithXFormers(string version = "") => this.AddArg($"xformers{version}"); |
||||
|
||||
public PipInstallArgs WithExtraIndex(string indexUrl) => |
||||
this.AddArg(("--extra-index-url", indexUrl)); |
||||
|
||||
public PipInstallArgs WithTorchExtraIndex(string index) => |
||||
this.AddArg(("--extra-index-url", $"https://download.pytorch.org/whl/{index}")); |
||||
|
||||
/// <inheritdoc /> |
||||
public override string ToString() |
||||
{ |
||||
return base.ToString(); |
||||
} |
||||
} |
@ -0,0 +1,61 @@
|
||||
using StabilityMatrix.Core.Processes; |
||||
using StabilityMatrix.Core.Python; |
||||
|
||||
namespace StabilityMatrix.Tests.Core; |
||||
|
||||
[TestClass] |
||||
public class PipInstallArgsTests |
||||
{ |
||||
[TestMethod] |
||||
public void TestGetTorch() |
||||
{ |
||||
// Arrange |
||||
const string version = "==2.1.0"; |
||||
|
||||
// Act |
||||
var args = new PipInstallArgs().WithTorch(version).ToProcessArgs().ToString(); |
||||
|
||||
// Assert |
||||
Assert.AreEqual("torch==2.1.0", args); |
||||
} |
||||
|
||||
[TestMethod] |
||||
public void TestGetTorchWithExtraIndex() |
||||
{ |
||||
// Arrange |
||||
const string version = ">=2.0.0"; |
||||
const string index = "cu118"; |
||||
|
||||
// Act |
||||
var args = new PipInstallArgs() |
||||
.WithTorch(version) |
||||
.WithTorchVision() |
||||
.WithTorchExtraIndex(index) |
||||
.ToProcessArgs() |
||||
.ToString(); |
||||
|
||||
// Assert |
||||
Assert.AreEqual( |
||||
"torch>=2.0.0 torchvision --extra-index-url https://download.pytorch.org/whl/cu118", |
||||
args |
||||
); |
||||
} |
||||
|
||||
[TestMethod] |
||||
public void TestGetTorchWithMoreStuff() |
||||
{ |
||||
// Act |
||||
var args = new PipInstallArgs() |
||||
.AddArg("--pre") |
||||
.WithTorch("~=2.0.0") |
||||
.WithTorchVision() |
||||
.WithTorchExtraIndex("nightly/cpu") |
||||
.ToString(); |
||||
|
||||
// Assert |
||||
Assert.AreEqual( |
||||
"--pre torch~=2.0.0 torchvision --extra-index-url https://download.pytorch.org/whl/nightly/cpu", |
||||
args |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,43 @@
|
||||
using StabilityMatrix.Core.Processes; |
||||
|
||||
namespace StabilityMatrix.Tests.Models; |
||||
|
||||
[TestClass] |
||||
public class ProcessArgsTests |
||||
{ |
||||
[DataTestMethod] |
||||
[DataRow("pip", new[] { "pip" })] |
||||
[DataRow("pip install torch", new[] { "pip", "install", "torch" })] |
||||
[DataRow( |
||||
"pip install -r \"file spaces/here\"", |
||||
new[] { "pip", "install", "-r", "file spaces/here" } |
||||
)] |
||||
[DataRow( |
||||
"pip install -r \"file spaces\\here\"", |
||||
new[] { "pip", "install", "-r", "file spaces\\here" } |
||||
)] |
||||
public void TestStringToArray(string input, string[] expected) |
||||
{ |
||||
ProcessArgs args = input; |
||||
string[] result = args; |
||||
CollectionAssert.AreEqual(expected, result); |
||||
} |
||||
|
||||
[DataTestMethod] |
||||
[DataRow(new[] { "pip" }, "pip")] |
||||
[DataRow(new[] { "pip", "install", "torch" }, "pip install torch")] |
||||
[DataRow( |
||||
new[] { "pip", "install", "-r", "file spaces/here" }, |
||||
"pip install -r \"file spaces/here\"" |
||||
)] |
||||
[DataRow( |
||||
new[] { "pip", "install", "-r", "file spaces\\here" }, |
||||
"pip install -r \"file spaces\\here\"" |
||||
)] |
||||
public void TestArrayToString(string[] input, string expected) |
||||
{ |
||||
ProcessArgs args = input; |
||||
string result = args; |
||||
Assert.AreEqual(expected, result); |
||||
} |
||||
} |
Loading…
Reference in new issue