- KreaService: GenerateAsync() mit Job-Polling, Image-Download, Metadaten-Speicherung
- KreaEndpoint: POST /api/images/generate, GET /api/images, GET /api/images/file/{filename}, GET /api/images/status
- KreaImageRecord: Output-Model
- Output: data/images/<timestamp>-<index>.<ext> + data/images/<timestamp>.json
- 16 Modelle: flux, flux-kontext, flux-1.1-pro, imagen-3/4, chatgpt-image, runway-gen-4, etc.
- appsettings.json: KreaToken (Format: KEY_ID:SECRET), obsolete TelegramBotToken/WebhookSecret entfernt
113 lines
4.1 KiB
C#
113 lines
4.1 KiB
C#
using System.IO;
|
||
using System.Text.Json;
|
||
using System.Threading.Tasks;
|
||
using Gott.Services;
|
||
using Microsoft.AspNetCore.Builder;
|
||
using Microsoft.AspNetCore.Http;
|
||
using Microsoft.AspNetCore.Routing;
|
||
|
||
namespace Gott.Endpoints
|
||
{
|
||
public static class KreaEndpoint
|
||
{
|
||
public static void MapKreaEndpoints(this IEndpointRouteBuilder app)
|
||
{
|
||
app.MapPost("/api/images/generate", HandleGenerate);
|
||
app.MapGet("/api/images", HandleList);
|
||
app.MapGet("/api/images/file/{filename}", HandleFile);
|
||
app.MapGet("/api/images/status", HandleStatus);
|
||
}
|
||
|
||
private static async Task HandleGenerate(HttpRequest req, HttpResponse res, KreaService krea)
|
||
{
|
||
if (!krea.IsConfigured)
|
||
{
|
||
res.StatusCode = 400;
|
||
await res.WriteAsJsonAsync(new { error = "Krea API nicht konfiguriert (KreaToken fehlt)" });
|
||
return;
|
||
}
|
||
|
||
JsonElement body;
|
||
try { body = await JsonSerializer.DeserializeAsync<JsonElement>(req.Body); }
|
||
catch
|
||
{
|
||
res.StatusCode = 400;
|
||
await res.WriteAsJsonAsync(new { error = "Ungültiger JSON-Body" });
|
||
return;
|
||
}
|
||
|
||
var prompt = body.TryGetProperty("prompt", out var p) ? p.GetString() : null;
|
||
if (string.IsNullOrWhiteSpace(prompt))
|
||
{
|
||
res.StatusCode = 400;
|
||
await res.WriteAsJsonAsync(new { error = "prompt ist erforderlich" });
|
||
return;
|
||
}
|
||
|
||
var model = body.TryGetProperty("model", out var m) ? m.GetString() : "flux";
|
||
var width = body.TryGetProperty("width", out var w) ? w.GetInt32() : 1024;
|
||
var height = body.TryGetProperty("height", out var h) ? h.GetInt32() : 1024;
|
||
var steps = body.TryGetProperty("steps", out var st) ? st.GetInt32() : 25;
|
||
var guidanceScale = body.TryGetProperty("guidanceScale", out var g) ? g.GetDouble() : 3.0;
|
||
var seed = body.TryGetProperty("seed", out var sd) ? sd.GetString() : null;
|
||
var batchSize = body.TryGetProperty("batchSize", out var b) ? b.GetInt32() : 1;
|
||
|
||
try
|
||
{
|
||
var result = await krea.GenerateAsync(prompt, model, width, height, steps, guidanceScale, seed, batchSize);
|
||
await res.WriteAsJsonAsync(result);
|
||
}
|
||
catch (System.Exception ex)
|
||
{
|
||
res.StatusCode = 500;
|
||
await res.WriteAsJsonAsync(new { error = ex.Message });
|
||
}
|
||
}
|
||
|
||
private static async Task HandleList(HttpRequest req, HttpResponse res, KreaService krea)
|
||
{
|
||
var images = krea.ListImages();
|
||
await res.WriteAsJsonAsync(images);
|
||
}
|
||
|
||
private static async Task HandleFile(HttpRequest req, HttpResponse res, KreaService krea, string filename)
|
||
{
|
||
// Sicherheitscheck – kein Path Traversal
|
||
if (filename.Contains("..") || filename.Contains("/") || filename.Contains("\\"))
|
||
{
|
||
res.StatusCode = 400;
|
||
return;
|
||
}
|
||
|
||
var path = krea.GetImagePath(filename);
|
||
if (path == null)
|
||
{
|
||
res.StatusCode = 404;
|
||
return;
|
||
}
|
||
|
||
var ext = Path.GetExtension(filename).ToLower();
|
||
var contentType = ext switch
|
||
{
|
||
".png" => "image/png",
|
||
".jpg" => "image/jpeg",
|
||
".jpeg" => "image/jpeg",
|
||
".gif" => "image/gif",
|
||
_ => "image/webp",
|
||
};
|
||
|
||
res.ContentType = contentType;
|
||
await res.SendFileAsync(path);
|
||
}
|
||
|
||
private static async Task HandleStatus(HttpRequest req, HttpResponse res, KreaService krea)
|
||
{
|
||
await res.WriteAsJsonAsync(new
|
||
{
|
||
configured = krea.IsConfigured,
|
||
models = KreaService.IMAGE_MODELS.Keys,
|
||
});
|
||
}
|
||
}
|
||
}
|