Browse Source

fix: 支持 Gemini thoughtsTokenCount 计费

- 在 GeminiUsageMetadata 类型中添加 thoughtsTokenCount 字段
- 新增 GeminiTokenDetail 类型支持按 modality 分类的 token 详情
- 将 thoughtsTokenCount 累加到 output_tokens 进行计费
  (Gemini 思考 token 价格与输出 token 相同)
- 添加 promptTokensDetails、cacheTokensDetails、
  candidatesTokensDetails 字段支持

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
sususu98 2 months ago
parent
commit
7226788a6e
2 changed files with 16 additions and 1 deletions
  1. 11 1
      src/app/v1/_lib/gemini/types.ts
  2. 5 0
      src/app/v1/_lib/proxy/response-handler.ts

+ 11 - 1
src/app/v1/_lib/gemini/types.ts

@@ -51,11 +51,21 @@ export interface GeminiRequest {
   };
 }
 
+export interface GeminiTokenDetail {
+  modality: "TEXT" | "IMAGE" | "AUDIO" | "VIDEO";
+  tokenCount: number;
+}
+
 export interface GeminiUsageMetadata {
   promptTokenCount: number;
   candidatesTokenCount: number;
   totalTokenCount: number;
-  cachedContentTokenCount?: number; // Gemini 缓存支持
+  cachedContentTokenCount?: number; // Gemini 缓存命中的 token 数
+  thoughtsTokenCount?: number; // Gemini 思考模型的推理 token
+  // 详细信息(按 modality 分类)
+  promptTokensDetails?: GeminiTokenDetail[];
+  cacheTokensDetails?: GeminiTokenDetail[];
+  candidatesTokensDetails?: GeminiTokenDetail[];
 }
 
 export interface GeminiCandidate {

+ 5 - 0
src/app/v1/_lib/proxy/response-handler.ts

@@ -1213,6 +1213,11 @@ function extractUsageMetrics(value: unknown): UsageMetrics | null {
     result.cache_read_input_tokens = usage.cachedContentTokenCount;
     hasAny = true;
   }
+  // Gemini 思考/推理 token:直接累加到 output_tokens(思考价格与输出价格相同)
+  if (typeof usage.thoughtsTokenCount === "number" && usage.thoughtsTokenCount > 0) {
+    result.output_tokens = (result.output_tokens ?? 0) + usage.thoughtsTokenCount;
+    hasAny = true;
+  }
 
   if (typeof usage.output_tokens === "number") {
     result.output_tokens = usage.output_tokens;