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:
Meleki committed 2026-03-04 14:29:33 +01:00
1 parent 51db01752f
commit 8fc29c82d9
12 files changed
+222 -106

No files matched your search

+80 -24
View File
@@ -124,15 +124,59 @@ public class ChatService
/// <summary>
/// Baut die Message-History aus der DB (aktive Chains).
/// Optimiert: Nur Text-Messages (user/assistant) für ältere Chains,
/// Tool-Calls nur für die aktuelle Chain, Attachments nur für die letzte User-Message.
/// </summary>
public async Task<List<object>> BuildHistoryFromDb(string sessionId)
{
var chains = await _db.GetActiveChains(sessionId);
var history = new List<object>();
var chainsList = (await _db.GetActiveChains(sessionId)).ToList();
// chronologisch sortieren (älteste zuerst)
chainsList.Reverse();
foreach (var chain in chains)
var history = new List<object>();
var isLastChain = false;
long? lastUserMsgId = null;
for (int i = 0; i < chainsList.Count; i++)
{
var msgs = await _db.GetChainMessages(chain.ChainId);
var chain = chainsList[i];
isLastChain = (i == chainsList.Count - 1);
var msgs = (await _db.GetChainMessages(chain.ChainId)).ToList();
// Letzte User-Message-ID der letzten Chain merken (für Attachments)
if (isLastChain)
{
var lastUserMsg = msgs.LastOrDefault(m => m.Role == "user" && m.Type == "text");
lastUserMsgId = lastUserMsg?.Id;
}
// Für ältere Chains: nur Text-Messages (wie Frontend es vorher gemacht hat)
if (!isLastChain)
{
foreach (var msg in msgs)
{
if (msg.Role == "user" && msg.Type == "text" && !string.IsNullOrEmpty(msg.Content))
{
history.Add(new Dictionary<string, object>
{
["role"] = "user",
["content"] = new List<object> { new { type = "text", text = msg.Content } }
});
}
else if (msg.Role == "assistant" && msg.Type == "text" && !string.IsNullOrEmpty(msg.Content))
{
history.Add(new Dictionary<string, object>
{
["role"] = "assistant",
["content"] = new List<object> { new { type = "text", text = msg.Content } }
});
}
}
continue;
}
// Letzte Chain: vollständig mit Tool-Calls
var grouped = new Dictionary<int, List<MessageRecord>>();
foreach (var msg in msgs)
{
@@ -148,36 +192,48 @@ public class ChatService
if (msg.Role == "user" && msg.Type == "text")
{
var content = new List<object>();
var attachments = await _db.GetAttachments(msg.Id);
foreach (var att in attachments)
// Attachments nur für die letzte User-Message laden
if (msg.Id == lastUserMsgId)
{
if (att.Type == "image")
var attachments = await _db.GetAttachments(msg.Id);
foreach (var att in attachments)
{
content.Add(new
if (att.Type == "image")
{
type = "image",
source = new { type = "base64", media_type = att.MediaType, data = att.Data }
});
}
else if (att.Type == "document")
{
content.Add(new
content.Add(new
{
type = "image",
source = new { type = "base64", media_type = att.MediaType, data = att.Data }
});
}
else if (att.Type == "document")
{
type = "document",
source = new { type = "base64", media_type = att.MediaType, data = att.Data }
});
content.Add(new
{
type = "document",
source = new { type = "base64", media_type = att.MediaType, data = att.Data }
});
}
}
}
content.Add(new { type = "text", text = msg.Content ?? "" });
history.Add(new Dictionary<string, object> { ["role"] = "user", ["content"] = content });
if (!string.IsNullOrEmpty(msg.Content))
content.Add(new { type = "text", text = msg.Content });
if (content.Count > 0)
history.Add(new Dictionary<string, object> { ["role"] = "user", ["content"] = content });
}
else if (msg.Role == "assistant" && msg.Type == "text")
{
history.Add(new Dictionary<string, object>
if (!string.IsNullOrEmpty(msg.Content))
{
["role"] = "assistant",
["content"] = new List<object> { new { type = "text", text = msg.Content ?? "" } }
});
history.Add(new Dictionary<string, object>
{
["role"] = "assistant",
["content"] = new List<object> { new { type = "text", text = msg.Content } }
});
}
}
else if (msg.Role == "assistant" && msg.Type == "tool_use")
{