37 lines
1.2 KiB
TypeScript
37 lines
1.2 KiB
TypeScript
import { getRedisClient } from "../redis";
|
|
|
|
export interface TokenUsageRecord {
|
|
id: string; // uuid/id da requisição (pode ser requestId)
|
|
timestamp: number;
|
|
model: string;
|
|
inputTokens: number;
|
|
outputTokens: number;
|
|
totalTokens: number;
|
|
costUsd: number;
|
|
context?: Record<string, unknown>; // dados opcionais (ex.: rota, itemId)
|
|
}
|
|
|
|
const KEY_PREFIX = "ai:usage";
|
|
|
|
export async function recordTokenUsage(
|
|
record: TokenUsageRecord,
|
|
): Promise<void> {
|
|
const redis = await getRedisClient();
|
|
const dayKey = `${KEY_PREFIX}:day:${new Date(record.timestamp).toISOString().slice(0, 10)}`; // YYYY-MM-DD
|
|
const listKey = `${KEY_PREFIX}:records`;
|
|
|
|
// Armazenar agregado diário
|
|
const pipeline = redis.multi();
|
|
pipeline.hIncrBy(dayKey, "inputTokens", record.inputTokens);
|
|
pipeline.hIncrBy(dayKey, "outputTokens", record.outputTokens);
|
|
pipeline.hIncrBy(dayKey, "totalTokens", record.totalTokens);
|
|
pipeline.hIncrByFloat(dayKey, "costUsd", record.costUsd);
|
|
|
|
// Armazenar registro detalhado (para relatórios)
|
|
pipeline.lPush(listKey, JSON.stringify(record));
|
|
// Manter os últimos 10k registros para não crescer indefinidamente (ajuste conforme necessidade)
|
|
pipeline.lTrim(listKey, 0, 9999);
|
|
|
|
await pipeline.exec();
|
|
}
|