Skip to content

Commit 8032015

Browse files
committed
Add Accelerated Model Discovery
1 parent 1512a37 commit 8032015

File tree

9 files changed

+457
-30
lines changed

9 files changed

+457
-30
lines changed

StabilityMatrix.Avalonia/App.axaml.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,20 @@ internal static IServiceCollection ConfigureServices()
599599
})
600600
.AddPolicyHandler(retryPolicyLonger);
601601

602+
services
603+
.AddRefitClient<ILykosModelDiscoveryApi>(defaultRefitSettings)
604+
.ConfigureHttpClient(c =>
605+
{
606+
c.BaseAddress = new Uri("https://discovery.lykos.ai/api/v1");
607+
c.Timeout = TimeSpan.FromHours(1);
608+
c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "");
609+
})
610+
.AddPolicyHandler(retryPolicy)
611+
.AddHttpMessageHandler(
612+
serviceProvider =>
613+
new TokenAuthHeaderHandler(serviceProvider.GetRequiredService<LykosAuthTokenProvider>())
614+
);
615+
602616
services
603617
.AddRefitClient<IPyPiApi>(defaultRefitSettings)
604618
.ConfigureHttpClient(c =>

StabilityMatrix.Avalonia/DesignData/DesignData.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,9 @@ public static CompletionList SampleCompletionList
12011201
.ToArray();
12021202
});
12031203

1204+
public static SponsorshipPromptViewModel SponsorshipPromptViewModel =>
1205+
DialogFactory.Get<SponsorshipPromptViewModel>(vm => { });
1206+
12041207
public static OpenArtWorkflowViewModel OpenArtWorkflowViewModel =>
12051208
new(Services.GetRequiredService<ISettingsManager>(), Services.GetRequiredService<IPackageFactory>())
12061209
{

StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ namespace StabilityMatrix.Avalonia.ViewModels.CheckpointBrowser;
3636
public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinitelyScroll
3737
{
3838
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
39-
private readonly ICivitApi civitApi;
39+
private readonly CivitCompatApiManager civitApi;
4040
private readonly ISettingsManager settingsManager;
4141
private readonly ILiteDbContext liteDbContext;
42+
private readonly IConnectedServiceManager connectedServiceManager;
4243
private readonly INotificationService notificationService;
4344
private readonly ICivitBaseModelTypeService baseModelTypeService;
4445
private bool dontSearch = false;
@@ -104,6 +105,11 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit
104105
private IObservableCollection<BaseModelOptionViewModel> allBaseModels =
105106
new ObservableCollectionExtended<BaseModelOptionViewModel>();
106107

108+
[ObservableProperty]
109+
private bool civitUseDiscoveryApi;
110+
111+
public bool UseLocalCache => true;
112+
107113
public double StatsResizeFactor => Math.Clamp(ResizeFactor, 0.75d, 1.25d);
108114

109115
public IEnumerable<CivitPeriod> AllCivitPeriods =>
@@ -126,17 +132,19 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit
126132
SelectedBaseModels.Count > 0 && SelectedBaseModels.Count < AllBaseModels.Count;
127133

128134
public CivitAiBrowserViewModel(
129-
ICivitApi civitApi,
135+
CivitCompatApiManager civitApi,
130136
ISettingsManager settingsManager,
131137
ServiceManager<ViewModelBase> dialogFactory,
132138
ILiteDbContext liteDbContext,
139+
IConnectedServiceManager connectedServiceManager,
133140
INotificationService notificationService,
134141
ICivitBaseModelTypeService baseModelTypeService
135142
)
136143
{
137144
this.civitApi = civitApi;
138145
this.settingsManager = settingsManager;
139146
this.liteDbContext = liteDbContext;
147+
this.connectedServiceManager = connectedServiceManager;
140148
this.notificationService = notificationService;
141149
this.baseModelTypeService = baseModelTypeService;
142150

@@ -270,6 +278,15 @@ or nameof(HideEarlyAccessModels)
270278
)
271279
);
272280

281+
AddDisposable(
282+
settingsManager.RelayPropertyFor(
283+
this,
284+
model => model.CivitUseDiscoveryApi,
285+
settings => settings.CivitUseDiscoveryApi,
286+
true
287+
)
288+
);
289+
273290
EventManager.Instance.NavigateAndFindCivitAuthorRequested += OnNavigateAndFindCivitAuthorRequested;
274291
}
275292

@@ -361,6 +378,29 @@ private bool FilterModelCardsPredicate(CheckpointBrowserCardViewModel card)
361378
return !card.CivitModel.Nsfw || ShowNsfw;
362379
}
363380

381+
[RelayCommand]
382+
private async Task OnUseDiscoveryToggle()
383+
{
384+
if (CivitUseDiscoveryApi)
385+
{
386+
CivitUseDiscoveryApi = false;
387+
}
388+
else
389+
{
390+
if (!await connectedServiceManager.PromptEnableCivitUseDiscoveryApi())
391+
return;
392+
393+
CivitUseDiscoveryApi = true;
394+
}
395+
396+
// Reset cache in case model differences
397+
Logger.Info("Toggled Discovery API, clearing cache");
398+
399+
var items = await liteDbContext.CivitModelQueryCache.DeleteAllAsync();
400+
401+
Logger.Info("Deleted {Count} Civit model query cache entries", items);
402+
}
403+
364404
/// <summary>
365405
/// Background update task
366406
/// </summary>
@@ -432,20 +472,24 @@ private async Task CivitModelQuery(CivitModelsRequest request, bool isInfiniteSc
432472
.Where(m => m.Mode == null)
433473
.ToList();
434474

435-
// Database update calls will invoke `OnModelsUpdated`
436-
// Add to database
437-
await liteDbContext.UpsertCivitModelAsync(models);
438-
// Add as cache entry
439-
var cacheNew = await liteDbContext.UpsertCivitModelQueryCacheEntryAsync(
440-
new()
441-
{
442-
Id = ObjectHash.GetMd5Guid(request),
443-
InsertedAt = DateTimeOffset.UtcNow,
444-
Request = request,
445-
Items = models,
446-
Metadata = modelsResponse?.Metadata
447-
}
448-
);
475+
var cacheNew = true;
476+
if (UseLocalCache)
477+
{
478+
// Database update calls will invoke `OnModelsUpdated`
479+
// Add to database
480+
await liteDbContext.UpsertCivitModelAsync(models);
481+
// Add as cache entry
482+
cacheNew = await liteDbContext.UpsertCivitModelQueryCacheEntryAsync(
483+
new()
484+
{
485+
Id = ObjectHash.GetMd5Guid(request),
486+
InsertedAt = DateTimeOffset.UtcNow,
487+
Request = request,
488+
Items = models,
489+
Metadata = modelsResponse?.Metadata
490+
}
491+
);
492+
}
449493

450494
if (cacheNew)
451495
{
@@ -554,7 +598,8 @@ private async Task SearchModels(bool isInfiniteScroll = false)
554598
{
555599
Nsfw = "true", // Handled by local view filter
556600
Sort = SortMode,
557-
Period = SelectedPeriod
601+
Period = SelectedPeriod,
602+
Limit = 30
558603
};
559604

560605
if (NextPageCursor != null)
@@ -637,10 +682,17 @@ private async Task SearchModels(bool isInfiniteScroll = false)
637682
}
638683

639684
// See if query is cached
640-
var cachedQuery = await liteDbContext.TryQueryWithClearOnExceptionAsync(
641-
liteDbContext.CivitModelQueryCache,
642-
liteDbContext.CivitModelQueryCache.IncludeAll().FindByIdAsync(ObjectHash.GetMd5Guid(modelRequest))
643-
);
685+
CivitModelQueryCacheEntry? cachedQuery = null;
686+
687+
if (UseLocalCache)
688+
{
689+
cachedQuery = await liteDbContext.TryQueryWithClearOnExceptionAsync(
690+
liteDbContext.CivitModelQueryCache,
691+
liteDbContext
692+
.CivitModelQueryCache.IncludeAll()
693+
.FindByIdAsync(ObjectHash.GetMd5Guid(modelRequest))
694+
);
695+
}
644696

645697
// If cached, update model cards
646698
if (cachedQuery is not null)
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System.ComponentModel;
2+
using CommunityToolkit.Mvvm.ComponentModel;
3+
using CommunityToolkit.Mvvm.Input;
4+
using FluentAvalonia.UI.Controls;
5+
using FluentAvalonia.UI.Media.Animation;
6+
using Injectio.Attributes;
7+
using StabilityMatrix.Avalonia.Languages;
8+
using StabilityMatrix.Avalonia.Services;
9+
using StabilityMatrix.Avalonia.ViewModels.Base;
10+
using StabilityMatrix.Avalonia.ViewModels.Settings;
11+
using StabilityMatrix.Avalonia.Views.Dialogs;
12+
using StabilityMatrix.Core.Attributes;
13+
using StabilityMatrix.Core.Models.Api.Lykos;
14+
using StabilityMatrix.Core.Processes;
15+
16+
namespace StabilityMatrix.Avalonia.ViewModels.Dialogs;
17+
18+
[View(typeof(SponsorshipPromptDialog))]
19+
[ManagedService]
20+
[RegisterTransient<SponsorshipPromptViewModel>]
21+
public partial class SponsorshipPromptViewModel(
22+
INavigationService<MainWindowViewModel> navigationService,
23+
INavigationService<SettingsViewModel> settingsNavService
24+
) : TaskDialogViewModelBase
25+
{
26+
[Localizable(false)]
27+
[ObservableProperty]
28+
private string titleEmoji = "\u2764\ufe0f";
29+
30+
[ObservableProperty]
31+
private string title = Resources.Sponsorship_Title;
32+
33+
[ObservableProperty]
34+
private string existingSupporterPreamble = Resources.Sponsorship_ExistingSupporterPreamble;
35+
36+
[ObservableProperty]
37+
private string? featureText;
38+
39+
[ObservableProperty]
40+
private bool isPatreonConnected;
41+
42+
[ObservableProperty]
43+
private bool isExistingSupporter;
44+
45+
public void Initialize(
46+
LykosAccountStatusUpdateEventArgs status,
47+
string featureName,
48+
string? requiredTier = null
49+
)
50+
{
51+
IsPatreonConnected = status.IsPatreonConnected;
52+
IsExistingSupporter = status.IsActiveSupporter;
53+
54+
if (string.IsNullOrEmpty(requiredTier))
55+
{
56+
FeatureText = string.Format(Resources.Sponsorship_ReqAnyTier, featureName);
57+
}
58+
else
59+
{
60+
FeatureText = string.Format(Resources.Sponsorship_ReqSpecificTier, featureName, requiredTier);
61+
}
62+
}
63+
64+
[RelayCommand]
65+
private async Task NavigateToAccountSettings()
66+
{
67+
CloseDialog(TaskDialogStandardResult.Close);
68+
navigationService.NavigateTo<SettingsViewModel>(new SuppressNavigationTransitionInfo());
69+
await Task.Delay(100);
70+
settingsNavService.NavigateTo<AccountSettingsViewModel>(new SuppressNavigationTransitionInfo());
71+
}
72+
73+
[Localizable(false)]
74+
[RelayCommand]
75+
private static void OpenSupportUrl()
76+
{
77+
ProcessRunner.OpenUrl("https://www.patreon.com/join/StabilityMatrix");
78+
}
79+
80+
public override TaskDialog GetDialog()
81+
{
82+
var dialog = base.GetDialog();
83+
dialog.Buttons =
84+
[
85+
new TaskDialogCommand
86+
{
87+
Text = Resources.Action_ViewSupportOptions,
88+
IsDefault = true,
89+
Command = OpenSupportUrlCommand
90+
},
91+
new TaskDialogButton
92+
{
93+
Text = Resources.Action_MaybeLater,
94+
DialogResult = TaskDialogStandardResult.Close
95+
}
96+
];
97+
return dialog;
98+
}
99+
}

0 commit comments

Comments
 (0)