Refine memory settings and admin usage stats
This commit is contained in:
@@ -30,7 +30,10 @@ type AccountRow = {
|
||||
tool_calls: number;
|
||||
input_tokens: number;
|
||||
output_tokens: number;
|
||||
reasoning_tokens: number;
|
||||
total_tokens: number;
|
||||
average_tokens_per_session: number;
|
||||
average_tool_calls_per_session: number;
|
||||
latest_session_at: number;
|
||||
models: Record<string, number>;
|
||||
user_memory_lines: number;
|
||||
@@ -331,6 +334,70 @@ function AdminDashboard({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 xl:grid-cols-[1.2fr_0.8fr]">
|
||||
<div className="rounded-lg border bg-card">
|
||||
<div className="border-b p-3 font-medium">用量详情</div>
|
||||
<div className="grid gap-3 p-3 md:grid-cols-4">
|
||||
<SmallStat
|
||||
label="输入 token"
|
||||
value={formatNumber(selectedAccount?.input_tokens ?? 0)}
|
||||
/>
|
||||
<SmallStat
|
||||
label="输出 token"
|
||||
value={formatNumber(selectedAccount?.output_tokens ?? 0)}
|
||||
/>
|
||||
<SmallStat
|
||||
label="推理 token"
|
||||
value={formatNumber(selectedAccount?.reasoning_tokens ?? 0)}
|
||||
/>
|
||||
<SmallStat
|
||||
label="平均 token/会话"
|
||||
value={formatNumber(
|
||||
selectedAccount?.average_tokens_per_session ?? 0,
|
||||
)}
|
||||
/>
|
||||
<SmallStat
|
||||
label="平均工具/会话"
|
||||
value={selectedAccount?.average_tool_calls_per_session ?? 0}
|
||||
/>
|
||||
<SmallStat
|
||||
label="注册状态"
|
||||
value={selectedAccount?.registered ? "已注册" : "仅目录"}
|
||||
/>
|
||||
<SmallStat
|
||||
label="最近活跃"
|
||||
value={formatTime(selectedAccount?.latest_session_at)}
|
||||
/>
|
||||
<SmallStat
|
||||
label="模型数"
|
||||
value={Object.keys(selectedAccount?.models ?? {}).length}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-lg border bg-card">
|
||||
<div className="border-b p-3 font-medium">模型分布</div>
|
||||
<div className="max-h-40 overflow-y-auto p-3 text-sm">
|
||||
{Object.entries(selectedAccount?.models ?? {}).length ? (
|
||||
Object.entries(selectedAccount?.models ?? {})
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.map(([model, count]) => (
|
||||
<div
|
||||
key={model}
|
||||
className="mb-2 grid grid-cols-[1fr_auto] gap-3"
|
||||
>
|
||||
<span className="truncate text-muted-foreground">
|
||||
{model}
|
||||
</span>
|
||||
<span>{count} 会话</span>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="text-muted-foreground">暂无模型用量</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 xl:grid-cols-[360px_1fr]">
|
||||
<div className="grid gap-4 content-start">
|
||||
<div className="rounded-lg border bg-card">
|
||||
@@ -463,3 +530,13 @@ function formatNumber(value: number) {
|
||||
maximumFractionDigits: 1,
|
||||
}).format(value);
|
||||
}
|
||||
|
||||
function formatTime(value?: number) {
|
||||
if (!value) return "暂无";
|
||||
return new Intl.DateTimeFormat("zh-CN", {
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
}).format(new Date(value * 1000));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { getCurrentAccount } from "@/lib/claw-auth";
|
||||
|
||||
const CLAW_API_URL = process.env.CLAW_API_URL ?? "http://127.0.0.1:8765";
|
||||
|
||||
export async function GET() {
|
||||
const account = await getCurrentAccount();
|
||||
if (!account)
|
||||
return Response.json({ error: "unauthorized" }, { status: 401 });
|
||||
const url = new URL(`${CLAW_API_URL}/api/memory/events`);
|
||||
url.searchParams.set("account_id", account.id);
|
||||
const response = await fetch(url, { cache: "no-store" });
|
||||
const payload = await response.text();
|
||||
return new Response(payload, {
|
||||
status: response.status,
|
||||
headers: {
|
||||
"content-type":
|
||||
response.headers.get("content-type") ?? "application/json",
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user