chain blocks: single-line layout, user message display, raw json fix, range label with time
This commit is contained in:
1 parent
791dd5718c
commit
670c5b7f16
4 files changed
+160
-52
No files matched your search
+94
-13
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user