mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-04 22:13:08 +00:00
fix(admin): keyset export paging, rollup-free spend, consistent totals
Review pass over the preceding commits. - The activity export paged by OFFSET. The journals are append-only and the feed is newest-first, so rows written mid-export shift the window down and repeat rows already emitted. Pages by keyset on (created_at, feed, id) now. - top_token_users and the per-user breakdown counted run-level rollup rows. A scheduled run already has a row per LLM call, so its spend was billed twice -- invisible while the column was tokens, obvious once it was dollars. Both now exclude them, matching every other spend query. - total_cost was summed from the per-model split, which drops rows with no model_id and so undercounted the figure printed above the series. Summed from the series instead. - The CSV export encoded its detail cell without the fallback the NDJSON branch had, so a non-JSON-native value would have failed the stream. - The activity view reset pagination in an effect, which fetched the stale page against the new filters before fetching again. Reset in the setters. - The audit taxonomy is no longer re-exported from the helper module; the one caller that wanted it imports from where it lives.
This commit is contained in:
1 parent
f6f8af8cef
commit
c2d1893992
9 files changed
+113
-47
No files matched your search
@@ -43,7 +43,7 @@ _EXPORT_CHUNK = 1_000
|
||||
_MAX_SEARCH_LENGTH = 200
|
||||
|
||||
|
||||
def _csv_list(name: str, allowed: tuple[str, ...]) -> Optional[list[str]]:
|
||||
def _facet_list(name: str, allowed: tuple[str, ...]) -> Optional[list[str]]:
|
||||
"""Parse a repeated/comma-separated query arg, dropping unknown values.
|
||||
|
||||
Args:
|
||||
@@ -96,8 +96,8 @@ def _search_arg() -> Optional[str]:
|
||||
def _filters() -> dict:
|
||||
"""The filter set shared by the feed and the export."""
|
||||
return {
|
||||
"feeds": _csv_list("feed", _FEEDS),
|
||||
"categories": _csv_list("category", ACTIVITY_CATEGORIES),
|
||||
"feeds": _facet_list("feed", _FEEDS),
|
||||
"categories": _facet_list("category", ACTIVITY_CATEGORIES),
|
||||
"events": _event_list(),
|
||||
"actor_id": request.args.get("actor_id") or None,
|
||||
"user_id": request.args.get("user_id") or None,
|
||||
@@ -216,7 +216,9 @@ def _csv_rows(filters: dict, limit: int) -> Iterator[str]:
|
||||
for row in _export_rows(filters, limit):
|
||||
serialized = _serialize(row)
|
||||
# ``detail`` is a JSON object; a CSV cell holds its compact encoding.
|
||||
serialized["detail"] = json.dumps(serialized.get("detail") or {})
|
||||
serialized["detail"] = json.dumps(
|
||||
serialized.get("detail") or {}, default=str
|
||||
)
|
||||
writer.writerow(serialized)
|
||||
yield _drain(buffer)
|
||||
|
||||
|
||||
@@ -359,7 +359,9 @@ class AdminUsageResource(Resource):
|
||||
"group_by": group_by,
|
||||
"series": series,
|
||||
"total_tokens": int(total),
|
||||
"total_cost": round(sum(row["cost"] for row in by_model), 4),
|
||||
# Summed from the series, not from ``by_model``: the latter
|
||||
# drops rows with no model_id, so it would undercount.
|
||||
"total_cost": round(sum(row["cost"] for row in series), 4),
|
||||
"by_model": by_model,
|
||||
"latency": latency,
|
||||
"top_users": top_users,
|
||||
|
||||
Reference in new issue
Block a user