PRE-ALPHA: This package is under active development and APIs may change significantly. Utility tools for CivitaiSharp including file hashing (BLAKE3, SHA256, SHA512, CRC32), download management with pattern-based file organization, HTML-to-Markdown/PlainText parsing for model descriptions, and file format detection. Builds on CivitaiSharp.Core. CivitaiSharp is an independent open-source project and is not affiliated with, endorsed by, or associated with Civitai.com or Civitai, Inc.
$ dotnet add package CivitaiSharp.Tools
A modern, lightweight, and AOT-ready .NET 10 client library for all things Civitai.com.
Note: CivitaiSharp is currently in Alpha. APIs, features, and stability are subject to change.
| Package | Status | Description |
|---|---|---|
| CivitaiSharp.Core | Alpha | Public API client for models, images, tags, and creators |
| CivitaiSharp.Sdk | Alpha | Generator/Orchestration API client for image generation jobs |
| CivitaiSharp.Tools | Alpha | Utilities for downloads, file hashing, and HTML parsing |
Note: All packages are currently in Alpha. APIs may change between minor versions.
Warning: CivitaiSharp.Sdk is not fully tested and should not be used in production environments. Use at your own risk.
Install via NuGet:
# Core library - API client for models, images, tags, and creators
dotnet add package CivitaiSharp.Core --prerelease
# SDK - Image generation and job management (requires API token)
dotnet add package CivitaiSharp.Sdk --prerelease
# Tools - File hashing, downloads, and HTML parsing
dotnet add package CivitaiSharp.Tools --prerelease
The simplest way to get started with CivitaiSharp.Core:
using CivitaiSharp.Core;
using CivitaiSharp.Core.Extensions;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddCivitaiApi();
await using var provider = services.BuildServiceProvider();
var client = provider.GetRequiredService<IApiClient>();
var result = await client.Models.ExecuteAsync();
if (result.IsSuccess)
{
foreach (var model in result.Value.Items)
Console.WriteLine(model.Name);
}
using CivitaiSharp.Core;
using CivitaiSharp.Core.Extensions;
using CivitaiSharp.Core.Models;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddCivitaiApi(options =>
{
options.TimeoutSeconds = 120;
options.StrictJsonParsing = true;
});
await using var provider = services.BuildServiceProvider();
var client = provider.GetRequiredService<IApiClient>();
var result = await client.Models
.WhereType(ModelType.Checkpoint)
.WhereNsfw(false)
.OrderBy(ModelSort.MostDownloaded)
.ExecuteAsync(resultsLimit: 10);
if (result.IsSuccess)
{
foreach (var model in result.Value.Items)
Console.WriteLine($"{model.Name} by {model.Creator?.Username}");
}
else
{
Console.WriteLine($"Error: {result.ErrorInfo.Message}");
}
CivitaiSharp reads configuration from the CivitaiSharp section by default.
Minimal Configuration (appsettings.json)
{
"CivitaiSharp": {
"Api": {},
"Sdk": {}
}
}
All settings have sensible defaults, so an empty section is valid.
Full Configuration (appsettings.json)
{
"CivitaiSharp": {
"Api": {
"Key": null,
"BaseUrl": "https://civitai.com",
"Version": "v1",
"TimeoutSeconds": 30
},
"Sdk": {
"Key": null,
"BaseUrl": "https://orchestration.civitai.com",
"Version": "v2",
"TimeoutSeconds": 30
}
}
}
| Property | Type | Default | Description |
|---|---|---|---|
Api.Key | string? | null | Optional API key for authenticated requests |
Api.BaseUrl | string | https://civitai.com | Base URL for the Civitai API |
Api.Version | string | v1 | API version path segment |
Api.TimeoutSeconds | int | 30 | HTTP request timeout (1-300 seconds) |
| Property | Type | Default | Description |
|---|---|---|---|
Sdk.Key | string? | null | API token for SDK operations (required) |
Sdk.BaseUrl | string | https://orchestration.civitai.com | Base URL for the Generator/Orchestration API |
Sdk.Version | string | v2 | API version path segment |
Sdk.TimeoutSeconds | int | 30 | HTTP request timeout (1-300 seconds) |
Authentication Note: The Core library can query public endpoints (models, images, tags, creators) without an API key. An API key is only required for authenticated features like favorites, hidden models, and higher rate limits. NSFW Content: Setting
WhereNsfw(true)on models or using certainImageNsfwLevelvalues (Mature, X) requires authentication. The SDK always requires an API token for all operations.
Configuration with IConfiguration
using CivitaiSharp.Core.Extensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var services = new ServiceCollection();
services.AddCivitaiApi(configuration);
// Or with a custom section name:
// services.AddCivitaiApi(configuration, "MyCustomSection");
await using var provider = services.BuildServiceProvider();
CivitaiSharp.Core provides fluent builders for each endpoint. Each builder is immutable and thread-safe.
Models Endpoint
// Get all models (default query)
var result = await client.Models.ExecuteAsync();
// Get a specific model by ID
var result = await client.Models.GetByIdAsync(12345);
if (result.IsSuccess)
Console.WriteLine($"Model: {result.Value.Name}");
// Get the first matching model (efficient single-item retrieval)
var result = await client.Models
.WhereName("SDXL")
.FirstOrDefaultAsync();
if (result is { IsSuccess: true, Value: not null })
Console.WriteLine($"Found: {result.Value.Name}");
// Search by name
var result = await client.Models
.WhereName("SDXL")
.ExecuteAsync();
// Filter by type and sort
var result = await client.Models
.WhereType(ModelType.Checkpoint)
.OrderBy(ModelSort.MostDownloaded)
.ExecuteAsync(resultsLimit: 25);
// Filter by tag
var result = await client.Models
.WhereTag("anime")
.WhereNsfw(false)
.ExecuteAsync();
// Filter by creator
var result = await client.Models
.WhereUsername("Mewyk")
.OrderBy(ModelSort.Newest)
.ExecuteAsync();
// Filter by base model (string value, e.g., "SDXL 1.0", "SD 1.5", "Flux.1 D")
var result = await client.Models
.WhereBaseModel("SDXL 1.0")
.WhereType(ModelType.Lora)
.ExecuteAsync();
// Filter by multiple base models
var result = await client.Models
.WhereBaseModels("SDXL 1.0", "Pony")
.ExecuteAsync();
// Filter by specific model IDs (ignored if query is also provided)
var result = await client.Models
.WhereIds(12345, 67890, 11111)
.ExecuteAsync();
// Get a specific model version by version ID
var versionResult = await client.Models.GetByVersionIdAsync(130072);
if (versionResult.IsSuccess)
{
Console.WriteLine($"Version: {versionResult.Value.Name}");
Console.WriteLine($"AIR: {versionResult.Value.AirIdentifier}");
}
// Get a model version by file hash (SHA256, AutoV2, CRC32, etc.)
var hashResult = await client.Models.GetByVersionHashAsync("ABC123DEF456");
if (hashResult.IsSuccess)
{
Console.WriteLine($"Found: {hashResult.Value.Model?.Name}");
Console.WriteLine($"AIR: {hashResult.Value.AirIdentifier}");
}
Images Endpoint
// Get all images (default query)
var result = await client.Images.ExecuteAsync();
// Get the first matching image
var result = await client.Images
.WhereModelId(12345)
.FirstOrDefaultAsync();
if (result is { IsSuccess: true, Value: not null })
Console.WriteLine($"Image URL: {result.Value.Url}");
// Filter by model ID
var result = await client.Images
.WhereModelId(12345)
.ExecuteAsync();
// Filter by model version ID
var result = await client.Images
.WhereModelVersionId(67890)
.OrderBy(ImageSort.Newest)
.ExecuteAsync();
// Filter by username
var result = await client.Images
.WhereUsername("Mewyk")
.WhereNsfwLevel(ImageNsfwLevel.None)
.ExecuteAsync(resultsLimit: 50);
// Filter by post ID
var result = await client.Images
.WherePostId(11111)
.ExecuteAsync();
Tags Endpoint
// Get all tags (default query)
var result = await client.Tags.ExecuteAsync();
// Search tags by name
var result = await client.Tags
.WhereName("portrait")
.ExecuteAsync(resultsLimit: 100);
Creators Endpoint
// Get all creators (default query)
var result = await client.Creators.ExecuteAsync();
// Search creators by name
var result = await client.Creators
.WhereName("Mewyk")
.ExecuteAsync(resultsLimit: 20);
// Page-based pagination (Models, Tags, and Creators use pages, not cursors)
var result = await client.Creators
.WithPageIndex(2)
.ExecuteAsync(resultsLimit: 50);
Pagination
// Cursor-based pagination (Images only)
string? cursor = null;
var allImages = new List<Image>();
do
{
result = await client.Images
.WhereModelId(12345)
.ExecuteAsync(resultsLimit: 100, cursor: cursor);
if (!result.IsSuccess)
break;
allImages.AddRange(result.Value.Items);
cursor = result.Value.Metadata?.NextCursor;
} while (cursor is not null);
// Page-based pagination (Models, Tags, Creators)
var page1 = await client.Models.WithPageIndex(1).ExecuteAsync();
var page2 = await client.Tags.WithPageIndex(2).ExecuteAsync();
var page3 = await client.Creators.WithPageIndex(3).ExecuteAsync();
Tools - File Hashing
using CivitaiSharp.Tools.Hashing;
using CivitaiSharp.Tools.Extensions;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddCivitaiDownloads();
await using var provider = services.BuildServiceProvider();
var hashingService = provider.GetRequiredService<IFileHashingService>();
// Compute SHA256 hash
var result = await hashingService.ComputeHashAsync(
@"C:\Models\model.safetensors",
HashAlgorithm.Sha256);
if (result.IsSuccess)
{
Console.WriteLine($"Hash: {result.Value.Hash}");
Console.WriteLine($"Size: {result.Value.FileSize:N0} bytes");
}
// Supported algorithms: Sha256, Sha512, Blake3, Crc32
var blake3Result = await hashingService.ComputeHashAsync(filePath, HashAlgorithm.Blake3);
Tools - Downloading Files
using CivitaiSharp.Core;
using CivitaiSharp.Core.Extensions;
using CivitaiSharp.Tools.Downloads;
using CivitaiSharp.Tools.Extensions;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddCivitaiApi();
services.AddCivitaiDownloads(options =>
{
options.Images.BaseDirectory = @"C:\Downloads\Images";
options.Images.PathPattern = "{Username}/{Id}.{Extension}";
options.Models.BaseDirectory = @"C:\Models";
options.Models.PathPattern = "{ModelType}/{ModelName}/{FileName}";
options.Models.VerifyHash = true;
});
await using var provider = services.BuildServiceProvider();
var apiClient = provider.GetRequiredService<IApiClient>();
var downloadService = provider.GetRequiredService<IDownloadService>();
// Download a model file with hash verification
var modelResult = await apiClient.Models.GetByIdAsync(4201);
if (modelResult.IsSuccess)
{
var version = modelResult.Value.ModelVersions?.FirstOrDefault();
var file = version?.Files?.FirstOrDefault(f => f.Primary == true);
if (file is not null && version is not null)
{
var downloadResult = await downloadService.DownloadAsync(file, version);
if (downloadResult.IsSuccess)
{
Console.WriteLine($"Downloaded: {downloadResult.Value.FilePath}");
Console.WriteLine($"Verified: {downloadResult.Value.IsVerified}");
}
}
}
Tools - HTML Parsing
using CivitaiSharp.Tools.Parsing;
// Convert HTML description to Markdown
var markdown = HtmlParser.ToMarkdown(model.Description);
// Convert to plain text
var plainText = HtmlParser.ToPlainText(model.Description);
// Or use extension methods on Model/ModelVersion
var markdown = model.GetDescriptionAsMarkdown();
var plainText = modelVersion.GetDescriptionAsPlainText();
SDK - Image Generation (Jobs)
using CivitaiSharp.Sdk;
using CivitaiSharp.Sdk.Extensions;
using CivitaiSharp.Sdk.Air;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddCivitaiSdk(options =>
{
options.Key = "your-api-token"; // Required for SDK
});
await using var provider = services.BuildServiceProvider();
var sdkClient = provider.GetRequiredService<ISdkClient>();
// Create an image generation job
var model = new AirIdentifier("sdxl", AirAssetType.Checkpoint, "civitai", 4201, 130072);
var result = await sdkClient.Jobs
.CreateImage()
.WithAir(model)
.WithPositivePrompt("a beautiful sunset over mountains, highly detailed")
.WithNegativePrompt("blurry, low quality")
.WithDimensions(1024, 1024)
.WithSteps(30)
.WithConfigurationScale(7.5m)
.WithSeed(12345)
.ExecuteAsync();
if (result is Result<JobStatusCollection>.Success success)
{
var token = success.Data.Token;
Console.WriteLine($"Job submitted: {token}");
// Query job status
var statusResult = await sdkClient.Jobs.Query
.WithDetailed()
.GetByTokenAsync(token);
if (statusResult is Result<JobStatusCollection>.Success statusSuccess)
{
foreach (var job in statusSuccess.Data.JobsList)
{
var status = job.Scheduled ? "Processing" : "Complete";
Console.WriteLine($"Job {job.JobId}: {status}");
}
}
}
// Wait for job completion (blocks up to ~10 minutes)
var completedResult = await sdkClient.Jobs.Query
.WithWait()
.WithDetailed()
.GetByTokenAsync(token);
// Query jobs by custom properties
var queryResult = await sdkClient.Jobs.Query
.WhereProperty("userId", JsonSerializer.SerializeToElement("12345"))
.WhereProperty("environment", JsonSerializer.SerializeToElement("production"))
.ExecuteAsync();
Use all available parameters for fine-tuned control:
var baseCheckpoint = new AirIdentifier("sdxl", AirAssetType.Checkpoint, "civitai", 4201, 130072);
var comprehensiveJob = await sdkClient.Jobs
.CreateImage()
.WithAir(baseCheckpoint)
.WithPositivePrompt("masterpiece, best quality, professional photo of a cyberpunk cityscape at night, neon lights, rain-slicked streets, highly detailed architecture")
.WithNegativePrompt("blurry, low quality, bad anatomy, watermark, signature, jpeg artifacts, worst quality")
.WithDimensions(1024, 1536)
.WithSteps(35)
.WithConfigurationScale(8.0m)
.WithScheduler(Scheduler.DpmPlusPlus2MKarras)
.WithSeed(987654321)
.WithClipSkip(2)
.WithQuantity(4) // Generate 4 variations
.WithPriority(Priority.Default)
.WithCallbackUrl("https://example.tld/webhook/image-complete")
.WithRetries(3)
.WithTimeout(TimeSpan.FromMinutes(10))
.ExecuteAsync();
if (comprehensiveJob is Result<JobStatusCollection>.Success jobSuccess)
{
Console.WriteLine($"Submitted {jobSuccess.Data.JobsList.Count} jobs with token: {jobSuccess.Data.Token}");
}
Combine multiple LoRAs with different strengths for enhanced control:
var baseCheckpoint = new AirIdentifier("sdxl", AirAssetType.Checkpoint, "civitai", 4201, 130072);
var characterLoRA = new AirIdentifier("sdxl", AirAssetType.Lora, "civitai", 328553, 368189);
var styleLoRA = new AirIdentifier("sdxl", AirAssetType.Lora, "civitai", 234567, 456789);
var lightingLoRA = new AirIdentifier("sdxl", AirAssetType.Lora, "civitai", 345678, 567890);
var multiLoRAJob = await sdkClient.Jobs
.CreateImage()
.WithAir(baseCheckpoint)
.WithPositivePrompt("anime character portrait, cinematic lighting, detailed face")
.WithNegativePrompt("blurry, low quality, bad hands")
.WithDimensions(1024, 1024)
.WithSteps(30)
.WithConfigurationScale(7.5m)
// Character LoRA with high strength
.WithAdditionalNetwork(characterLoRA, NetworkBuilder.Create()
.WithStrength(0.9m)
.WithTriggerWord("anime_style")
.Build())
// Style LoRA with medium strength
.WithAdditionalNetwork(styleLoRA, NetworkBuilder.Create()
.WithStrength(0.6m)
.WithTriggerWord("cinematic")
.Build())
// Lighting LoRA with subtle strength
.WithAdditionalNetwork(lightingLoRA, NetworkBuilder.Create()
.WithStrength(0.4m)
.Build())
.ExecuteAsync();
if (multiLoRAJob is Result<JobStatusCollection>.Success loraSuccess)
{
Console.WriteLine($"Multi-LoRA job submitted: {loraSuccess.Data.Token}");
}
Combine ControlNet for pose guidance with LoRAs for style:
var baseCheckpoint = new AirIdentifier("sdxl", AirAssetType.Checkpoint, "civitai", 4201, 130072);
var styleLoRA = new AirIdentifier("sdxl", AirAssetType.Lora, "civitai", 234567, 456789);
var detailLoRA = new AirIdentifier("sdxl", AirAssetType.Lora, "civitai", 345678, 567890);
var controlNetJob = await sdkClient.Jobs
.CreateImage()
.WithAir(baseCheckpoint)
.WithPositivePrompt("professional photo of a person in business attire, studio lighting, sharp focus")
.WithNegativePrompt("blurry, low quality, bad anatomy, deformed")
.WithDimensions(768, 1024)
.WithSteps(35)
.WithConfigurationScale(7.0m)
// ControlNet for pose guidance
.WithControlNet(ControlNetBuilder.Create()
.WithImageUrl("https://example.tld/reference-pose.png")
.WithPreprocessor(ControlNetPreprocessor.Canny)
.WithWeight(1.0m)
.WithStartStep(0.0m)
.WithEndStep(0.8m)
.Build())
// Style LoRA
.WithAdditionalNetwork(styleLoRA, NetworkBuilder.Create()
.WithStrength(0.7m)
.WithTriggerWord("professional_photo")
.Build())
// Detail enhancement LoRA
.WithAdditionalNetwork(detailLoRA, NetworkBuilder.Create()
.WithStrength(0.5m)
.Build())
.ExecuteAsync();
if (controlNetJob is Result<JobStatusCollection>.Success controlNetSuccess)
{
Console.WriteLine($"ControlNet+LoRA job submitted: {controlNetSuccess.Data.Token}");
// Wait for completion
var completedJob = await sdkClient.Jobs.Query
.WithWait()
.WithDetailed()
.GetByTokenAsync(controlNetSuccess.Data.Token);
if (completedJob is Result<JobStatusCollection>.Success completed)
{
foreach (var job in completed.Data.JobsList)
{
if (job.Result?.BlobUrl is string blobUrl)
{
Console.WriteLine($"Generated image: {blobUrl}");
}
}
}
}
SDK - Coverage Service
using CivitaiSharp.Sdk;
using CivitaiSharp.Sdk.Air;
// Check if a model is available before submitting a job
var model = new AirIdentifier("sdxl", AirAssetType.Checkpoint, "civitai", 4201, 130072);
var lora = new AirIdentifier("sdxl", AirAssetType.Lora, "civitai", 328553, 368189);
// Check single model
var coverageResult = await sdkClient.Coverage.GetAsync(model);
if (coverageResult is Result<ProviderAssetAvailability>.Success coverage)
{
Console.WriteLine($"Availability: {coverage.Data.Availability}");
Console.WriteLine($"Workers: {coverage.Data.Workers}");
if (coverage.Data.Availability == AvailabilityStatus.Available)
{
Console.WriteLine($"Model is available with {coverage.Data.Workers} workers");
}
}
// Check multiple resources at once
var resources = new[] { model, lora };
var batchResult = await sdkClient.Coverage.GetAsync(resources);
if (batchResult is Result<IReadOnlyDictionary<AirIdentifier, ProviderAssetAvailability>>.Success batch)
{
foreach (var (resource, availability) in batch.Data)
{
Console.WriteLine($"{resource}: {availability.Availability} (Workers: {availability.Workers})");
}
}
SDK - Usage Service
using CivitaiSharp.Sdk;
// Get current account usage
var usageResult = await sdkClient.Usage.GetConsumptionAsync();
if (usageResult is Result<ConsumptionDetails>.Success usage)
{
Console.WriteLine($"Job Count: {usage.Data.JobCount}");
Console.WriteLine($"Total Cost: {usage.Data.TotalCost:F2} Buzz");
Console.WriteLine($"Remaining Credits: {usage.Data.RemainingCredits:F2}");
Console.WriteLine($"Period: {usage.Data.PeriodStart} to {usage.Data.PeriodEnd}");
}
// Get usage for specific date range
var startDate = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var endDate = new DateTime(2025, 1, 31, 23, 59, 59, DateTimeKind.Utc);
var monthlyResult = await sdkClient.Usage.GetConsumptionAsync(startDate, endDate);
if (monthlyResult is Result<ConsumptionDetails>.Success monthly)
{
Console.WriteLine($"January 2025:");
Console.WriteLine($" Jobs: {monthly.Data.JobCount}");
Console.WriteLine($" Total Cost: {monthly.Data.TotalCost:F2} Buzz");
Console.WriteLine($" Remaining Credits: {monthly.Data.RemainingCredits:F2}");
if (monthly.Data.JobCount > 0)
{
Console.WriteLine($" Average Cost: {monthly.Data.AverageCostPerJob:F2} Buzz per job");
}
}
Error Handling
var result = await client.Models.ExecuteAsync();
// Pattern matching
var message = result switch
{
{ IsSuccess: true, Value: var page } => $"Found {page.Items.Count} models",
{ IsSuccess: false, ErrorInfo: var error } => error.Code switch
{
ErrorCode.RateLimited => "Too many requests, please slow down",
ErrorCode.Unauthorized => "Invalid or missing API key",
ErrorCode.NotFound => "Resource not found",
_ => $"Error: {error.Code} - {error.Message}"
}
};
// Traditional approach
if (result.IsSuccess)
{
foreach (var model in result.Value.Items)
Console.WriteLine(model.Name);
}
else
{
Console.WriteLine($"Failed: {result.ErrorInfo.Message}");
}
IHttpClientFactory and Microsoft DIAll CivitaiSharp packages are fully compatible with Native AOT compilation and IL trimming:
System.Text.Json source generators (JsonSerializerContext) for reflection-free serialization<IsAotCompatible>true</IsAotCompatible> and <EnableTrimAnalyzer>true</EnableTrimAnalyzer>To publish with AOT:
dotnet publish -c Release -r win-x64 /p:PublishAot=true
To publish with trimming:
dotnet publish -c Release -r win-x64 /p:PublishTrimmed=true
CivitaiSharp interacts with the Civitai.com API, which has several known quirks. Some are mitigated automatically; others are documented and under investigation.
| Issue | Description |
|---|---|
| Tags endpoint model count | Documented feature, but responses never include this field |
limit=0 parameter | Documented to return all results for various endpoints, but returns an error |
| Semantic errors with HTTP 200 | Errors, Not Found, and others, all return HTTP 200 |
| Endpoint inconsistencies | Intermittent throttling, unreported outages, undocumented rate limits |
| Variable metadata structures | Metadata format varies widely between responses |
| User existence issues | During partial outages, existing users may appear nonexistent |
| Creator endpoint unreliability | See details below |
The /api/v1/creators endpoint is known to experience intermittent reliability issues:
Recommendations:
// Example: Handling Creator endpoint unreliability
var result = await client.Creators.ExecuteAsync(resultsLimit: 10);
if (!result.IsSuccess)
{
// Log the error but continue with degraded functionality
logger.LogWarning("Creator data unavailable: {Error}", result.ErrorInfo.Message);
return GetCachedCreators(); // Fallback to cached data
}
Additional quirks are being tracked and will be addressed in future releases.
CivitaiSharp follows MAJOR.MINOR.PATCH semantic versioning:
| Component | Description |
|---|---|
| MAJOR | Significant, breaking API changes |
| MINOR | New features; may include limited breaking changes unlikely to affect most users |
| PATCH | Backwards-compatible bug fixes and improvements |
Pre-release versions use the format: MAJOR.MINOR.PATCH-alpha.N
Note: While in Alpha (0.x.x), APIs may change between minor versions. Stability is guaranteed from v1.0.0 onwards.
This repository is released under the MIT License.
Contributions are welcome. Please read CONTRIBUTING.md for guidelines.
CivitaiSharp is an independent open-source project and is not affiliated with, sponsored by, endorsed by, or officially associated with Civitai.com or Civitai, Inc. The Civitai name and any related trademarks are the property of their respective owners. Use of these names is for identification purposes only and does not imply any endorsement or partnership.