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.
This commit is contained in:
@@ -174,6 +174,7 @@ internal static class SchoolEndpoints
|
||||
string personId,
|
||||
string? lang,
|
||||
GameCommandQueue commands,
|
||||
PortraitService portraits,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(personId) || personId.Length > 64)
|
||||
@@ -187,13 +188,95 @@ internal static class SchoolEndpoints
|
||||
var outcome = await command.Result.Task.WaitAsync(CommandTimeout, cancellationToken);
|
||||
return outcome.Error switch
|
||||
{
|
||||
PersonLookupError.None when outcome.Card is not null => Results.Ok(outcome.Card),
|
||||
PersonLookupError.None when outcome.Card is not null =>
|
||||
Results.Ok(portraits.WithPortraitFlags(id, outcome.Card)),
|
||||
PersonLookupError.UnknownPerson => Problem(StatusCodes.Status404NotFound, "unknown-person", "That person is not in the school."),
|
||||
_ => Problem(StatusCodes.Status404NotFound, "unknown-school", "That school does not exist."),
|
||||
};
|
||||
})
|
||||
.WithName("GetSchoolPerson");
|
||||
|
||||
schools.MapGet("/{id:int}/people/{personId}/portrait", async (
|
||||
int id,
|
||||
string personId,
|
||||
string? kind,
|
||||
PortraitService portraits,
|
||||
SchoolStore store,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(personId) || personId.Length > 64)
|
||||
{
|
||||
return Problem(StatusCodes.Status400BadRequest, "invalid-query", "The person id is not valid.");
|
||||
}
|
||||
|
||||
if (!PortraitKindParser.TryParse(kind, out var portraitKind))
|
||||
{
|
||||
return Problem(StatusCodes.Status400BadRequest, "invalid-query", "kind must be avatar or full.");
|
||||
}
|
||||
|
||||
var lookup = await portraits.EnsurePersonAsync(id, personId, cancellationToken);
|
||||
if (lookup == PersonLookupError.UnknownPerson)
|
||||
{
|
||||
return Problem(StatusCodes.Status404NotFound, "unknown-person", "That person is not in the school.");
|
||||
}
|
||||
|
||||
if (lookup != PersonLookupError.None)
|
||||
{
|
||||
return Problem(StatusCodes.Status404NotFound, "unknown-school", "That school does not exist.");
|
||||
}
|
||||
|
||||
var path = store.PortraitPath(id, personId, portraitKind);
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
return Problem(StatusCodes.Status404NotFound, "portrait-missing", "That portrait has not been generated yet.");
|
||||
}
|
||||
|
||||
return Results.File(path, "image/png");
|
||||
})
|
||||
.WithName("GetSchoolPersonPortrait");
|
||||
|
||||
schools.MapPost("/{id:int}/people/{personId}/portrait", async (
|
||||
int id,
|
||||
string personId,
|
||||
string? kind,
|
||||
PortraitService portraits,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(personId) || personId.Length > 64)
|
||||
{
|
||||
return Problem(StatusCodes.Status400BadRequest, "invalid-query", "The person id is not valid.");
|
||||
}
|
||||
|
||||
if (!PortraitKindParser.TryParse(kind, out var portraitKind))
|
||||
{
|
||||
return Problem(StatusCodes.Status400BadRequest, "invalid-query", "kind must be avatar or full.");
|
||||
}
|
||||
|
||||
if (!portraits.IsGenerationEnabled)
|
||||
{
|
||||
return Problem(StatusCodes.Status503ServiceUnavailable, "swarmui-not-configured", "SwarmUI is not configured.");
|
||||
}
|
||||
|
||||
var result = await portraits.GenerateAsync(id, personId, portraitKind, cancellationToken);
|
||||
return result.Outcome switch
|
||||
{
|
||||
PortraitGenerationOutcome.Succeeded => Results.Created(
|
||||
$"/api/schools/{id}/people/{Uri.EscapeDataString(personId)}/portrait?kind={(portraitKind == PortraitKind.Avatar ? "avatar" : "full")}",
|
||||
new PortraitResponse(
|
||||
portraitKind == PortraitKind.Avatar ? "avatar" : "full",
|
||||
result.HasAvatar,
|
||||
result.HasFullBody)),
|
||||
PortraitGenerationOutcome.UnknownPerson =>
|
||||
Problem(StatusCodes.Status404NotFound, "unknown-person", "That person is not in the school."),
|
||||
PortraitGenerationOutcome.NotConfigured =>
|
||||
Problem(StatusCodes.Status503ServiceUnavailable, "swarmui-not-configured", "SwarmUI is not configured."),
|
||||
PortraitGenerationOutcome.TimedOut =>
|
||||
Problem(StatusCodes.Status504GatewayTimeout, "swarmui-timeout", "SwarmUI did not finish in time."),
|
||||
_ => Problem(StatusCodes.Status502BadGateway, "swarmui-unavailable", "SwarmUI could not generate the portrait."),
|
||||
};
|
||||
})
|
||||
.WithName("GenerateSchoolPersonPortrait");
|
||||
|
||||
schools.MapGet("/{id:int}/staffing", (
|
||||
int id,
|
||||
string? lang,
|
||||
|
||||
Reference in New Issue
Block a user