diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 1b2d547d2..2234f0836 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -23,6 +23,13 @@
],
"rollForward": false
},
+ "refitter": {
+ "version": "1.4.1",
+ "commands": [
+ "refitter"
+ ],
+ "rollForward": false
+ },
"dotnet-script": {
"version": "1.6.0",
"commands": [
diff --git a/.husky/task-runner.json b/.husky/task-runner.json
index cedfb34b1..c8c0d739e 100644
--- a/.husky/task-runner.json
+++ b/.husky/task-runner.json
@@ -13,6 +13,12 @@
"command": "dotnet",
"args": [ "xstyler", "-f", "${staged}" ],
"include": [ "**/*.axaml" ]
+ },
+ {
+ "name": "Run refitter for LykosAuthApi",
+ "group": "generate-openapi",
+ "command": "dotnet",
+ "args": ["refitter", "--settings-file", "./StabilityMatrix.Core/Api/LykosAuthApi/.refitter"]
}
]
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9a54cb91c..2c7d93464 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,10 +4,32 @@ All notable changes to Stability Matrix will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html).
+
+## v2.13.4
+### Added
+- Added support for RTX 5000-series GPUs in ComfyUI, Forge, and reForge
+- Added "Rebuild .NET Project" command to SwarmUI installs - available via the 3-dots menu -> Package Commands -> Rebuild .NET Project
+### Changed
+- Upgraded ComfyUI CUDA torch to 12.6
+- Upgraded Lykos account connection to use OAuth 2.0 device flow
+- (Internal) Updated Avalonia to 11.2.5
+### Fixed
+- Fixed [#1128](https://github.com/LykosAI/StabilityMatrix/issues/1128) - overwriting models when downloading multiple with the same name
+- Fixed ROCm torch indexes for ComfyUI & Forge
+- Fixed model browser sometimes downloading to `ModelsLora` or `ModelsStableDiffusion` folders instead of the correct folder
+- Fixed incorrect Unet folder path for ComfyUI users on Linux/macOS
+- Fixed [#1157](https://github.com/LykosAI/StabilityMatrix/issues/1157) - crash when broken symlinks exist in model directories
+- Fixed [#1154](https://github.com/LykosAI/StabilityMatrix/issues/1154) - increased width for package name on the package cards
+- Fixed ComfyUI-Zluda not being recognized as an option for Inference or SwarmUI
+- Fixed SwarmUI showing Python options in the 3-dots menu
+- Fixed SD.Next install failures in certain cases when using Zluda
+### Supporters
+#### Visionaries
+- Huge thanks to our amazing Visionary-tier Patrons, **Waterclouds** and **Corey T**! We're truly grateful for your continued generosity and support!
+#### Pioneers
+- Special appreciation to our fantastic Pioneer-tier Patrons: **tankfox**, **Mr. Unknown**, **Szir777**, **Tigon**, **NowFallenAngel**, and our newest addition, **Al Gorithm**! Thank you all for your incredible commitment and ongoing encouragement!
## v2.13.3
-### Added
-- Added Safetensor Metadata viewer to the Checkpoint Manager context menu - thanks to @genteure!
### Changed
- "Remove symbolic links on shutdown" option now also removes links from Output Sharing
### Fixed
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4a63e62f7..4c3ac44e1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,48 @@
-# Stability Matrix Code Style Guidelines
+# Building
+## Running & Debug
+- If building using managed IDEs like Rider or Visual Studio, ensure that a valid `--runtime ...` argument is being passed to `dotnet`, or `RuntimeIdentifier=...` is set for calling `msbuild`. This is required for runtime-specific resources to be included in the build. Stability Matrix currently supports building for the `win-x64`, `linux-x64` and `osx-arm64` runtimes.
+- You can also build the `StabilityMatrix.Avalonia` project using `dotnet`:
+```bash
+dotnet build ./StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj -r win-x64 -c Debug
+```
+- Note that on Windows, the `net8.0-windows10.0.17763.0` framework is used, build outputs will be in `StabilityMatrix.Avalonia/bin/Debug/net8.0-windows10.0.17763.0/win-x64`. On other platforms the `net8.0` framework is used.
+
+## Building to single file for release
+(Replace `$RELEASE_VERSION` with a non v-prefixed semver version number, e.g. `2.10.0`, `2.11.0-dev.1`, etc.)
+### Windows
+```bash
+dotnet publish ./StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj -r win-x64 -c Release -p:Version=$env:RELEASE_VERSION -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:PublishReadyToRun=true
+```
+### macOS
+The `output_dir` environment variable can be specified or defaults to `./out/osx-arm64/`
+```bash
+./Build/build_macos_app.sh -v $RELEASE_VERSION
+```
+### Linux
+```bash
+sudo apt-get -y install libfuse2
+dotnet tool install -g KuiperZone.PupNet
+pupnet -r linux-x64 -c Release --kind appimage --app-version $RELEASE_VERSION --clean
+```
+
+# Scripts
+## Install Husky.Net & Pre-commit hooks
+- Building the `StabilityMatrix.Avalonia` project once should also install Husky.Net, or run the following command:
+```bash
+dotnet tool restore && dotnet husky install
+```
+## Adding Husky pre-commit hooks
+```bash
+dotnet husky install
+```
+## Generated OpenApi clients
+- Refitter is used to generate some OpenApi clients. New clients should be added to `./.husky/task-runner.json`.
+- To regenerate clients, run the following command:
+```bash
+dotnet husky run -g generate-openapi
+```
+
+# Style Guidelines
These are just guidelines, mostly following the official C# style guidelines, except in a few cases. We might not adhere to these 100% ourselves, but lets try our best :)
## Naming conventions
@@ -47,4 +91,4 @@ if (alreadyAteLunch)
- Mock data for XAML Designer should go in `DesignData\`
- The `Helper\` and `Services\` folder don't really have guidelines, use your best judgment
- XAML & JSON converters should go in the `Converters\` and `Converters\Json\` directories respectively
-- Refit interfaces should go in the `Api\` folder
\ No newline at end of file
+- Refit interfaces should go in the `Api\` folder
diff --git a/Directory.Build.props b/Directory.Build.props
index cac749720..bde27a37c 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -8,7 +8,7 @@
- 11.2.2
+ 11.2.5
diff --git a/Directory.Packages.props b/Directory.Packages.props
index f0c7fda08..f2f2e7d3a 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -53,6 +53,8 @@
+
+
@@ -125,4 +127,4 @@
-
+
\ No newline at end of file
diff --git a/StabilityMatrix.Avalonia/App.axaml.cs b/StabilityMatrix.Avalonia/App.axaml.cs
index e4d835a51..586e46fd6 100644
--- a/StabilityMatrix.Avalonia/App.axaml.cs
+++ b/StabilityMatrix.Avalonia/App.axaml.cs
@@ -7,6 +7,7 @@
using System.Linq;
using System.Net;
using System.Net.Http;
+using System.Net.Http.Headers;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -37,6 +38,8 @@
using NLog.Extensions.Logging;
using NLog.Targets;
using Octokit;
+using OpenIddict.Abstractions;
+using OpenIddict.Client;
using Polly;
using Polly.Contrib.WaitAndRetry;
using Polly.Extensions.Http;
@@ -52,6 +55,7 @@
using StabilityMatrix.Avalonia.ViewModels.Progress;
using StabilityMatrix.Avalonia.Views;
using StabilityMatrix.Core.Api;
+using StabilityMatrix.Core.Api.LykosAuthApi;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Converters.Json;
using StabilityMatrix.Core.Database;
@@ -67,6 +71,7 @@
using Application = Avalonia.Application;
using Logger = NLog.Logger;
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
+using ProductHeaderValue = Octokit.ProductHeaderValue;
#if DEBUG
using StabilityMatrix.Avalonia.Diagnostics.LogViewer;
using StabilityMatrix.Avalonia.Diagnostics.LogViewer.Extensions;
@@ -123,6 +128,14 @@ public sealed class App : Application
#else
public const string LykosAnalyticsApiBaseUrl = "https://analytics.lykos.ai";
#endif
+#if DEBUG
+ // ReSharper disable twice LocalizableElement
+ // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
+ public static string LykosAccountApiBaseUrl =>
+ Config?["LykosAccountApiBaseUrl"] ?? "https://account.lykos.ai/";
+#else
+ public const string LykosAccountApiBaseUrl = "https://account.lykos.ai/";
+#endif
// ReSharper disable once MemberCanBePrivate.Global
public IClassicDesktopStyleApplicationLifetime? DesktopLifetime =>
@@ -365,7 +378,10 @@ internal static void ConfigurePageViewModels(IServiceCollection services)
provider.GetRequiredService>(),
provider.GetRequiredService(),
provider.GetRequiredService(),
- provider.GetRequiredService()
+ provider.GetRequiredService(),
+ provider.GetRequiredService(),
+ provider.GetRequiredService>(),
+ provider.GetRequiredService>()
)
{
Pages =
@@ -594,7 +610,7 @@ internal static IServiceCollection ConfigureServices()
.AddPolicyHandler(retryPolicyLonger);
services
- .AddRefitClient(defaultRefitSettings)
+ .AddRefitClient(defaultRefitSettings)
.ConfigureHttpClient(c =>
{
c.BaseAddress = new Uri(LykosAuthApiBaseUrl);
@@ -607,6 +623,21 @@ internal static IServiceCollection ConfigureServices()
new TokenAuthHeaderHandler(serviceProvider.GetRequiredService())
);
+ services
+ .AddRefitClient(defaultRefitSettings)
+ .ConfigureHttpClient(c =>
+ {
+ c.BaseAddress = new Uri(LykosAuthApiBaseUrl);
+ c.Timeout = TimeSpan.FromHours(1);
+ c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "");
+ })
+ .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { AllowAutoRedirect = false })
+ .AddPolicyHandler(retryPolicy)
+ .AddHttpMessageHandler(
+ serviceProvider =>
+ new TokenAuthHeaderHandler(serviceProvider.GetRequiredService())
+ );
+
services
.AddRefitClient(defaultRefitSettings)
.ConfigureHttpClient(c =>
@@ -643,6 +674,37 @@ internal static IServiceCollection ConfigureServices()
}
);
+ // Add OpenId
+ services
+ .AddOpenIddict()
+ .AddClient(options =>
+ {
+ options.AllowDeviceCodeFlow().AllowRefreshTokenFlow();
+
+ options.DisableTokenStorage();
+ options.AddEphemeralEncryptionKey().AddEphemeralSigningKey();
+
+ options.UseSystemNetHttp().SetProductInformation("StabilityMatrix", "2.0");
+
+ options.AddRegistration(
+ new OpenIddictClientRegistration
+ {
+ ProviderName = OpenIdClientConstants.LykosAccount.ProviderName,
+ Issuer = new Uri(LykosAccountApiBaseUrl),
+ ClientId = "ai.lykos.stabilitymatrix",
+ Scopes =
+ {
+ OpenIddictConstants.Scopes.Profile,
+ OpenIddictConstants.Scopes.Email,
+ OpenIddictConstants.Scopes.OpenId,
+ "api",
+ OpenIddictConstants.Scopes.OfflineAccess
+ },
+ RedirectUri = Program.MessagePipeUri.Append("/callback/login/lykos")
+ }
+ );
+ });
+
ConditionalAddLogViewer(services);
var logConfig = ConfigureLogging();
diff --git a/StabilityMatrix.Avalonia/Assets/brands-lykos-oauth-icon.svg b/StabilityMatrix.Avalonia/Assets/brands-lykos-oauth-icon.svg
new file mode 100644
index 000000000..e97a94363
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Assets/brands-lykos-oauth-icon.svg
@@ -0,0 +1,53 @@
+
+
diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs
index f609ecf81..ee78ff454 100644
--- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs
+++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs
@@ -788,6 +788,13 @@ public static UpdateSettingsViewModel UpdateSettingsViewModel
+ "redirect_uri=http://localhost:5022/api/oauth/patreon/callback";
});
+ public static OAuthDeviceAuthViewModel OAuthDeviceAuthViewModel =>
+ DialogFactory.Get(vm =>
+ {
+ vm.VerificationUri = new Uri("https://example.org/connect/verify");
+ vm.UserCode = "AB23-CD56";
+ });
+
public static PythonPackageSpecifiersViewModel PythonPackageSpecifiersViewModel =>
DialogFactory.Get();
diff --git a/StabilityMatrix.Avalonia/Helpers/ClipboardCommands.cs b/StabilityMatrix.Avalonia/Helpers/ClipboardCommands.cs
new file mode 100644
index 000000000..5d20175d6
--- /dev/null
+++ b/StabilityMatrix.Avalonia/Helpers/ClipboardCommands.cs
@@ -0,0 +1,12 @@
+using System;
+using CommunityToolkit.Mvvm.Input;
+
+namespace StabilityMatrix.Avalonia.Helpers;
+
+public static class ClipboardCommands
+{
+ private static readonly Lazy> CopyTextCommandLazy =
+ new(() => new RelayCommand(text => App.Clipboard.SetTextAsync(text)));
+
+ public static RelayCommand CopyTextCommand => CopyTextCommandLazy.Value;
+}
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
index 06f8c8036..38fc36b20 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
+++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
@@ -167,6 +167,15 @@ public static string Action_Copy {
}
}
+ ///
+ /// Looks up a localized string similar to Copy and Open.
+ ///
+ public static string Action_CopyAndOpen {
+ get {
+ return ResourceManager.GetString("Action_CopyAndOpen", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Copy as Bitmap.
///
@@ -248,6 +257,15 @@ public static string Action_ExitApplication {
}
}
+ ///
+ /// Looks up a localized string similar to Go to Settings.
+ ///
+ public static string Action_GoToSettings {
+ get {
+ return ResourceManager.GetString("Action_GoToSettings", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Hide.
///
@@ -3431,6 +3449,32 @@ public static string Text_DeleteFollowingItems {
}
}
+ ///
+ /// Looks up a localized string similar to ## Heads Up: Lykos Account Sign-Out & Security Upgrade
+ ///
+ ///We've made some important behind-the-scenes improvements to how Stability Matrix handles Lykos accounts, upgrading to a more secure and convenient login system **(OAuth 2.0 with OpenID Connect)**. Because of this, you've been signed out of your Lykos account.
+ ///
+ ///### Why the change?
+ ///
+ ///Your security and privacy are important to us. This upgrade brings:
+ ///
+ ///* **Streamlined Experience:** Sign in once to [account.lykos.ai](https://account.lykos.ai) to c [rest of string was truncated]";.
+ ///
+ public static string Text_LykosAccountUpgradeNotice {
+ get {
+ return ResourceManager.GetString("Text_LykosAccountUpgradeNotice", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Open the link in your browser and enter the following code to authorize your account with Stability Matrix..
+ ///
+ public static string Text_OAuthDeviceAuthDescription {
+ get {
+ return ResourceManager.GetString("Text_OAuthDeviceAuthDescription", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Open the link in your browser and follow the instructions to connect your account..
///
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.de.resx b/StabilityMatrix.Avalonia/Languages/Resources.de.resx
index b65fa5527..a41fdfd06 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.de.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.de.resx
@@ -937,4 +937,7 @@
CLIP Stärke
+
+ Zu den Einstellungen
+
\ No newline at end of file
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.es.resx b/StabilityMatrix.Avalonia/Languages/Resources.es.resx
index 0bc23e712..98e3f445b 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.es.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.es.resx
@@ -1079,4 +1079,7 @@
Se han importado el workflow y los nodos personalizados.
+
+ Ir a la configuración
+
\ No newline at end of file
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx b/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx
index c0cde7f22..cc8d4fa97 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.fr-FR.resx
@@ -1029,4 +1029,7 @@
Le workflow et les custom nodes ont été importés.
+
+ Aller aux paramètres
+
\ No newline at end of file
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.it-it.resx b/StabilityMatrix.Avalonia/Languages/Resources.it-it.resx
index dd3bcc3b8..a34ac2eba 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.it-it.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.it-it.resx
@@ -683,4 +683,7 @@
CivitAI
+
+ Vai alle impostazioni
+
\ No newline at end of file
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.ja-JP.resx b/StabilityMatrix.Avalonia/Languages/Resources.ja-JP.resx
index e3a073520..a3e4b00fb 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.ja-JP.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.ja-JP.resx
@@ -1148,4 +1148,95 @@
Stability Matrixを実行する前に、ZIPファイルからアプリを抽出してください
+
+ コンソールに表示されている行より上にスクロールして戻ることができる行数
+
+
+ アカウント接続に問題が発生しました
+
+
+ モデルメタデータの編集
+
+
+ バージョン名
+
+
+ リンクをクリップボードにコピー
+
+
+ {0} でサインイン
+ e.g. 'Sign in with Google'
+
+
+ ブラウザのリンクを開き、指示に従ってアカウントを接続してください
+
+
+ Python Dependencies Override
+
+
+ インストールと更新時に依存関係を追加・置換・削除
+
+
+ Dependency Specifiers
+
+
+ {
+ "packageName": "stable-diffusion-webui",
+ "packageVersion": "v1.10.0",
+ "isSuccess": true,
+ "type": "install",
+ "timestamp": "2024-09-04T02:14:04.1967404+00:00"
+}
+
+
+ この動作はいつでも {0} の手順で変更できます。
+ e.g. 'You can always change this behavior in Settings > Category > Item.'
+
+
+ Stability Matrixの改善にご協力ください。OS, パッケージの種類など改善に必要なデータのみ匿名で送信し、あなた及びあなたのアカウントとの関連付けはいたしません、また個人データ・機密情報は決して送信しません。
+
+
+ 使用された機能、OSのバージョン、インストールされているパッケージの種類などについての匿名データを送信して、Stability Matrixの改善にご協力ください。
+
+
+ 送信されたデータは、あなたまたはあなたのアカウントとは決して関連付けられず、個人データや機密情報を含みません。
+
+
+ 使用状況のデータ
+
+
+ プライバシーポリシー
+
+
+ 画像が見つかりません
+
+
+ 非表示のカテゴリを非表示
+
+
+ NSFW画像を表示
+
+
+ 長いファイル名を有効にする
+ (Setting to enable long file paths on windows)
+
+
+ MAX_PATH limitations を削除する(Windows で長いファイルパスを有効にする設定)
+ (Setting to enable long file paths on windows)
+
+
+ システム設定
+
+
+ 変更を適用する
+
+
+ 変更を有効にするには、再起動が必要になる場合があります。
+
+
+ このパッケージではこのリリースを利用できません。
+
+
+ 設定に移動
+
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.ko-KR.resx b/StabilityMatrix.Avalonia/Languages/Resources.ko-KR.resx
index bdd545ed0..f507e12dc 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.ko-KR.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.ko-KR.resx
@@ -1188,4 +1188,7 @@
클립보드에 링크 복사
+
+ 설정으로 이동
+
\ No newline at end of file
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.pt-BR.resx b/StabilityMatrix.Avalonia/Languages/Resources.pt-BR.resx
index 7e62580f2..a3eb9fcae 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.pt-BR.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.pt-BR.resx
@@ -1150,4 +1150,149 @@
Desativar atualização automática
+
+ EXTRAIA O PROGRAMA DO ARQUIVO ZIP ANTES DE EXECUTAR O STABILITY MATRIX
+
+
+ Tamanho do Histórico
+
+
+ O número de linhas acima daquelas exibidas no console em que você pode rolar de volta
+
+
+ Nós tivemos algum problema para conectar sua conta
+
+
+ Editar Metadados do Modelo
+
+
+ NSFW
+
+
+ Tags
+
+
+ Nome de Versão
+
+
+ Palavras Treinadas
+
+
+ Pré-visualizar imagem
+
+
+ Tamanho do Lote
+
+
+ Lotes
+
+
+ Amostrador
+
+
+ Agendador
+
+
+ Tamanho máximo
+
+
+ Usar prompt separado
+
+
+ Semente
+
+
+ Prompt Negativo
+
+
+ Nova Pasta
+
+
+ Copiar Link para a Área de Transferência
+
+
+ Entrar com {0}
+ e.g. 'Sign in with Google'
+
+
+ Permita que seu navegador abra este aplicativo quando solicitado.
+
+
+ Abra o link no seu navegador e siga as instruções para conectar sua conta.
+
+
+ Substituir dependências do Python
+
+
+ Adicione, substitua ou remova dependências para instalação e atualização
+
+
+ Especificadores de dependência
+
+
+ {
+ "packageName": "stable-diffusion-webui",
+ "packageVersion": "v1.10.0",
+ "isSuccess": true,
+ "type": "install",
+ "timestamp": "2024-09-04T02:14:04.1967404+00:00"
+}
+
+
+ Dados Analíticos
+
+
+ Você sempre pode alterar esse comportamento em {0}.
+ e.g. 'You can always change this behavior in Settings > Category > Item.'
+
+
+ Ajude-nos a melhorar o Stability Matrix enviando dados anônimos sobre recursos usados, versões de sistema operacional, tipos de pacotes instalados, etc. Os dados enviados nunca serão associados a você ou à sua conta e não incluirão dados pessoais ou qualquer informação sensível.
+
+
+ Ajude-nos a melhorar o Stability Matrix enviando dados anônimos sobre recursos usados, versões de sistema operacional, tipos de pacotes instalados, etc.
+
+
+ Os dados enviados nunca serão associados a você ou à sua conta e não incluirão dados pessoais ou qualquer informação sensível.
+
+
+ Dados de Uso
+
+
+ Política de Privacidade
+
+
+ Imagem ocultada
+
+
+ Nenhuma imagem encontrada
+
+
+ Ocultar categorias vazias
+
+
+ Mostrar imagens NSFW
+
+
+ Habilitar caminhos longos
+ (Setting to enable long file paths on windows)
+
+
+ Remover limitações MAX_PATH de funções comuns de arquivo e diretório do Win32
+ (Setting to enable long file paths on windows)
+
+
+ Configurações do Sistema
+
+
+ Alterações Aplicadas
+
+
+ Uma reinicialização pode ser necessária para que as alterações do sistema tenham efeito.
+
+
+ Este pacote não possui versões disponíveis.
+
+
+ Ir para Configurações
+
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.pt-PT.resx b/StabilityMatrix.Avalonia/Languages/Resources.pt-PT.resx
index ee79e62c6..86980fda4 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.pt-PT.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.pt-PT.resx
@@ -937,4 +937,7 @@
CLIP Força a aplicar
+
+ Ir para as Definições
+
\ No newline at end of file
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx
index 9a17d0c9a..53e4f3696 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.resx
@@ -1302,4 +1302,43 @@
- or -
+
+ Open the link in your browser and enter the following code to authorize your account with Stability Matrix.
+
+
+ Copy and Open
+
+
+ Open on OpenModelDB
+
+
+ Wildcards
+
+
+ ## Heads Up: Lykos Account Sign-Out & Security Upgrade
+
+We've made some important behind-the-scenes improvements to how Stability Matrix handles Lykos accounts, upgrading to a more secure and convenient login system **(OAuth 2.0 with OpenID Connect)**. Because of this, you've been signed out of your Lykos account.
+
+### Why the change?
+
+Your security and privacy are important to us. This upgrade brings:
+
+* **Streamlined Experience:** Sign in once to [account.lykos.ai](https://account.lykos.ai) to connect with Stability Matrix and other Lykos AI services.
+* **More Ways to Sign In:** Use your existing [lykos.ai](https://lykos.ai) account, or sign in with **Apple**, **GitHub**, or **Google**.
+* **Enhanced Privacy:** Stability Matrix only requests the permissions it needs.
+* **Industry Standard Security:** We're using OAuth 2.0, the gold standard for secure logins.
+* **Ready for the Future:** This allows for secure connections with other apps and services.
+
+### What do I need to do?
+
+Click the **"Go to Settings"** button, then click **"Connect"** next to **"Lykos account"**.
+
+### Is a Lykos account required?
+
+Nope! Stability Matrix is still fully functional without one. But, your Lykos account enables some extra connected features, such as automatic updates to development builds for our Patreon supporters (and more to come!).
+
+
+
+ Go to Settings
+
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.ru-ru.resx b/StabilityMatrix.Avalonia/Languages/Resources.ru-ru.resx
index 36e8b6488..c9d621c44 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.ru-ru.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.ru-ru.resx
@@ -1266,4 +1266,7 @@
Релизы для этого пакета недоступны.
+
+ Перейти к настройкам
+
\ No newline at end of file
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.tr-TR.resx b/StabilityMatrix.Avalonia/Languages/Resources.tr-TR.resx
index ca8a29abd..6435fb2a3 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.tr-TR.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.tr-TR.resx
@@ -1192,4 +1192,7 @@
Bağlantıyı Panoya Kopyala
+
+ Ayarlara Git
+
\ No newline at end of file
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.zh-Hans.resx b/StabilityMatrix.Avalonia/Languages/Resources.zh-Hans.resx
index 73c37d0eb..3e05d8687 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.zh-Hans.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.zh-Hans.resx
@@ -1262,4 +1262,30 @@
系统更改可能需要重启才能生效。
+
+ 前往设置
+
+
+ ## 重要提示:Lykos 帐户登出和安全升级
+
+我们对 Stability Matrix 处理 Lykos 帐户的方式进行了一些重要的幕后改进,升级到更安全、更便捷的登录系统 **(OAuth 2.0 with OpenID Connect)**。 因此,您已登出 Lykos 帐户。
+
+### 为什么进行此更改?
+
+您的安全和隐私对我们很重要。 此升级带来:
+
+* **简化的体验:** 登录 [account.lykos.ai](https://account.lykos.ai) 一次即可连接到 Stability Matrix 和其他 Lykos AI 服务。
+* **更多登录方式:** 使用您现有的 [lykos.ai](https://lykos.ai) 帐户,或使用 **Apple**、**GitHub** 或 **Google** 登录。
+* **增强的隐私:** Stability Matrix 仅请求其所需的权限。
+* **行业标准安全性:** 我们正在使用 OAuth 2.0,这是安全登录的黄金标准。
+* **为未来做好准备:** 这允许与其他应用程序和服务进行安全连接。
+
+### 我需要做什么?
+
+单击**“前往设置”**按钮,然后单击**“Lykos 帐户”**旁边的**“连接”**。
+
+### Lykos 帐户是必需的吗?
+
+不,Stability Matrix 在没有帐户的情况下仍然可以正常运行。 但是,您的 Lykos 帐户可以启用一些额外的连接功能,例如为我们的 Patreon 支持者自动更新到开发版本(以及更多即将推出的功能)。
+
diff --git a/StabilityMatrix.Avalonia/Languages/Resources.zh-Hant.resx b/StabilityMatrix.Avalonia/Languages/Resources.zh-Hant.resx
index 1ea14f2f6..d02665bd4 100644
--- a/StabilityMatrix.Avalonia/Languages/Resources.zh-Hant.resx
+++ b/StabilityMatrix.Avalonia/Languages/Resources.zh-Hant.resx
@@ -642,4 +642,30 @@
CivitAI
+
+ 前往設定
+
+
+ ## 重要提示:Lykos 帳戶登出和安全性升級
+
+我們對 Stability Matrix 處理 Lykos 帳戶的方式進行了一些重要的幕後改進,升級到更安全、更便捷的登入系統 **(OAuth 2.0 with OpenID Connect)**。 因此,您已登出 Lykos 帳戶。
+
+### 為什麼進行此變更?
+
+您的安全和隱私對我們很重要。 此升級帶來:
+
+* **簡化的體驗:** 登入 [account.lykos.ai](https://account.lykos.ai) 一次即可連接到 Stability Matrix 和其他 Lykos AI 服務。
+* **更多登入方式:** 使用您現有的 [lykos.ai](https://lykos.ai) 帳戶,或使用 **Apple**、**GitHub** 或 **Google** 登入。
+* **增強的隱私:** Stability Matrix 僅請求其所需的權限。
+* **行業標準安全性:** 我們正在使用 OAuth 2.0,這是安全登入的黃金標準。
+* **為未來做好準備:** 這允許與其他應用程式和服務進行安全連接。
+
+### 我需要做什麼?
+
+點擊**「前往設定」**按鈕,然後點擊**「Lykos 帳戶」**旁邊的**「連線」**。
+
+### Lykos 帳戶是必需的嗎?
+
+不,Stability Matrix 在沒有帳戶的情況下仍然可以正常運作。 但是,您的 Lykos 帳戶可以啟用一些額外的連接功能,例如為我們的 Patreon 支持者自動更新到開發版本(以及更多即將推出的功能)。
+
diff --git a/StabilityMatrix.Avalonia/Services/AccountsService.cs b/StabilityMatrix.Avalonia/Services/AccountsService.cs
index 763d51e41..897c505e4 100644
--- a/StabilityMatrix.Avalonia/Services/AccountsService.cs
+++ b/StabilityMatrix.Avalonia/Services/AccountsService.cs
@@ -1,14 +1,24 @@
using System;
using System.Net;
+using System.Security.Claims;
+using System.Threading;
using System.Threading.Tasks;
using Injectio.Attributes;
using Microsoft.Extensions.Logging;
+using Microsoft.IdentityModel.JsonWebTokens;
+using Microsoft.IdentityModel.Tokens;
+using OpenIddict.Abstractions;
+using OpenIddict.Client;
+using OpenIddict.Client.SystemNetHttp;
using StabilityMatrix.Core.Api;
+using StabilityMatrix.Core.Api.LykosAuthApi;
+using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.Api;
using StabilityMatrix.Core.Models.Api.CivitTRPC;
using StabilityMatrix.Core.Models.Api.Lykos;
using StabilityMatrix.Core.Services;
+using static OpenIddict.Client.OpenIddictClientModels;
using ApiException = Refit.ApiException;
namespace StabilityMatrix.Avalonia.Services;
@@ -18,8 +28,10 @@ public class AccountsService : IAccountsService
{
private readonly ILogger logger;
private readonly ISecretsManager secretsManager;
- private readonly ILykosAuthApi lykosAuthApi;
+ private readonly ILykosAuthApiV1 lykosAuthApi;
+ private readonly ILykosAuthApiV2 lykosAuthApiV2;
private readonly ICivitTRPCApi civitTRPCApi;
+ private readonly OpenIddictClientService openIdClient;
///
public event EventHandler? LykosAccountStatusUpdate;
@@ -34,14 +46,18 @@ public class AccountsService : IAccountsService
public AccountsService(
ILogger logger,
ISecretsManager secretsManager,
- ILykosAuthApi lykosAuthApi,
- ICivitTRPCApi civitTRPCApi
+ ILykosAuthApiV1 lykosAuthApi,
+ ILykosAuthApiV2 lykosAuthApiV2,
+ ICivitTRPCApi civitTRPCApi,
+ OpenIddictClientService openIdClient
)
{
this.logger = logger;
this.secretsManager = secretsManager;
this.lykosAuthApi = lykosAuthApi;
+ this.lykosAuthApiV2 = lykosAuthApiV2;
this.civitTRPCApi = civitTRPCApi;
+ this.openIdClient = openIdClient;
// Update our own status when the Lykos account status changes
LykosAccountStatusUpdate += (_, args) => LykosStatus = args;
@@ -96,18 +112,35 @@ public async Task LykosLogoutAsync()
OnLykosAccountStatusUpdate(LykosAccountStatusUpdateEventArgs.Disconnected);
}
+ public async Task LykosAccountV2LoginAsync(LykosAccountV2Tokens tokens)
+ {
+ var secrets = await secretsManager.SafeLoadAsync();
+ secrets = secrets with { LykosAccountV2 = tokens };
+ await secretsManager.SaveAsync(secrets);
+
+ await RefreshLykosAsync(secrets);
+ }
+
+ public async Task LykosAccountV2LogoutAsync()
+ {
+ var secrets = await secretsManager.SafeLoadAsync();
+ await secretsManager.SaveAsync(secrets with { LykosAccountV2 = null });
+
+ OnLykosAccountStatusUpdate(LykosAccountStatusUpdateEventArgs.Disconnected);
+ }
+
///
public async Task LykosPatreonOAuthLogoutAsync()
{
var secrets = await secretsManager.SafeLoadAsync();
- if (secrets.LykosAccount is null)
+ if (secrets.LykosAccountV2 is null)
{
throw new InvalidOperationException(
"Lykos account must be connected in to manage OAuth connections"
);
}
- await lykosAuthApi.DeletePatreonOAuth();
+ await lykosAuthApiV2.ApiV2OauthPatreon();
await RefreshLykosAsync(secrets);
}
@@ -151,17 +184,29 @@ public async Task RefreshAsync()
private async Task RefreshLykosAsync(Secrets secrets)
{
if (
- secrets.LykosAccount is not null
- && !string.IsNullOrWhiteSpace(secrets.LykosAccount?.RefreshToken)
- && !string.IsNullOrWhiteSpace(secrets.LykosAccount?.AccessToken)
+ secrets.LykosAccountV2 is not null
+ && !string.IsNullOrWhiteSpace(secrets.LykosAccountV2?.RefreshToken)
+ && !string.IsNullOrWhiteSpace(secrets.LykosAccountV2?.AccessToken)
)
{
try
{
- var user = await lykosAuthApi.GetUserSelf();
+ var user = await lykosAuthApiV2.ApiV2AccountsMe();
+
+ ClaimsPrincipal? principal = null;
+
+ if (secrets.LykosAccountV2.IdentityToken is not null)
+ {
+ principal = secrets.LykosAccountV2.GetIdentityTokenPrincipal();
+ }
OnLykosAccountStatusUpdate(
- new LykosAccountStatusUpdateEventArgs { IsConnected = true, User = user }
+ new LykosAccountStatusUpdateEventArgs
+ {
+ IsConnected = true,
+ Principal = principal,
+ User = user
+ }
);
return;
@@ -236,7 +281,7 @@ private void OnLykosAccountStatusUpdate(LykosAccountStatusUpdateEventArgs e)
logger.LogInformation(
"Lykos account connected: {Id} ({Username})",
e.User?.Id,
- e.User?.Account.Name
+ e.Principal?.Identity?.Name
);
}
diff --git a/StabilityMatrix.Avalonia/Services/IAccountsService.cs b/StabilityMatrix.Avalonia/Services/IAccountsService.cs
index 36e91915f..814b15782 100644
--- a/StabilityMatrix.Avalonia/Services/IAccountsService.cs
+++ b/StabilityMatrix.Avalonia/Services/IAccountsService.cs
@@ -13,14 +13,22 @@ public interface IAccountsService
LykosAccountStatusUpdateEventArgs? LykosStatus { get; }
+ [Obsolete]
Task LykosSignupAsync(string email, string password, string username);
+ [Obsolete]
Task LykosLoginAsync(string email, string password);
+ [Obsolete]
Task LykosLoginViaGoogleOAuthAsync(string code, string state, string codeVerifier);
+ [Obsolete]
Task LykosLogoutAsync();
+ Task LykosAccountV2LoginAsync(LykosAccountV2Tokens tokens);
+
+ Task LykosAccountV2LogoutAsync();
+
Task LykosPatreonOAuthLogoutAsync();
Task CivitLoginAsync(string apiToken);
diff --git a/StabilityMatrix.Avalonia/Services/ModelImportService.cs b/StabilityMatrix.Avalonia/Services/ModelImportService.cs
index cadde8122..885d2d5ec 100644
--- a/StabilityMatrix.Avalonia/Services/ModelImportService.cs
+++ b/StabilityMatrix.Avalonia/Services/ModelImportService.cs
@@ -5,11 +5,14 @@
using AsyncAwaitBestPractices;
using Avalonia.Controls.Notifications;
using Injectio.Attributes;
+using Python.Runtime;
+using StabilityMatrix.Core.Extensions;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.Api;
using StabilityMatrix.Core.Models.FileInterfaces;
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Services;
+using Dispatcher = Avalonia.Threading.Dispatcher;
namespace StabilityMatrix.Avalonia.Services;
@@ -117,6 +120,23 @@ public async Task DoImport(
modelFile.Name = Path.GetInvalidFileNameChars()
.Aggregate(modelFile.Name, (current, c) => current.Replace(c, '_'));
+ // New code: Ensure unique file name
+ var originalFileName = modelFile.Name;
+ var uniqueFileName = GenerateUniqueFileName(downloadFolder.ToString(), originalFileName);
+ if (!uniqueFileName.Equals(originalFileName, StringComparison.Ordinal))
+ {
+ Dispatcher.UIThread.Post(() =>
+ {
+ notificationService.Show(
+ new Notification(
+ "File renamed",
+ $"A file with the name \"{originalFileName}\" already exists. The model will be saved as \"{uniqueFileName}\"."
+ )
+ );
+ });
+ modelFile.Name = uniqueFileName;
+ }
+
var downloadPath = downloadFolder.JoinFile(modelFile.Name);
// Download model info and preview first
@@ -163,4 +183,25 @@ public async Task DoImport(
await trackedDownloadService.TryStartDownload(download);
}
+
+ private string GenerateUniqueFileName(string folder, string fileName)
+ {
+ var fullPath = Path.Combine(folder, fileName);
+ if (!File.Exists(fullPath))
+ return fileName;
+
+ var name = Path.GetFileNameWithoutExtension(fileName);
+ var extension = Path.GetExtension(fileName);
+ var count = 1;
+ string newFileName;
+
+ do
+ {
+ newFileName = $"{name} ({count}){extension}";
+ fullPath = Path.Combine(folder, newFileName);
+ count++;
+ } while (File.Exists(fullPath));
+
+ return newFileName;
+ }
}
diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
index 280a138de..c158182b3 100644
--- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
+++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
@@ -125,6 +125,8 @@
+
+
diff --git a/StabilityMatrix.Avalonia/Styles/ControlThemes/HyperlinkIconButtonStyles.axaml b/StabilityMatrix.Avalonia/Styles/ControlThemes/HyperlinkIconButtonStyles.axaml
index e49ef7547..18d096abb 100644
--- a/StabilityMatrix.Avalonia/Styles/ControlThemes/HyperlinkIconButtonStyles.axaml
+++ b/StabilityMatrix.Avalonia/Styles/ControlThemes/HyperlinkIconButtonStyles.axaml
@@ -3,21 +3,20 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls"
xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent"
+ xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:ui="using:FluentAvalonia.UI.Controls">
-
-
-
+
+
+
-
-
-
-
+
+
+
+
@@ -29,42 +28,42 @@
-
-
-
+
+
+
-
+
-
-
+
+
+
-
-
+
+
-
-
+
-
+
-
+
diff --git a/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml b/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml
index cf02c7d3e..15fcaa402 100644
--- a/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml
+++ b/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml
@@ -39,21 +39,23 @@
@@ -67,7 +69,7 @@
-
-
+
+ Spacing="16">
-
+
-
+
+ IsVisible="{Binding IsLoading}"
+ Spacing="16">
-
+ Source="{Binding IconUri}"/>-->
+
+
-
-
+ IsIndeterminate="True"
+ IsVisible="{Binding IsLoading}" />
diff --git a/StabilityMatrix.Avalonia/Views/PackageManager/MainPackageManagerView.axaml b/StabilityMatrix.Avalonia/Views/PackageManager/MainPackageManagerView.axaml
index 1c18d27e7..a76e893f0 100644
--- a/StabilityMatrix.Avalonia/Views/PackageManager/MainPackageManagerView.axaml
+++ b/StabilityMatrix.Avalonia/Views/PackageManager/MainPackageManagerView.axaml
@@ -6,10 +6,13 @@
xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:designData="clr-namespace:StabilityMatrix.Avalonia.DesignData"
+ xmlns:generic="clr-namespace:System.Collections.Generic;assembly=System.Runtime"
xmlns:icons="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia"
+ xmlns:input="clr-namespace:FluentAvalonia.UI.Input;assembly=FluentAvalonia"
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
xmlns:markupExtensions="clr-namespace:StabilityMatrix.Avalonia.MarkupExtensions"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core"
xmlns:packageManager="clr-namespace:StabilityMatrix.Avalonia.ViewModels.PackageManager"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:vendorLabs="clr-namespace:StabilityMatrix.Avalonia.Controls.VendorLabs"
@@ -76,13 +79,12 @@
+ IsVisible="{Binding UsesVenv}">
@@ -169,7 +171,7 @@