Browse Source

Converted civitai browser to new pagination cursor stuff & converted backend to use DynamicData

pull/629/head
JT 8 months ago
parent
commit
6657cf59ea
  1. 6
      CHANGELOG.md
  2. 2
      StabilityMatrix.Avalonia/DesignData/DesignData.cs
  3. 8
      StabilityMatrix.Avalonia/Models/IInfinitelyScroll.cs
  4. 216
      StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs
  5. 68
      StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml
  6. 16
      StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml.cs
  7. 14
      StabilityMatrix.Core/Models/Api/CivitMetadata.cs
  8. 5
      StabilityMatrix.Core/Models/Api/CivitModelStats.cs
  9. 60
      StabilityMatrix.Core/Models/Api/CivitModelsRequest.cs

6
CHANGELOG.md

@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
## v2.10.0-dev.3
### Added
- Added support for deep links from the new Stability Matrix Chrome extension
### Changed
- Due to changes on the CivitAI API, you can no longer select a specific page in the CivitAI Model Browser
- Due to the above API changes, new pages are now loaded via "infinite scrolling"
### Fixed
- Fixed Inference HiresFix module "Inherit Primary Sampler Addons" setting not effectively disabling when unchecked
- Fixed model download location options for VAEs in the CivitAI Model Browser
@ -16,6 +19,9 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
- Fixed ComfyUI with Inference pop-up during one-click install appearing below the visible scroll area
- Fixed no packages being available for one-click install on PCs without a GPU
- Fixed models not being removed from the installed models cache when deleting them from the Checkpoints page
- Fixed missing ratings on some models in the CivitAI Model Browser
- Fixed missing favorite count in the CivitAI Model Browser
- Fixed recommended models not showing all SDXL models
## v2.10.0-dev.2
### Added

2
StabilityMatrix.Avalonia/DesignData/DesignData.cs

@ -325,7 +325,7 @@ public static class DesignData
);
}*/
CivitAiBrowserViewModel.ModelCards = new ObservableCollection<CheckpointBrowserCardViewModel>
CivitAiBrowserViewModel.ModelCards = new ObservableCollectionExtended<CheckpointBrowserCardViewModel>
{
dialogFactory.Get<CheckpointBrowserCardViewModel>(vm =>
{

8
StabilityMatrix.Avalonia/Models/IInfinitelyScroll.cs

@ -0,0 +1,8 @@
using System.Threading.Tasks;
namespace StabilityMatrix.Avalonia.Models;
public interface IInfinitelyScroll
{
Task LoadNextPageAsync();
}

216
StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs

@ -1,13 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Collections;
@ -15,12 +11,15 @@ using Avalonia.Controls;
using Avalonia.Controls.Notifications;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DynamicData;
using DynamicData.Alias;
using DynamicData.Binding;
using LiteDB;
using LiteDB.Async;
using NLog;
using OneOf.Types;
using Refit;
using StabilityMatrix.Avalonia.Languages;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.CheckpointManager;
@ -41,24 +40,26 @@ namespace StabilityMatrix.Avalonia.ViewModels.CheckpointBrowser;
[View(typeof(CivitAiBrowserPage))]
[Singleton]
public partial class CivitAiBrowserViewModel : TabViewModelBase
public partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinitelyScroll
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly ICivitApi civitApi;
private readonly IDownloadService downloadService;
private readonly ISettingsManager settingsManager;
private readonly ServiceManager<ViewModelBase> dialogFactory;
private readonly ILiteDbContext liteDbContext;
private readonly INotificationService notificationService;
private const int MaxModelsPerPage = 20;
private LRUCache<
int /* model id */
,
CheckpointBrowserCardViewModel
> cache = new(50);
[ObservableProperty]
private ObservableCollection<CheckpointBrowserCardViewModel>? modelCards;
public SourceCache<CivitModel, int> ModelCache { get; } = new(m => m.Id);
public IObservableCollection<CheckpointBrowserCardViewModel> ModelCards { get; set; } =
new ObservableCollectionExtended<CheckpointBrowserCardViewModel>();
[ObservableProperty]
private DataGridCollectionView? modelCardsView;
@ -81,27 +82,9 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
[ObservableProperty]
private CivitModelType selectedModelType = CivitModelType.Checkpoint;
[ObservableProperty]
private int currentPageNumber;
[ObservableProperty]
private int totalPages;
[ObservableProperty]
private bool hasSearched;
[ObservableProperty]
private bool canGoToNextPage;
[ObservableProperty]
private bool canGoToPreviousPage;
[ObservableProperty]
private bool canGoToFirstPage;
[ObservableProperty]
private bool canGoToLastPage;
[ObservableProperty]
private bool isIndeterminate;
@ -117,7 +100,8 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
[ObservableProperty]
private bool showSantaHats = true;
private List<CheckpointBrowserCardViewModel> allModelCards = new();
[ObservableProperty]
private string? nextPageCursor;
public IEnumerable<CivitPeriod> AllCivitPeriods =>
Enum.GetValues(typeof(CivitPeriod)).Cast<CivitPeriod>();
@ -143,24 +127,45 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
)
{
this.civitApi = civitApi;
this.downloadService = downloadService;
this.settingsManager = settingsManager;
this.dialogFactory = dialogFactory;
this.liteDbContext = liteDbContext;
this.notificationService = notificationService;
CurrentPageNumber = 1;
CanGoToNextPage = true;
CanGoToLastPage = true;
ModelCache
.Connect()
.DeferUntilLoaded()
.Select(model =>
{
var cachedViewModel = cache.Get(model.Id);
if (cachedViewModel != null)
{
if (!cachedViewModel.IsImporting)
{
cache.Remove(model.Id);
}
return cachedViewModel;
}
var newCard = dialogFactory.Get<CheckpointBrowserCardViewModel>(vm =>
{
vm.CivitModel = model;
vm.OnDownloadStart = viewModel =>
{
if (cache.Get(viewModel.CivitModel.Id) != null)
return;
cache.Add(viewModel.CivitModel.Id, viewModel);
};
return vm;
});
Observable
.FromEventPattern<PropertyChangedEventArgs>(this, nameof(PropertyChanged))
.Where(x => x.EventArgs.PropertyName == nameof(CurrentPageNumber))
.Throttle(TimeSpan.FromMilliseconds(250))
.Select<EventPattern<PropertyChangedEventArgs>, int>(_ => CurrentPageNumber)
.Where(page => page <= TotalPages && page > 0)
.ObserveOn(SynchronizationContext.Current)
.Subscribe(_ => TrySearchAgain(false).SafeFireAndForget(), err => Logger.Error(err));
return newCard;
})
.Filter(FilterModelCardsPredicate)
.Bind(ModelCards)
.Subscribe();
EventManager.Instance.NavigateAndFindCivitModelRequested += OnNavigateAndFindCivitModelRequested;
}
@ -171,7 +176,7 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
return;
SearchQuery = $"$#{e}";
SearchModelsCommand.ExecuteAsync(null).SafeFireAndForget();
SearchModelsCommand.ExecuteAsync(false).SafeFireAndForget();
}
public override void OnLoaded()
@ -223,7 +228,7 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
/// <summary>
/// Background update task
/// </summary>
private async Task CivitModelQuery(CivitModelsRequest request)
private async Task CivitModelQuery(CivitModelsRequest request, bool isInfiniteScroll = false)
{
var timer = Stopwatch.StartNew();
var queryText = request.Query;
@ -279,12 +284,14 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
if (cacheNew)
{
Logger.Debug("New cache entry, updating model cards");
UpdateModelCards(models, modelsResponse.Metadata);
UpdateModelCards(models, isInfiniteScroll);
}
else
{
Logger.Debug("Cache entry already exists, not updating model cards");
}
NextPageCursor = modelsResponse.Metadata?.NextCursor;
}
catch (OperationCanceledException)
{
@ -327,60 +334,22 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
/// <summary>
/// Updates model cards using api response object.
/// </summary>
private void UpdateModelCards(IEnumerable<CivitModel>? models, CivitMetadata? metadata)
private void UpdateModelCards(List<CivitModel>? models, bool addCards = false)
{
if (models is null)
{
ModelCards?.Clear();
ModelCache?.Clear();
}
else
{
var updateCards = models
.Select(model =>
{
var cachedViewModel = cache.Get(model.Id);
if (cachedViewModel != null)
{
if (!cachedViewModel.IsImporting)
{
cache.Remove(model.Id);
}
return cachedViewModel;
}
var newCard = dialogFactory.Get<CheckpointBrowserCardViewModel>(vm =>
{
vm.CivitModel = model;
vm.OnDownloadStart = viewModel =>
{
if (cache.Get(viewModel.CivitModel.Id) != null)
return;
cache.Add(viewModel.CivitModel.Id, viewModel);
};
return vm;
});
return newCard;
})
.ToList();
allModelCards = updateCards;
var filteredCards = updateCards.Where(FilterModelCardsPredicate);
if (SortMode == CivitSortMode.Installed)
if (!addCards)
{
filteredCards = filteredCards.OrderByDescending(x => x.UpdateCardText == "Update Available");
ModelCache.Clear();
}
ModelCards = new ObservableCollection<CheckpointBrowserCardViewModel>(filteredCards);
ModelCache.AddOrUpdate(models);
}
TotalPages = metadata?.TotalPages ?? 1;
CanGoToFirstPage = CurrentPageNumber != 1;
CanGoToPreviousPage = CurrentPageNumber > 1;
CanGoToNextPage = CurrentPageNumber < TotalPages;
CanGoToLastPage = CurrentPageNumber != TotalPages;
// Status update
ShowMainLoadingSpinner = false;
IsIndeterminate = false;
@ -390,15 +359,15 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
private string previousSearchQuery = string.Empty;
[RelayCommand]
private async Task SearchModels()
private async Task SearchModels(bool isInfiniteScroll = false)
{
var timer = Stopwatch.StartNew();
if (SearchQuery != previousSearchQuery)
if (SearchQuery != previousSearchQuery || !isInfiniteScroll)
{
// Reset page number
CurrentPageNumber = 1;
previousSearchQuery = SearchQuery;
NextPageCursor = null;
}
// Build request
@ -407,10 +376,14 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
Limit = MaxModelsPerPage,
Nsfw = "true", // Handled by local view filter
Sort = SortMode,
Period = SelectedPeriod,
Page = CurrentPageNumber
Period = SelectedPeriod
};
if (NextPageCursor != null)
{
modelRequest.Cursor = NextPageCursor;
}
if (SelectedModelType != CivitModelType.All)
{
modelRequest.Types = [SelectedModelType];
@ -516,14 +489,15 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
modelRequest.GetHashCode(),
elapsed.TotalSeconds
);
UpdateModelCards(cachedQuery.Items, cachedQuery.Metadata);
NextPageCursor = cachedQuery.Metadata?.NextCursor;
UpdateModelCards(cachedQuery.Items, isInfiniteScroll);
// Start remote query (background mode)
// Skip when last query was less than 2 min ago
var timeSinceCache = DateTimeOffset.UtcNow - cachedQuery.InsertedAt;
if (timeSinceCache?.TotalMinutes >= 2)
{
CivitModelQuery(modelRequest).SafeFireAndForget();
CivitModelQuery(modelRequest, isInfiniteScroll).SafeFireAndForget();
Logger.Debug(
"Cached query was more than 2 minutes ago ({Seconds:F0} s), updating cache with remote query",
timeSinceCache.Value.TotalSeconds
@ -534,54 +508,23 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
{
// Not cached, wait for remote query
ShowMainLoadingSpinner = true;
await CivitModelQuery(modelRequest);
await CivitModelQuery(modelRequest, isInfiniteScroll);
}
UpdateResultsText();
}
public void FirstPage()
{
CurrentPageNumber = 1;
}
public void PreviousPage()
{
if (CurrentPageNumber == 1)
return;
CurrentPageNumber--;
}
public void NextPage()
{
if (CurrentPageNumber == TotalPages)
return;
CurrentPageNumber++;
}
public void LastPage()
{
CurrentPageNumber = TotalPages;
}
public void ClearSearchQuery()
{
SearchQuery = string.Empty;
}
partial void OnShowNsfwChanged(bool value)
public async Task LoadNextPageAsync()
{
settingsManager.Transaction(s => s.ModelBrowserNsfwEnabled, value);
// ModelCardsView?.Refresh();
var updateCards = allModelCards.Where(FilterModelCardsPredicate);
ModelCards = new ObservableCollection<CheckpointBrowserCardViewModel>(updateCards);
if (!HasSearched)
return;
UpdateResultsText();
if (NextPageCursor != null)
{
await SearchModelsCommand.ExecuteAsync(true);
}
}
partial void OnSelectedPeriodChanged(CivitPeriod value)
@ -596,6 +539,7 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
SelectedBaseModelType
)
);
NextPageCursor = null;
}
partial void OnSortModeChanged(CivitSortMode value)
@ -610,6 +554,7 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
SelectedBaseModelType
)
);
NextPageCursor = null;
}
partial void OnSelectedModelTypeChanged(CivitModelType value)
@ -624,6 +569,7 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
SelectedBaseModelType
)
);
NextPageCursor = null;
}
partial void OnSelectedBaseModelTypeChanged(string value)
@ -638,6 +584,7 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
value
)
);
NextPageCursor = null;
}
private async Task TrySearchAgain(bool shouldUpdatePageNumber = true)
@ -648,18 +595,17 @@ public partial class CivitAiBrowserViewModel : TabViewModelBase
if (shouldUpdatePageNumber)
{
CurrentPageNumber = 1;
NextPageCursor = null;
}
// execute command instead of calling method directly so that the IsRunning property gets updated
await SearchModelsCommand.ExecuteAsync(null);
await SearchModelsCommand.ExecuteAsync(false);
}
private void UpdateResultsText()
{
NoResultsFound = ModelCards?.Count <= 0;
NoResultsText =
allModelCards.Count > 0 ? $"{allModelCards.Count} results hidden by filters" : "No results found";
NoResultsText = "No results found";
}
public override string Header => Resources.Label_CivitAi;

68
StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml

@ -16,6 +16,7 @@
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
xmlns:helpers="clr-namespace:StabilityMatrix.Avalonia.Helpers"
xmlns:controls1="clr-namespace:Avalonia.Labs.Controls;assembly=Avalonia.Labs.Controls"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
d:DataContext="{x:Static designData:DesignData.CivitAiBrowserViewModel}"
d:DesignHeight="700"
d:DesignWidth="800"
@ -71,6 +72,7 @@
</UserControl.Styles>
<UserControl.Resources>
<system:Boolean x:Key="False">False</system:Boolean>
<converters:KiloFormatterStringConverter x:Key="KiloFormatterConverter"/>
<DataTemplate x:Key="CivitModelTemplate" DataType="{x:Type checkpointBrowser:CheckpointBrowserCardViewModel}">
<Border
@ -336,7 +338,7 @@
<TextBlock
Margin="4,0"
VerticalAlignment="Center"
Text="{Binding CivitModel.ModelVersionStats.FavoriteCount, Converter={StaticResource KiloFormatterConverter}}" />
Text="{Binding CivitModel.Stats.ThumbsUpCount, Converter={StaticResource KiloFormatterConverter}}" />
<avalonia:Icon Margin="4,0" Value="fa-solid fa-download" />
<TextBlock
@ -402,6 +404,7 @@
VerticalAlignment="Stretch"
Classes="accent"
Command="{Binding SearchModelsCommand}"
CommandParameter="{StaticResource False}"
IsDefault="True">
<Grid>
<controls:ProgressRing
@ -472,57 +475,18 @@
</ItemsRepeater.Layout>
</ItemsRepeater>
</ScrollViewer>
<TextBlock
Grid.Row="2"
Margin="8,8"
VerticalAlignment="Center"
Text="{x:Static lang:Resources.Label_DataProvidedByCivitAi}" />
<StackPanel Grid.Row="2"
HorizontalAlignment="Center"
IsVisible="{Binding HasSearched}"
Margin="0,8,0,8"
Orientation="Horizontal">
<Button
Margin="0,0,8,0"
Command="{Binding FirstPage}"
IsEnabled="{Binding CanGoToFirstPage}"
ToolTip.Tip="{x:Static lang:Resources.Label_FirstPage}">
<avalonia:Icon Value="fa-solid fa-backward-fast" />
</Button>
<Button
Margin="0,0,16,0"
Command="{Binding PreviousPage}"
IsEnabled="{Binding CanGoToPreviousPage}"
ToolTip.Tip="{x:Static lang:Resources.Label_PreviousPage}">
<avalonia:Icon Value="fa-solid fa-caret-left" />
</Button>
<TextBlock Margin="8,0,4,0" TextAlignment="Center"
Text="{x:Static lang:Resources.Label_Page}"
VerticalAlignment="Center"/>
<ui:NumberBox Value="{Binding CurrentPageNumber, FallbackValue=1}"
VerticalAlignment="Center"
SpinButtonPlacementMode="Hidden"
TextAlignment="Center"/>
<TextBlock Margin="4,0,8,0" VerticalAlignment="Center">
<Run Text="/"/>
<Run Text="{Binding TotalPages, FallbackValue=5}"/>
</TextBlock>
<Button
Margin="16,0,8,0"
Command="{Binding NextPage}"
IsEnabled="{Binding CanGoToNextPage}"
ToolTip.Tip="{x:Static lang:Resources.Label_NextPage}">
<avalonia:Icon Value="fa-solid fa-caret-right" />
</Button>
<Button
Command="{Binding LastPage}"
IsEnabled="{Binding CanGoToLastPage}"
ToolTip.Tip="{x:Static lang:Resources.Label_LastPage}">
<avalonia:Icon Value="fa-solid fa-forward-fast" />
</Button>
</StackPanel>
<TextBlock Grid.Row="2" Text="End of results"
TextAlignment="Center"
Margin="0,0,0,8">
<TextBlock.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="HasSearched"/>
<Binding Path="NextPageCursor"
Converter="{x:Static StringConverters.IsNullOrEmpty}"/>
</MultiBinding>
</TextBlock.IsVisible>
</TextBlock>
<TextBlock
Grid.Row="0"

16
StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml.cs

@ -1,8 +1,11 @@
using System.Diagnostics;
using System;
using System.Diagnostics;
using AsyncAwaitBestPractices;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Core.Attributes;
using CivitAiBrowserViewModel = StabilityMatrix.Avalonia.ViewModels.CheckpointBrowser.CivitAiBrowserViewModel;
@ -26,8 +29,15 @@ public partial class CivitAiBrowserPage : UserControlBase
if (sender is not ScrollViewer scrollViewer)
return;
var isAtEnd = scrollViewer.Offset == scrollViewer.ScrollBarMaximum;
Debug.WriteLine($"IsAtEnd: {isAtEnd}");
if (scrollViewer.Offset.Y == 0)
return;
var isAtEnd = Math.Abs(scrollViewer.Offset.Y - scrollViewer.ScrollBarMaximum.Y) < 1f;
if (isAtEnd && DataContext is IInfinitelyScroll scroll)
{
scroll.LoadNextPageAsync().SafeFireAndForget();
}
}
private void InputElement_OnKeyDown(object? sender, KeyEventArgs e)

14
StabilityMatrix.Core/Models/Api/CivitMetadata.cs

@ -2,24 +2,26 @@
namespace StabilityMatrix.Core.Models.Api;
public class CivitMetadata
{
[JsonPropertyName("totalItems")]
public int TotalItems { get; set; }
[JsonPropertyName("currentPage")]
public int CurrentPage { get; set; }
[JsonPropertyName("pageSize")]
public int PageSize { get; set; }
[JsonPropertyName("totalPages")]
public int TotalPages { get; set; }
[JsonPropertyName("nextPage")]
public string? NextPage { get; set; }
[JsonPropertyName("prevPage")]
public string? PrevPage { get; set; }
[JsonPropertyName("nextCursor")]
public string? NextCursor { get; set; }
}

5
StabilityMatrix.Core/Models/Api/CivitModelStats.cs

@ -6,7 +6,10 @@ public class CivitModelStats : CivitStats
{
[JsonPropertyName("favoriteCount")]
public int FavoriteCount { get; set; }
[JsonPropertyName("commentCount")]
public int CommentCount { get; set; }
[JsonPropertyName("thumbsUpCount")]
public int ThumbsUpCount { get; set; }
}

60
StabilityMatrix.Core/Models/Api/CivitModelsRequest.cs

@ -2,7 +2,6 @@
namespace StabilityMatrix.Core.Models.Api;
public class CivitModelsRequest
{
/// <summary>
@ -10,99 +9,99 @@ public class CivitModelsRequest
/// </summary>
[AliasAs("limit")]
public int? Limit { get; set; }
/// <summary>
/// The page from which to start fetching models
/// </summary>
[AliasAs("page")]
public int? Page { get; set; }
/// <summary>
/// Search query to filter models by name
/// </summary>
[AliasAs("query")]
public string? Query { get; set; }
/// <summary>
/// Search query to filter models by tag
/// </summary>
[AliasAs("tag")]
public string? Tag { get; set; }
/// <summary>
/// Search query to filter models by user
/// </summary>
[AliasAs("username")]
public string? Username { get; set; }
/// <summary>
/// The type of model you want to filter with. If none is specified, it will return all types
/// </summary>
[AliasAs("types")]
public CivitModelType[]? Types { get; set; }
/// <summary>
/// The order in which you wish to sort the results
/// </summary>
[AliasAs("sort")]
public CivitSortMode? Sort { get; set; }
/// <summary>
/// The time frame in which the models will be sorted
/// </summary>
[AliasAs("period")]
public CivitPeriod? Period { get; set; }
/// <summary>
/// The rating you wish to filter the models with. If none is specified, it will return models with any rating
/// </summary>
[AliasAs("rating")]
public int? Rating { get; set; }
/// <summary>
/// Filter to models that require or don't require crediting the creator
/// <remarks>Requires Authentication</remarks>
/// </summary>
[AliasAs("favorites")]
public bool? Favorites { get; set; }
/// <summary>
/// Filter to hidden models of the authenticated user
/// <remarks>Requires Authentication</remarks>
/// </summary>
[AliasAs("hidden")]
public bool? Hidden { get; set; }
/// <summary>
/// Only include the primary file for each model (This will use your preferred format options if you use an API token or session cookie)
/// </summary>
[AliasAs("primaryFileOnly")]
public bool? PrimaryFileOnly { get; set; }
/// <summary>
/// Filter to models that allow or don't allow creating derivatives
/// </summary>
[AliasAs("allowDerivatives")]
public bool? AllowDerivatives { get; set; }
/// <summary>
/// Filter to models that allow or don't allow derivatives to have a different license
/// </summary>
[AliasAs("allowDifferentLicenses")]
public bool? AllowDifferentLicenses { get; set; }
/// <summary>
/// Filter to models based on their commercial permissions
/// </summary>
[AliasAs("allowCommercialUse")]
public CivitCommercialUse? AllowCommercialUse { get; set; }
/// <summary>
/// If false, will return safer images and hide models that don't have safe images
/// </summary>
[AliasAs("nsfw")]
public string? Nsfw { get; set; }
/// <summary>
/// options: <br/>
/// SD 1.4 <br/>
@ -117,22 +116,25 @@ public class CivitModelsRequest
/// </summary>
[AliasAs("baseModels")]
public string? BaseModel { get; set; }
[AliasAs("ids")]
public string CommaSeparatedModelIds { get; set; }
[AliasAs("cursor")]
public string? Cursor { get; set; }
public override string ToString()
{
return $"Page: {Page}, " +
$"Query: {Query}, " +
$"Tag: {Tag}, " +
$"Username: {Username}, " +
$"Types: {Types}, " +
$"Sort: {Sort}, " +
$"Period: {Period}, " +
$"Rating: {Rating}, " +
$"Nsfw: {Nsfw}, " +
$"BaseModel: {BaseModel}, " +
$"CommaSeparatedModelIds: {CommaSeparatedModelIds}";
return $"Page: {Page}, "
+ $"Query: {Query}, "
+ $"Tag: {Tag}, "
+ $"Username: {Username}, "
+ $"Types: {Types}, "
+ $"Sort: {Sort}, "
+ $"Period: {Period}, "
+ $"Rating: {Rating}, "
+ $"Nsfw: {Nsfw}, "
+ $"BaseModel: {BaseModel}, "
+ $"CommaSeparatedModelIds: {CommaSeparatedModelIds}";
}
}

Loading…
Cancel
Save