Files
openbridge-token-usage-viewer/src/orpc/handlers/usage.ts
MAO Dongyang d22a0f8d69 feat: 替换 OpenBridge 组件并实现航海规范主题系统
- 使用 shadcn/ui 重新实现 TopBar、ThemeSidebar、AlertBadge 组件
- 解决 @oicl/openbridge-webcomponents ESM 模块解析问题
- 添加 OpenBridge 四种主题 CSS 变量 (day/bright/dusk/night)
- Night 主题使用暗黄色文字保护夜视能力
- 更新 API 端点适配新的按模型分组数据结构
2026-01-26 21:17:56 +08:00

93 lines
2.5 KiB
TypeScript

/**
* Token 使用量处理器
*
* 从远程 API 获取数据,筛选 Opus/Thinking 模型,并存储历史记录
*/
import { usageHistoryTable } from '@/db/schema'
import { env } from '@/env'
import { dbProvider } from '@/orpc/middlewares'
import { os } from '@/orpc/server'
/** 远程 API 响应中的账户数据结构 */
interface RemoteAccountData {
accountName: string
remainingFraction: number
resetTime?: string
status?: string
}
/** 远程 API 响应中的模型数据结构 (按模型分组) */
interface RemoteModelData {
modelId: string
displayName?: string
accounts: RemoteAccountData[]
}
/** 远程 API 响应结构 */
interface RemoteResponse {
data: RemoteModelData[]
}
export const getUsage = os.usage.getUsage
.use(dbProvider)
.handler(async ({ context }) => {
// 1. 获取远程数据
const response = await fetch(env.TOKEN_USAGE_URL)
if (!response.ok) {
throw new Error(`Failed to fetch usage data: ${response.statusText}`)
}
const data = (await response.json()) as RemoteResponse
// 2. 找到 claude-opus-4-5-thinking 模型,然后从其 accounts 中提取数据
const opusModels: Array<{
account: string
model: string
displayName?: string
remainingFraction: number
resetTime?: string
}> = []
// 新 API 按模型分组,找到目标模型
const opusModelData = data.data.find(
(m) => m.modelId === 'claude-opus-4-5-thinking',
)
if (opusModelData) {
// 遍历该模型下的所有账户
for (const accountData of opusModelData.accounts) {
const account = accountData.accountName.replace('.json', '')
opusModels.push({
account,
model: opusModelData.modelId,
displayName: opusModelData.displayName,
remainingFraction: accountData.remainingFraction,
resetTime: accountData.resetTime,
})
}
}
// 3. 存储到历史表(仅在 Bun 环境下工作)
try {
if (opusModels.length > 0 && context.db) {
await context.db.insert(usageHistoryTable).values(
opusModels.map((m) => ({
account: m.account,
model: m.model,
displayName: m.displayName,
remainingFraction: m.remainingFraction,
resetTime: m.resetTime,
})),
)
}
} catch (err) {
// 在非 Bun 环境下,数据库可能不可用,忽略错误
console.warn('Database insert skipped:', err)
}
return {
opusModels,
fetchedAt: new Date().toISOString(),
}
})