Implement portrait generation and retrieval for people in the school system. Added new API endpoints for generating and fetching portraits, including support for avatar and full-body images. Updated the client-side to handle portrait states and display options. Enhanced the person card UI to include tabs for overview and portrait, with appropriate localization strings. Updated solution files to include new test projects. Adjusted server configuration for SwarmUI integration.
ci / server (push) Failing after 3m46s
ci / client (push) Failing after 14s

This commit is contained in:
Leonid Pershin
2026-08-20 04:14:41 +03:00
parent 871178909e
commit dfa9a25dca
32 changed files with 1538 additions and 121 deletions
@@ -0,0 +1,72 @@
using HSchool.Server.Api;
using HSchool.Server.Game;
namespace HSchool.Server.Tests;
public class PortraitPromptBuilderTests
{
[Fact]
public void Build_IncludesAgeHairAndWornClothing()
{
var settings = new SwarmUiSettings
{
Positive = "School photo.",
Avatar = new SwarmUiSettings.SwarmUiPreset { Positive = "Head and shoulders." },
};
var card = SampleCard();
var (positive, _) = PortraitPromptBuilder.Build(card, settings, PortraitKind.Avatar);
Assert.Contains("age 12", positive, StringComparison.OrdinalIgnoreCase);
Assert.Contains("black", positive, StringComparison.OrdinalIgnoreCase);
Assert.Contains("shirt", positive, StringComparison.OrdinalIgnoreCase);
Assert.Contains("white", positive, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Head and shoulders.", positive, StringComparison.Ordinal);
}
[Fact]
public void Build_FullBody_AddsFullBodyPreset()
{
var settings = new SwarmUiSettings
{
Positive = "School photo.",
Avatar = new SwarmUiSettings.SwarmUiPreset { Positive = "Head and shoulders." },
FullBody = new SwarmUiSettings.SwarmUiPreset { Positive = "Standing full body." },
};
var (avatarPositive, _) = PortraitPromptBuilder.Build(SampleCard(), settings, PortraitKind.Avatar);
var (fullPositive, _) = PortraitPromptBuilder.Build(SampleCard(), settings, PortraitKind.Full);
Assert.Contains("Head and shoulders.", avatarPositive, StringComparison.Ordinal);
Assert.DoesNotContain("Standing full body.", avatarPositive, StringComparison.Ordinal);
Assert.Contains("Standing full body.", fullPositive, StringComparison.Ordinal);
}
private static PersonCardResponse SampleCard() =>
new(
"f0.c0",
"Maria Ivanova",
"Ivanova",
"Maria",
"",
true,
12,
new DateTime(2000, 3, 14, 0, 0, 0, DateTimeKind.Utc),
["student"],
5,
"A",
"class-1",
null,
null,
[new LabeledStatResponse("HairColor", "Hair colour", "Black")],
[],
[],
[],
null,
null,
new PersonFamilyResponse([], [], [], []),
[new WornItemResponse("Shirt", "Shirt", "White", "White", [], 1f, "new")],
[],
0f,
0f);
}