Files
openclaw-market/app/api/v1/token/stats/route.ts
2026-03-16 08:44:11 +08:00

93 lines
2.7 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { eq, and, gte, sql } from "drizzle-orm";
import { db } from "@/lib/db";
import { tokenUsage } from "@/lib/db/schema";
import { authenticateRequest } from "@/lib/auth/request";
import { getTodayDateString } from "@/lib/utils";
export async function GET(req: NextRequest) {
try {
const auth = await authenticateRequest(req);
if (auth instanceof NextResponse) {
return auth;
}
const { claw } = auth;
const today = getTodayDateString();
// Get total usage using raw query for aggregation
const totalResult = await db.execute(sql`
SELECT
COALESCE(SUM(input_tokens), 0) AS inputTokens,
COALESCE(SUM(output_tokens), 0) AS outputTokens
FROM token_usage
WHERE claw_id = ${claw.id}
`);
const totalRow = totalResult[0] as unknown as { inputTokens: number; outputTokens: number } | undefined;
const totalStats = totalRow
? {
inputTokens: Number(totalRow.inputTokens || 0),
outputTokens: Number(totalRow.outputTokens || 0),
totalTokens: Number(totalRow.inputTokens || 0) + Number(totalRow.outputTokens || 0),
}
: {
inputTokens: 0,
outputTokens: 0,
totalTokens: 0,
};
// Get last 30 days history
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
const thirtyDaysAgoStr = thirtyDaysAgo.toISOString().split("T")[0];
const history = await db
.select({
date: tokenUsage.date,
inputTokens: tokenUsage.inputTokens,
outputTokens: tokenUsage.outputTokens,
})
.from(tokenUsage)
.where(
and(
eq(tokenUsage.clawId, claw.id),
gte(tokenUsage.date, thirtyDaysAgoStr)
)
);
// Derive today's stats from history (avoids redundant query)
const todayRecord = history.find((h) => h.date === today);
const todayStats = todayRecord
? {
inputTokens: todayRecord.inputTokens,
outputTokens: todayRecord.outputTokens,
totalTokens: todayRecord.inputTokens + todayRecord.outputTokens,
}
: {
inputTokens: 0,
outputTokens: 0,
totalTokens: 0,
};
return NextResponse.json({
clawId: claw.id,
clawName: claw.name,
today: todayStats,
total: totalStats,
history: history.map((h) => ({
date: h.date,
inputTokens: h.inputTokens,
outputTokens: h.outputTokens,
totalTokens: h.inputTokens + h.outputTokens,
})),
});
} catch (error) {
console.error("Token stats error:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}