chain blocks: single-line layout, user message display, raw json fix, range label with time

This commit is contained in:
Meleki committed 2026-02-22 17:32:29 +01:00
1 parent 791dd5718c
commit 670c5b7f16
4 files changed
+160 -52

No files matched your search

+94 -13
View File
@@ -64,21 +64,65 @@ app.MapGet("/api/cost-chains", (Func<SqliteConnection> factory, string from, str
{
using var db = factory();
var rows = db.Query(@"
SELECT chainId,
SUM(CAST(json_extract(data, '$.message.usage.cost.total') AS REAL)) AS totalCost,
COUNT(*) AS count,
MIN(timestamp) AS first,
MAX(timestamp) AS last
FROM entries
WHERE json_extract(data, '$.message.usage.cost.total') IS NOT NULL
AND timestamp >= @from AND timestamp < @to
AND chainId IS NOT NULL
GROUP BY chainId
ORDER BY totalCost DESC
LIMIT @limit OFFSET @offset",
SELECT c.chainId,
c.totalCost,
c.count,
c.first,
c.last,
e.data AS chainData
FROM (
SELECT chainId,
SUM(CAST(json_extract(data, '$.message.usage.cost.total') AS REAL)) AS totalCost,
COUNT(*) AS count,
MIN(timestamp) AS first,
MAX(timestamp) AS last
FROM entries
WHERE json_extract(data, '$.message.usage.cost.total') IS NOT NULL
AND timestamp >= @from AND timestamp < @to
AND chainId IS NOT NULL
GROUP BY chainId
ORDER BY totalCost DESC
LIMIT @limit OFFSET @offset
) c
LEFT JOIN entries e ON e.id = c.chainId",
new { from, to, limit, offset });
return Results.Ok(rows);
var result = rows.Select((dynamic r) =>
{
string? userMsg = null;
try
{
string raw = r.chainData;
var doc = System.Text.Json.JsonDocument.Parse(raw);
var msg = doc.RootElement.GetProperty("message");
var content = msg.GetProperty("content");
string fullText;
if (content.ValueKind == System.Text.Json.JsonValueKind.String)
fullText = content.GetString()!;
else
{
fullText = string.Join("\n", content.EnumerateArray()
.Where(c => c.TryGetProperty("type", out var t) && t.GetString() == "text")
.Select(c => c.GetProperty("text").GetString()));
}
userMsg = StripSystemPrefixes(fullText);
if (userMsg?.Length > 200) userMsg = userMsg[..200] + "...";
}
catch { }
return new
{
chainId = (string)r.chainId,
totalCost = (double)r.totalCost,
count = (long)r.count,
first = (string)r.first,
last = (string)r.last,
userMessage = userMsg ?? ""
};
});
return Results.Ok(result);
});
// GET /api/cost-summary?from=&to=
@@ -233,3 +277,40 @@ app.MapPost("/api/sync", async () =>
});
app.Run();
static string StripSystemPrefixes(string text)
{
var lines = text.Split('\n').ToList();
var inCodeBlock = false;
// Strip from top
while (lines.Count > 0)
{
var t = lines[0].Trim();
if (string.IsNullOrEmpty(t)) { lines.RemoveAt(0); continue; }
// [Direct ...], [Current ...], [System ...], [message_id ...], [message-id ...], [Chat messages ...], [Queued messages ...]
if (t.StartsWith('[') && (t.StartsWith("[Direct ") || t.StartsWith("[Current ") ||
t.StartsWith("[System ") || t.StartsWith("[message_id:") || t.StartsWith("[message-id ") ||
t.StartsWith("[Chat messages ") || t.StartsWith("[Queued messages ")))
{ lines.RemoveAt(0); continue; }
// [Telegram ... id:xxx ...] msg - strip only the bracket prefix, keep the message after ]
if (t.StartsWith("[Telegram ") && t.Contains(']'))
{
var afterBracket = t[(t.IndexOf(']') + 1)..].Trim();
if (!string.IsNullOrEmpty(afterBracket)) { lines[0] = afterBracket; break; }
lines.RemoveAt(0); continue;
}
// "Conversation info", "Queued #N", "---", "Assistant:"
if (t.StartsWith("Conversation info") || t.StartsWith("Queued #") ||
t.StartsWith("Assistant:") || t == "---") { lines.RemoveAt(0); continue; }
// Code block boundaries and JSON content inside
if (t == "```json" || t == "```") { inCodeBlock = !inCodeBlock; lines.RemoveAt(0); continue; }
if (inCodeBlock) { lines.RemoveAt(0); continue; }
// "User: " prefix
if (t.StartsWith("User: ")) { lines[0] = t["User: ".Length..]; break; }
break;
}
var result = string.Join("\n", lines).Trim();
return string.IsNullOrEmpty(result) ? text.Split('\n').LastOrDefault(l => !string.IsNullOrWhiteSpace(l))?.Trim() ?? "" : result;
}