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
+80
-24
@@ -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")
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user