checkpoint before checking out main

This commit is contained in:
Leonid Pershin
2026-08-20 14:43:00 +03:00
parent 477f8cf6c9
commit 5d46550f12
18 changed files with 429 additions and 64 deletions
@@ -86,6 +86,7 @@ public class SwarmUiClientTests
preset.ClipSkip = 2;
preset.Sampler = "dpmpp_sde";
preset.Scheduler = "karras";
preset.PositiveLoras = [new SwarmUiLoraEntry { Name = "style.safetensors", Weight = 0.75 }];
var profile = preset.ToProfile(PortraitKind.Avatar);
await client.GenerateAsync("a student", "bad", profile, CancellationToken.None);
@@ -93,6 +94,8 @@ public class SwarmUiClientTests
using var document = JsonDocument.Parse(handler.GenerateBody!);
Assert.Equal(-2, document.RootElement.GetProperty("clipstopatlayer").GetInt32());
Assert.False(document.RootElement.TryGetProperty("clipskip", out _));
Assert.Equal("style.safetensors", document.RootElement.GetProperty("loras").GetString());
Assert.Equal("0.75", document.RootElement.GetProperty("loraweights").GetString());
}
[Fact]
@@ -0,0 +1,145 @@
using System.Text.Json;
using HSchool.Server.Game;
namespace HSchool.Server.Tests;
public class SwarmUiLoraFormatterTests
{
[Fact]
public void FormatForApi_SplitsNamesAndWeights()
{
var (names, weights) = SwarmUiLoraFormatter.FormatForApi(
[
new SwarmUiLoraEntry { Name = "style.safetensors", Weight = 0.8 },
new SwarmUiLoraEntry { Name = "face.safetensors", Weight = 1 },
]);
Assert.Equal("style.safetensors,face.safetensors", names);
Assert.Equal("0.8,1", weights);
}
[Fact]
public void Concat_StacksModelPresetAndKind()
{
var stacked = SwarmUiLoraFormatter.Concat(
[new SwarmUiLoraEntry { Name = "model-lora", Weight = 1 }],
[new SwarmUiLoraEntry { Name = "preset-lora", Weight = 0.5 }],
[new SwarmUiLoraEntry { Name = "kind-lora", Weight = 0.2 }]);
Assert.Equal(["model-lora", "preset-lora", "kind-lora"], stacked.Select(entry => entry.Name));
}
[Fact]
public void AppendEmbedTags_AddsSwarmEmbedSyntax()
{
var prompt = SwarmUiLoraFormatter.AppendEmbedTags(
"a student",
[
new SwarmUiLoraEntry { Name = "pos.safetensors", Weight = 1 },
new SwarmUiLoraEntry { Name = "soft.safetensors", Weight = 0.6 },
]);
Assert.Contains("<embed:pos.safetensors>", prompt, StringComparison.Ordinal);
Assert.Contains("<embed:soft.safetensors:0.6>", prompt, StringComparison.Ordinal);
Assert.DoesNotContain("<lora:", prompt, StringComparison.Ordinal);
}
[Fact]
public void DiscoveryParser_ReadsEmbeddings()
{
using var document = JsonDocument.Parse(
"""
{
"models": {
"Stable-Diffusion": ["base.safetensors"],
"LoRA": ["style.safetensors"],
"Embedding": ["pos.safetensors", "neg.safetensors"]
},
"list": []
}
""");
var discovery = SwarmUiDiscoveryParser.Parse(document.RootElement);
Assert.Equal(["pos.safetensors", "neg.safetensors"], discovery.Embeddings);
Assert.Equal(["style.safetensors"], discovery.Loras);
}
[Fact]
public void ToProfile_StacksLorasAndEmbeddingsAcrossLayers()
{
var model = new SwarmUiModelDefinition
{
Id = "m.safetensors",
PositiveLoras = [new SwarmUiLoraEntry { Name = "model-lora", Weight = 1 }],
PositiveEmbeddings = [new SwarmUiLoraEntry { Name = "model-embed", Weight = 1 }],
};
var preset = new SwarmUiPresetDefinition
{
Id = "default",
Label = "Default",
Model = "m.safetensors",
PositiveLoras = [new SwarmUiLoraEntry { Name = "preset-lora", Weight = 0.5 }],
Avatar = new SwarmUiKindPreset
{
Width = 512,
Height = 512,
PositiveEmbeddings = [new SwarmUiLoraEntry { Name = "avatar-embed", Weight = 0.8 }],
},
};
var profile = preset.ToProfile(PortraitKind.Avatar, model);
Assert.Equal(["model-lora", "preset-lora"], profile.PositiveLoras.Select(entry => entry.Name));
Assert.Equal(["model-embed", "avatar-embed"], profile.PositiveEmbeddings.Select(entry => entry.Name));
}
[Fact]
public void Build_PutsEmbedsInPromptAndOmitsLoraTags()
{
var model = new SwarmUiModelDefinition
{
Id = "m.safetensors",
PositiveLoras = [new SwarmUiLoraEntry { Name = "style-lora", Weight = 1 }],
NegativeEmbeddings = [new SwarmUiLoraEntry { Name = "neg-embed", Weight = 1 }],
};
var preset = SwarmUiPresetDefinition.CreateDefault();
preset.PositiveEmbeddings = [new SwarmUiLoraEntry { Name = "pos-embed", Weight = 1 }];
var card = new HSchool.Server.Api.PersonCardResponse(
"f0.c0",
"Maria Ivanova",
"Ivanova",
"Maria",
"",
true,
16,
new DateTime(2000, 3, 14, 0, 0, 0, DateTimeKind.Utc),
["student"],
5,
"A",
"class-1",
null,
null,
[],
[],
[],
[],
null,
null,
new HSchool.Server.Api.PersonFamilyResponse([], [], [], []),
[],
[],
0f,
0f);
var (positive, negative) = PortraitPromptBuilder.Build(
card,
preset.ToProfile(PortraitKind.Avatar, model),
PortraitKind.Avatar);
Assert.Contains("<embed:pos-embed>", positive, StringComparison.Ordinal);
Assert.Contains("<embed:neg-embed>", negative, StringComparison.Ordinal);
Assert.DoesNotContain("<lora:", positive, StringComparison.Ordinal);
Assert.DoesNotContain("<lora:", negative, StringComparison.Ordinal);
}
}
@@ -110,6 +110,7 @@ public class SwarmUiSettingsStoreTests
],
[],
[],
[],
[]);
var allowed = config.AllowedModelIds(discovery);