Ver Fonte

feat(logs): track request endpoint and expose distinct endpoints

- ProxyMessageService: extract endpoint via session.getEndpoint() and pass to repository
- repository.createMessageRequest: accept and store endpoint, include in returning selection
- usage-logs: add getUsedEndpoints() using DISTINCT and null-safe filtering

This enables endpoint-based filtering and analytics; TypeScript build passes.
ding113 há 3 meses atrás
pai
commit
5d03fde291

+ 4 - 0
src/app/v1/_lib/proxy/message-service.ts

@@ -18,6 +18,9 @@ export class ProxyMessageService {
       return;
     }
 
+    // Extract endpoint from URL pathname (nullable)
+    const endpoint = session.getEndpoint() ?? undefined;
+
     const messageRequest = await createMessageRequest({
       provider_id: provider.id,
       user_id: authState.user.id,
@@ -28,6 +31,7 @@ export class ProxyMessageService {
       user_agent: session.userAgent ?? undefined, // 传入 user_agent
       original_model: session.getOriginalModel() ?? undefined, // 传入原始模型(用户请求的模型)
       messages_count: session.getMessagesLength(), // 传入 messages 数量
+      endpoint, // 传入请求端点(可能为 undefined)
     });
 
     session.setMessageContext({

+ 2 - 0
src/repository/message.ts

@@ -24,6 +24,7 @@ export async function createMessageRequest(
     costMultiplier: data.cost_multiplier?.toString() ?? undefined, // 供应商倍率(转为字符串)
     sessionId: data.session_id, // Session ID
     userAgent: data.user_agent, // User-Agent
+    endpoint: data.endpoint, // 请求端点(可为空)
     messagesCount: data.messages_count, // Messages 数量
   };
 
@@ -38,6 +39,7 @@ export async function createMessageRequest(
     costMultiplier: messageRequest.costMultiplier, // 新增
     sessionId: messageRequest.sessionId, // 新增
     userAgent: messageRequest.userAgent, // 新增
+    endpoint: messageRequest.endpoint, // 新增:返回端点
     messagesCount: messageRequest.messagesCount, // 新增
     createdAt: messageRequest.createdAt,
     updatedAt: messageRequest.updatedAt,

+ 13 - 0
src/repository/usage-logs.ts

@@ -268,3 +268,16 @@ export async function getUsedStatusCodes(): Promise<number[]> {
 
   return results.map((r) => r.statusCode).filter((c): c is number => c !== null);
 }
+
+/**
+ * 获取所有使用过的 Endpoint 列表(用于筛选器)
+ */
+export async function getUsedEndpoints(): Promise<string[]> {
+  const results = await db
+    .selectDistinct({ endpoint: messageRequest.endpoint })
+    .from(messageRequest)
+    .where(and(isNull(messageRequest.deletedAt), sql`${messageRequest.endpoint} IS NOT NULL`))
+    .orderBy(messageRequest.endpoint);
+
+  return results.map((r) => r.endpoint).filter((e): e is string => e !== null);
+}