style: polish admin user leaderboard
This commit is contained in:
1 parent
7657c45aae
commit
5590f7d85a
7 files changed
+508
-261
No files matched your search
@@ -146,8 +146,27 @@ def _iso(value) -> str:
|
||||
return value.isoformat() if isinstance(value, datetime) else str(value or "")
|
||||
|
||||
|
||||
def _range_start(days: int) -> datetime:
|
||||
return _now() - timedelta(days=max(1, min(days, 365)))
|
||||
def _parse_datetime(value: str | None, fallback: datetime) -> datetime:
|
||||
if not value:
|
||||
return fallback
|
||||
text = value.strip()
|
||||
if not text:
|
||||
return fallback
|
||||
if text.endswith("Z"):
|
||||
text = text[:-1] + "+00:00"
|
||||
try:
|
||||
return datetime.fromisoformat(text)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=f"Invalid datetime: {value}") from exc
|
||||
|
||||
|
||||
def _resolve_range(days: int, since: str | None, until: str | None) -> tuple[datetime, datetime, int]:
|
||||
end = _parse_datetime(until, _now())
|
||||
start = _parse_datetime(since, end - timedelta(days=max(1, min(days, 365))))
|
||||
if start > end:
|
||||
raise HTTPException(status_code=400, detail="since must be before until")
|
||||
span_days = max(1, min(365, (end - start).days + 1))
|
||||
return start, end, span_days
|
||||
|
||||
|
||||
def _question_count_expr():
|
||||
@@ -403,6 +422,8 @@ async def _query_overview(session, since: datetime, until: datetime, *, user_id:
|
||||
async def get_user_leaderboard(
|
||||
request: Request,
|
||||
days: int = Query(default=30, ge=1, le=365),
|
||||
since: str | None = Query(default=None, description="Inclusive range start, ISO datetime"),
|
||||
until: str | None = Query(default=None, description="Inclusive range end, ISO datetime"),
|
||||
limit: int = Query(default=20, ge=5, le=100),
|
||||
) -> AdminLeaderboardResponse:
|
||||
"""Return admin analytics for user activity, Q&A, skills, questions, and trends."""
|
||||
@@ -411,21 +432,20 @@ async def get_user_leaderboard(
|
||||
if session_factory is None:
|
||||
raise HTTPException(status_code=503, detail="Analytics requires database persistence")
|
||||
|
||||
until = _now()
|
||||
since = _range_start(days)
|
||||
since_dt, until_dt, range_days = _resolve_range(days, since, until)
|
||||
async with session_factory() as session:
|
||||
overview = await _query_overview(session, since, until)
|
||||
users = await _query_user_leaderboard(session, since, until)
|
||||
skills = await _query_call_rankings(session, since, until, user_id=None, field="skill", limit=limit)
|
||||
tools = await _query_call_rankings(session, since, until, user_id=None, field="tool", limit=limit)
|
||||
recent_questions = await _query_recent_questions(session, since, until, user_id=None, limit=limit)
|
||||
frequent_questions = await _query_frequent_questions(session, since, until, limit=limit)
|
||||
trends = await _query_trends(session, since, until)
|
||||
overview = await _query_overview(session, since_dt, until_dt)
|
||||
users = await _query_user_leaderboard(session, since_dt, until_dt)
|
||||
skills = await _query_call_rankings(session, since_dt, until_dt, user_id=None, field="skill", limit=limit)
|
||||
tools = await _query_call_rankings(session, since_dt, until_dt, user_id=None, field="tool", limit=limit)
|
||||
recent_questions = await _query_recent_questions(session, since_dt, until_dt, user_id=None, limit=limit)
|
||||
frequent_questions = await _query_frequent_questions(session, since_dt, until_dt, limit=limit)
|
||||
trends = await _query_trends(session, since_dt, until_dt)
|
||||
|
||||
return AdminLeaderboardResponse(
|
||||
range_days=days,
|
||||
since=_iso(since),
|
||||
until=_iso(until),
|
||||
range_days=range_days,
|
||||
since=_iso(since_dt),
|
||||
until=_iso(until_dt),
|
||||
overview=overview,
|
||||
users_by_activity=sorted(users, key=lambda u: (u.run_count + u.tool_call_count, u.total_tokens), reverse=True)[:limit],
|
||||
users_by_questions=sorted(users, key=lambda u: (u.qa_count, u.run_count), reverse=True)[:limit],
|
||||
@@ -443,6 +463,8 @@ async def get_user_analytics(
|
||||
user_id: str,
|
||||
request: Request,
|
||||
days: int = Query(default=30, ge=1, le=365),
|
||||
since: str | None = Query(default=None, description="Inclusive range start, ISO datetime"),
|
||||
until: str | None = Query(default=None, description="Inclusive range end, ISO datetime"),
|
||||
limit: int = Query(default=20, ge=5, le=100),
|
||||
) -> AdminUserAnalyticsResponse:
|
||||
"""Return one user's admin analytics profile."""
|
||||
@@ -451,22 +473,21 @@ async def get_user_analytics(
|
||||
if session_factory is None:
|
||||
raise HTTPException(status_code=503, detail="Analytics requires database persistence")
|
||||
|
||||
until = _now()
|
||||
since = _range_start(days)
|
||||
since_dt, until_dt, range_days = _resolve_range(days, since, until)
|
||||
async with session_factory() as session:
|
||||
users = await _query_user_leaderboard(session, since, until, user_id=user_id)
|
||||
users = await _query_user_leaderboard(session, since_dt, until_dt, user_id=user_id)
|
||||
if not users:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
overview = await _query_overview(session, since, until, user_id=user_id)
|
||||
skills = await _query_call_rankings(session, since, until, user_id=user_id, field="skill", limit=limit)
|
||||
tools = await _query_call_rankings(session, since, until, user_id=user_id, field="tool", limit=limit)
|
||||
recent_questions = await _query_recent_questions(session, since, until, user_id=user_id, limit=limit)
|
||||
trends = await _query_trends(session, since, until, user_id=user_id)
|
||||
overview = await _query_overview(session, since_dt, until_dt, user_id=user_id)
|
||||
skills = await _query_call_rankings(session, since_dt, until_dt, user_id=user_id, field="skill", limit=limit)
|
||||
tools = await _query_call_rankings(session, since_dt, until_dt, user_id=user_id, field="tool", limit=limit)
|
||||
recent_questions = await _query_recent_questions(session, since_dt, until_dt, user_id=user_id, limit=limit)
|
||||
trends = await _query_trends(session, since_dt, until_dt, user_id=user_id)
|
||||
|
||||
return AdminUserAnalyticsResponse(
|
||||
range_days=days,
|
||||
since=_iso(since),
|
||||
until=_iso(until),
|
||||
range_days=range_days,
|
||||
since=_iso(since_dt),
|
||||
until=_iso(until_dt),
|
||||
user=users[0],
|
||||
overview=overview,
|
||||
skills=skills,
|
||||
|
||||
Reference in new issue
Block a user