mirror of
https://github.com/Routstr/routstr-core.git
synced 2026-08-10 03:07:06 +00:00
fix(ci): resolve backend type/lint and ui format issues
This commit is contained in:
@@ -673,7 +673,7 @@ class UsageAnalyticsStore:
|
||||
)
|
||||
|
||||
if model_updates:
|
||||
rows = [
|
||||
model_rows = [
|
||||
(
|
||||
minute_ts,
|
||||
model,
|
||||
@@ -713,11 +713,11 @@ class UsageAnalyticsStore:
|
||||
output_tokens = output_tokens + excluded.output_tokens,
|
||||
total_tokens = total_tokens + excluded.total_tokens
|
||||
""",
|
||||
rows,
|
||||
model_rows,
|
||||
)
|
||||
|
||||
if model_presence_updates:
|
||||
rows = [
|
||||
presence_rows = [
|
||||
(minute_ts, model, count)
|
||||
for (minute_ts, model), count in model_presence_updates.items()
|
||||
]
|
||||
@@ -732,11 +732,11 @@ class UsageAnalyticsStore:
|
||||
ON CONFLICT(minute_ts, model) DO UPDATE SET
|
||||
count = count + excluded.count
|
||||
""",
|
||||
rows,
|
||||
presence_rows,
|
||||
)
|
||||
|
||||
if error_type_updates:
|
||||
rows = [
|
||||
error_type_rows = [
|
||||
(minute_ts, error_type, count)
|
||||
for (minute_ts, error_type), count in error_type_updates.items()
|
||||
]
|
||||
@@ -751,7 +751,7 @@ class UsageAnalyticsStore:
|
||||
ON CONFLICT(minute_ts, error_type) DO UPDATE SET
|
||||
count = count + excluded.count
|
||||
""",
|
||||
rows,
|
||||
error_type_rows,
|
||||
)
|
||||
|
||||
if error_events:
|
||||
@@ -1215,9 +1215,9 @@ class UsageAnalyticsStore:
|
||||
|
||||
for row in top_model_rows:
|
||||
bucket_ts = str(row["bucket_ts"])
|
||||
bucket = bucket_index.get(bucket_ts)
|
||||
if bucket is None:
|
||||
if bucket_ts not in bucket_index:
|
||||
continue
|
||||
bucket = bucket_index[bucket_ts]
|
||||
|
||||
model = str(row["model"])
|
||||
successful = int(row["successful"])
|
||||
|
||||
@@ -12,7 +12,7 @@ import json
|
||||
import math
|
||||
import time
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
from typing import Any, TypedDict
|
||||
|
||||
from nostr.event import Event
|
||||
from nostr.key import PrivateKey
|
||||
@@ -46,6 +46,13 @@ WINDOW_DEFINITIONS: tuple[tuple[str, int, int], ...] = (
|
||||
)
|
||||
|
||||
|
||||
class PayloadSpec(TypedDict):
|
||||
period_type: str
|
||||
period_key: str
|
||||
d_tag: str
|
||||
payload: dict[str, Any]
|
||||
|
||||
|
||||
def _event_to_dict(ev: Event) -> dict[str, Any]:
|
||||
return {
|
||||
"id": ev.id,
|
||||
@@ -197,7 +204,10 @@ def _aggregate_top_model_usage(
|
||||
}
|
||||
for model, values in model_totals.items()
|
||||
]
|
||||
model_rows.sort(key=lambda row: row["successful_requests"], reverse=True)
|
||||
model_rows.sort(
|
||||
key=lambda row: _to_int(row.get("successful_requests", 0)),
|
||||
reverse=True,
|
||||
)
|
||||
|
||||
return model_rows, others
|
||||
|
||||
@@ -600,7 +610,7 @@ async def publish_usage_analytics() -> None:
|
||||
generated_at=now_ts,
|
||||
)
|
||||
|
||||
payload_specs = [
|
||||
payload_specs: list[PayloadSpec] = [
|
||||
{
|
||||
"period_type": "latest",
|
||||
"period_key": "latest",
|
||||
@@ -624,7 +634,7 @@ async def publish_usage_analytics() -> None:
|
||||
to_publish: list[dict[str, Any]] = []
|
||||
refs: dict[str, dict[str, str]] = {}
|
||||
for spec in payload_specs:
|
||||
payload = spec["payload"]
|
||||
payload: dict[str, Any] = spec["payload"]
|
||||
payload_hash = _fingerprint_payload(payload)
|
||||
d_tag = str(spec["d_tag"])
|
||||
period_type = str(spec["period_type"])
|
||||
|
||||
@@ -198,7 +198,11 @@ function detectProviderFromModel(model: string): string {
|
||||
if (value.includes('claude')) return 'anthropic';
|
||||
if (value.includes('gpt') || value.includes('openai')) return 'openai';
|
||||
if (value.includes('gemini')) return 'google';
|
||||
if (value.includes('grok') || value.includes('x-ai') || value.includes('xai')) {
|
||||
if (
|
||||
value.includes('grok') ||
|
||||
value.includes('x-ai') ||
|
||||
value.includes('xai')
|
||||
) {
|
||||
return 'x-ai';
|
||||
}
|
||||
if (value.includes('deepseek')) return 'deepseek';
|
||||
@@ -206,15 +210,20 @@ function detectProviderFromModel(model: string): string {
|
||||
if (value.includes('kimi') || value.includes('moonshot')) return 'moonshot';
|
||||
if (value.includes('mistral')) return 'mistral';
|
||||
if (value.includes('qwen') || value.includes('alibaba')) return 'alibaba';
|
||||
if (value.includes('glm') || value.includes('z-ai') || value.includes('z ai')) {
|
||||
if (
|
||||
value.includes('glm') ||
|
||||
value.includes('z-ai') ||
|
||||
value.includes('z ai')
|
||||
) {
|
||||
return 'z-ai';
|
||||
}
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
function getModelPresentation(
|
||||
model: string
|
||||
): { displayName: string; provider: string } {
|
||||
function getModelPresentation(model: string): {
|
||||
displayName: string;
|
||||
provider: string;
|
||||
} {
|
||||
const trimmed = model.trim();
|
||||
const slashIndex = trimmed.indexOf('/');
|
||||
if (slashIndex > 0 && slashIndex < trimmed.length - 1) {
|
||||
@@ -257,10 +266,7 @@ export function TopModelsUsageChart({
|
||||
[mix.metrics]
|
||||
);
|
||||
|
||||
const chartModels = useMemo(
|
||||
() => mixTopModels.slice(0, 20),
|
||||
[mixTopModels]
|
||||
);
|
||||
const chartModels = useMemo(() => mixTopModels.slice(0, 20), [mixTopModels]);
|
||||
const leaderboardModels = useMemo(
|
||||
() => mixTopModels.slice(0, 20),
|
||||
[mixTopModels]
|
||||
@@ -472,9 +478,7 @@ export function TopModelsUsageChart({
|
||||
|
||||
const windowSize = Math.floor(mixMetrics.length / 2);
|
||||
const previousMetrics =
|
||||
windowSize > 0
|
||||
? mixMetrics.slice(-windowSize * 2, -windowSize)
|
||||
: [];
|
||||
windowSize > 0 ? mixMetrics.slice(-windowSize * 2, -windowSize) : [];
|
||||
const currentMetrics =
|
||||
windowSize > 0 ? mixMetrics.slice(-windowSize) : mixMetrics;
|
||||
|
||||
@@ -482,10 +486,10 @@ export function TopModelsUsageChart({
|
||||
.map((model) => {
|
||||
const readMetric = (metric: (typeof mixMetrics)[number]): number =>
|
||||
mode === 'requests'
|
||||
? (metric.model_counts ?? {})[model] ?? 0
|
||||
? ((metric.model_counts ?? {})[model] ?? 0)
|
||||
: mode === 'revenue'
|
||||
? (metric.model_revenue_msats ?? {})[model] ?? 0
|
||||
: (metric.model_tokens ?? {})[model] ?? 0;
|
||||
? ((metric.model_revenue_msats ?? {})[model] ?? 0)
|
||||
: ((metric.model_tokens ?? {})[model] ?? 0);
|
||||
|
||||
const totalRaw = mixMetrics.reduce(
|
||||
(sum, metric) => sum + readMetric(metric),
|
||||
@@ -557,7 +561,9 @@ export function TopModelsUsageChart({
|
||||
<CardHeader className='space-y-3 sm:space-y-4'>
|
||||
<div className='flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between'>
|
||||
<div className='min-w-0'>
|
||||
<CardTitle className='text-base sm:text-lg'>Model Usage</CardTitle>
|
||||
<CardTitle className='text-base sm:text-lg'>
|
||||
Model Usage
|
||||
</CardTitle>
|
||||
<p className='text-muted-foreground mt-1 text-xs sm:text-sm'>
|
||||
Stacked requests, revenue, or tokens by model (
|
||||
{mix.interval_minutes}m buckets).
|
||||
@@ -689,7 +695,9 @@ export function TopModelsUsageChart({
|
||||
value,
|
||||
} satisfies TooltipRow;
|
||||
})
|
||||
.filter((row) => Number.isFinite(row.value) && row.value > 0)
|
||||
.filter(
|
||||
(row) => Number.isFinite(row.value) && row.value > 0
|
||||
)
|
||||
.sort((a, b) => b.value - a.value);
|
||||
|
||||
const total = rows.reduce((sum, row) => sum + row.value, 0);
|
||||
@@ -814,7 +822,7 @@ export function TopModelsUsageChart({
|
||||
className={cn(
|
||||
'grid grid-cols-[auto_minmax(0,1fr)_auto_auto] items-center gap-3 rounded-md px-2 py-2 text-xs',
|
||||
rowIsLinked &&
|
||||
'cursor-pointer transition hover:bg-muted/25',
|
||||
'hover:bg-muted/25 cursor-pointer transition',
|
||||
rowIsActive && 'bg-muted/30',
|
||||
rowIsDimmed && 'opacity-45'
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user