refactor: Chat-Payload vereinfacht + Inline-Bilder statt Platzhalter
Backend: - ChatEndpoint empfängt nur noch content + sessionId (nicht mehr die gesamte History) - History wird komplett aus DB aufgebaut via BuildHistoryFromDb - Gelöschte Nachrichten (deleted_on) werden aus History gefiltert - Leere Nachrichten werden übersprungen (kein API 400 mehr) - BuildHistoryFromDb optimiert: nur Text für ältere Chains, Tool-Calls nur für aktuelle Chain - GetChainMessages: includeDeleted-Parameter (Default: false) - Archiv-Export nutzt includeDeleted: true Frontend: - messages[]-Array komplett entfernt (kein Client-seitiger History-State mehr) - apiChat() sendet nur content + sessionId - Inline-Bilder: [Bild: name] wird durch <img> ersetzt (live mit DataURL, History per API-Nachladen) - _autoLoadImageAttachments() für History/Archiv/ältere Nachrichten - Klick auf Inline-Bild öffnet Vollbild-Modal
This commit is contained in:
1 parent
51db01752f
commit
8fc29c82d9
12 files changed
+222
-106
No files matched your search
+27
-50
@@ -23,10 +23,10 @@ public static class ChatEndpoint
|
||||
private static async Task HandleChat(HttpRequest req, HttpResponse res, IConfiguration config, ChatService chatService, DatabaseService db, StreamingTracker streamingTracker, AnthropicService anthropic, CancellationToken cancellationToken)
|
||||
{
|
||||
var body = await JsonSerializer.DeserializeAsync<ChatRequest>(req.Body);
|
||||
if (body == null || body.Messages == null || body.Messages.Count == 0)
|
||||
if (body == null || body.Content.ValueKind == JsonValueKind.Undefined)
|
||||
{
|
||||
res.StatusCode = 400;
|
||||
await res.WriteAsJsonAsync(new { error = "messages required" });
|
||||
await res.WriteAsJsonAsync(new { error = "content required" });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,58 +49,35 @@ public static class ChatEndpoint
|
||||
return;
|
||||
}
|
||||
|
||||
// Neue User-Message aus Request-Content aufbereiten und speichern
|
||||
var userMessage = new ChatMessage { Role = "user", Content = body.Content };
|
||||
var textContent = userMessage.GetTextContent();
|
||||
var attachmentBlocks = userMessage.GetAttachmentBlocks();
|
||||
|
||||
var attachmentRecords = attachmentBlocks.Select(b => new AttachmentRecord
|
||||
{
|
||||
Type = b.Type,
|
||||
MediaType = b.MediaType,
|
||||
FileName = b.FileName,
|
||||
Data = b.Data
|
||||
}).ToList();
|
||||
|
||||
await db.SaveMessageWithAttachments(new MessageRecord
|
||||
{
|
||||
ChainId = ctx.ChainId,
|
||||
Iteration = 0,
|
||||
Role = "user",
|
||||
Type = "text",
|
||||
Content = textContent
|
||||
}, attachmentRecords);
|
||||
|
||||
// History komplett aus DB aufbauen (inkl. gerade gespeicherter Message)
|
||||
var messages = await chatService.BuildHistoryFromDb(sessionId);
|
||||
|
||||
res.Headers["Content-Type"] = "text/event-stream";
|
||||
res.Headers["Cache-Control"] = "no-cache";
|
||||
res.Headers["Connection"] = "keep-alive";
|
||||
|
||||
// Messages aus dem Request aufbereiten
|
||||
var messages = new List<object>();
|
||||
foreach (var msg in body.Messages)
|
||||
{
|
||||
JsonElement content = msg.Content;
|
||||
if (msg.Content.ValueKind == JsonValueKind.Array)
|
||||
{
|
||||
var node = System.Text.Json.Nodes.JsonNode.Parse(msg.Content.GetRawText());
|
||||
foreach (var block in node.AsArray())
|
||||
{
|
||||
if (block is System.Text.Json.Nodes.JsonObject obj)
|
||||
obj.Remove("_file_name");
|
||||
}
|
||||
content = JsonSerializer.Deserialize<JsonElement>(node.ToJsonString());
|
||||
}
|
||||
|
||||
messages.Add(new Dictionary<string, JsonElement>
|
||||
{
|
||||
["role"] = JsonSerializer.Deserialize<JsonElement>($"\"{msg.Role}\""),
|
||||
["content"] = content
|
||||
});
|
||||
}
|
||||
|
||||
// Nur die letzte User-Message speichern (= die neue)
|
||||
var lastUserMsg = body.Messages.LastOrDefault(m => m.Role == "user");
|
||||
if (lastUserMsg != null)
|
||||
{
|
||||
var textContent = lastUserMsg.GetTextContent();
|
||||
var attachmentBlocks = lastUserMsg.GetAttachmentBlocks();
|
||||
|
||||
var attachmentRecords = attachmentBlocks.Select(b => new AttachmentRecord
|
||||
{
|
||||
Type = b.Type,
|
||||
MediaType = b.MediaType,
|
||||
FileName = b.FileName,
|
||||
Data = b.Data
|
||||
}).ToList();
|
||||
|
||||
await db.SaveMessageWithAttachments(new MessageRecord
|
||||
{
|
||||
ChainId = ctx.ChainId,
|
||||
Iteration = 0,
|
||||
Role = "user",
|
||||
Type = "text",
|
||||
Content = textContent
|
||||
}, attachmentRecords);
|
||||
}
|
||||
|
||||
streamingTracker.Start(sessionId, ctx.ChainId);
|
||||
try
|
||||
{
|
||||
|
||||
@@ -222,7 +222,7 @@ public static class HistoryEndpoint
|
||||
var result = new List<object>();
|
||||
foreach (var chain in chains)
|
||||
{
|
||||
var messages = await db.GetChainMessages(chain.ChainId);
|
||||
var messages = await db.GetChainMessages(chain.ChainId, includeDeleted: true);
|
||||
result.Add(new { chain, messages });
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user