diff --git a/GerbilManagerWebAPI/Endpoints/SaleAdEndpoints.cs b/GerbilManagerWebAPI/Endpoints/SaleAdEndpoints.cs new file mode 100644 index 0000000..5f73ebc --- /dev/null +++ b/GerbilManagerWebAPI/Endpoints/SaleAdEndpoints.cs @@ -0,0 +1,34 @@ +using GerbilManagerWebAPI.SaleAd; + +namespace GerbilManagerWebAPI.Endpoints +{ + /// + /// FEAT-12a: POST /gerbils/sale-ad — AI-gestütztes Abgabe-Inserat (frozen + /// contract, see gerbil-manager-web/src/api/saleAd.ts). + /// + /// 503 {code:"AiKeyMissing"} while the AI section is unconfigured — the + /// frontend maps exactly this code to its German disabled-state hint. + /// + public static class SaleAdEndpoints + { + public static IEndpointRouteBuilder MapSaleAdEndpoints(this IEndpointRouteBuilder app) + { + app.MapPost("/gerbils/sale-ad", + async (SaleAdRequest request, SaleAdService service, CancellationToken ct) => + { + var result = await service.GenerateAsync(request, ct); + return result.Status switch + { + SaleAdStatus.Ok => Results.Ok(new SaleAdResponse(result.Text!)), + SaleAdStatus.NotConfigured => Results.Json( + new SaleAdError("AiKeyMissing", result.Error ?? ""), statusCode: 503), + _ => Results.Json( + new SaleAdError("AiUpstreamError", result.Error ?? ""), statusCode: 502), + }; + }) + .WithTags("SaleAd"); + + return app; + } + } +} diff --git a/GerbilManagerWebAPI/Program.cs b/GerbilManagerWebAPI/Program.cs index c4bfc3e..c960f6e 100644 --- a/GerbilManagerWebAPI/Program.cs +++ b/GerbilManagerWebAPI/Program.cs @@ -35,6 +35,13 @@ builder.Services.AddCors(options => options.AddPolicy(LanCorsPolicy, policy => // OpenAPI document for the Scalar API reference (Swashbuckle removed). builder.Services.AddOpenApi(); +// FEAT-12a: provider-agnostic AI config (env vars AI__BaseUrl/AI__ApiKey/AI__Model +// or user-secrets — never committed) + typed client for sale-ad generation. +builder.Services.AddOptions() + .BindConfiguration(GerbilManagerWebAPI.SaleAd.AiOptions.SectionName); +builder.Services.AddHttpClient( + http => http.Timeout = TimeSpan.FromSeconds(60)); + var app = builder.Build(); app.MapDefaultEndpoints(); @@ -62,5 +69,6 @@ app.MapHealthRecordEndpoints(); app.MapWeightRecordEndpoints(); app.MapInbreedingEndpoints(); app.MapPhotoEndpoints(); +app.MapSaleAdEndpoints(); app.Run();