mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-02 20:40:52 +08:00
feat(translators): add token counting support for Claude and Gemini responses
- Implemented `TokenCount` transform method across translators to calculate token usage. - Integrated token counting logic into executor pipelines for Claude, Gemini, and CLI translators. - Added corresponding API endpoints and handlers (`/messages/count_tokens`) for token usage retrieval. - Enhanced translation registry to support `TokenCount` functionality alongside existing response types.
This commit is contained in:
@@ -54,5 +54,8 @@ func ConvertClaudeResponseToGeminiCLINonStream(ctx context.Context, modelName st
|
||||
json := `{"response": {}}`
|
||||
strJSON, _ = sjson.SetRaw(json, "response", strJSON)
|
||||
return strJSON
|
||||
|
||||
}
|
||||
|
||||
func GeminiCLITokenCount(ctx context.Context, count int64) string {
|
||||
return GeminiTokenCount(ctx, count)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,9 @@ func init() {
|
||||
Claude,
|
||||
ConvertGeminiCLIRequestToClaude,
|
||||
interfaces.TranslateResponse{
|
||||
Stream: ConvertClaudeResponseToGeminiCLI,
|
||||
NonStream: ConvertClaudeResponseToGeminiCLINonStream,
|
||||
Stream: ConvertClaudeResponseToGeminiCLI,
|
||||
NonStream: ConvertClaudeResponseToGeminiCLINonStream,
|
||||
TokenCount: GeminiCLITokenCount,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -530,6 +531,10 @@ func ConvertClaudeResponseToGeminiNonStream(_ context.Context, modelName string,
|
||||
return template
|
||||
}
|
||||
|
||||
func GeminiTokenCount(ctx context.Context, count int64) string {
|
||||
return fmt.Sprintf(`{"totalTokens":%d,"promptTokensDetails":[{"modality":"TEXT","tokenCount":%d}]}`, count, count)
|
||||
}
|
||||
|
||||
// consolidateParts merges consecutive text parts and thinking parts to create a cleaner response.
|
||||
// This function processes the parts array to combine adjacent text elements and thinking elements
|
||||
// into single consolidated parts, which results in a more readable and efficient response structure.
|
||||
|
||||
@@ -12,8 +12,9 @@ func init() {
|
||||
Claude,
|
||||
ConvertGeminiRequestToClaude,
|
||||
interfaces.TranslateResponse{
|
||||
Stream: ConvertClaudeResponseToGemini,
|
||||
NonStream: ConvertClaudeResponseToGeminiNonStream,
|
||||
Stream: ConvertClaudeResponseToGemini,
|
||||
NonStream: ConvertClaudeResponseToGeminiNonStream,
|
||||
TokenCount: GeminiTokenCount,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -376,3 +376,7 @@ func ConvertGeminiCLIResponseToClaudeNonStream(_ context.Context, _ string, orig
|
||||
}
|
||||
return string(encoded)
|
||||
}
|
||||
|
||||
func ClaudeTokenCount(ctx context.Context, count int64) string {
|
||||
return fmt.Sprintf(`{"input_tokens":%d}`, count)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,9 @@ func init() {
|
||||
GeminiCLI,
|
||||
ConvertClaudeRequestToCLI,
|
||||
interfaces.TranslateResponse{
|
||||
Stream: ConvertGeminiCLIResponseToClaude,
|
||||
NonStream: ConvertGeminiCLIResponseToClaudeNonStream,
|
||||
Stream: ConvertGeminiCLIResponseToClaude,
|
||||
NonStream: ConvertGeminiCLIResponseToClaudeNonStream,
|
||||
TokenCount: ClaudeTokenCount,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package gemini
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
@@ -74,3 +75,7 @@ func ConvertGeminiCliRequestToGeminiNonStream(_ context.Context, _ string, origi
|
||||
}
|
||||
return string(rawJSON)
|
||||
}
|
||||
|
||||
func GeminiTokenCount(ctx context.Context, count int64) string {
|
||||
return fmt.Sprintf(`{"totalTokens":%d,"promptTokensDetails":[{"modality":"TEXT","tokenCount":%d}]}`, count, count)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,9 @@ func init() {
|
||||
GeminiCLI,
|
||||
ConvertGeminiRequestToGeminiCLI,
|
||||
interfaces.TranslateResponse{
|
||||
Stream: ConvertGeminiCliRequestToGemini,
|
||||
NonStream: ConvertGeminiCliRequestToGeminiNonStream,
|
||||
Stream: ConvertGeminiCliRequestToGemini,
|
||||
NonStream: ConvertGeminiCliRequestToGeminiNonStream,
|
||||
TokenCount: GeminiTokenCount,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -370,3 +370,7 @@ func ConvertGeminiResponseToClaudeNonStream(_ context.Context, _ string, origina
|
||||
}
|
||||
return string(encoded)
|
||||
}
|
||||
|
||||
func ClaudeTokenCount(ctx context.Context, count int64) string {
|
||||
return fmt.Sprintf(`{"input_tokens":%d}`, count)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,9 @@ func init() {
|
||||
Gemini,
|
||||
ConvertClaudeRequestToGemini,
|
||||
interfaces.TranslateResponse{
|
||||
Stream: ConvertGeminiResponseToClaude,
|
||||
NonStream: ConvertGeminiResponseToClaudeNonStream,
|
||||
Stream: ConvertGeminiResponseToClaude,
|
||||
NonStream: ConvertGeminiResponseToClaudeNonStream,
|
||||
TokenCount: ClaudeTokenCount,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ package geminiCLI
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/tidwall/sjson"
|
||||
)
|
||||
|
||||
@@ -47,3 +49,7 @@ func ConvertGeminiResponseToGeminiCLINonStream(_ context.Context, _ string, orig
|
||||
rawJSON, _ = sjson.SetRawBytes([]byte(json), "response", rawJSON)
|
||||
return string(rawJSON)
|
||||
}
|
||||
|
||||
func GeminiCLITokenCount(ctx context.Context, count int64) string {
|
||||
return fmt.Sprintf(`{"totalTokens":%d,"promptTokensDetails":[{"modality":"TEXT","tokenCount":%d}]}`, count, count)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,9 @@ func init() {
|
||||
Gemini,
|
||||
ConvertGeminiCLIRequestToGemini,
|
||||
interfaces.TranslateResponse{
|
||||
Stream: ConvertGeminiResponseToGeminiCLI,
|
||||
NonStream: ConvertGeminiResponseToGeminiCLINonStream,
|
||||
Stream: ConvertGeminiResponseToGeminiCLI,
|
||||
NonStream: ConvertGeminiResponseToGeminiCLINonStream,
|
||||
TokenCount: GeminiCLITokenCount,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package gemini
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// PassthroughGeminiResponseStream forwards Gemini responses unchanged.
|
||||
@@ -22,3 +23,7 @@ func PassthroughGeminiResponseStream(_ context.Context, _ string, originalReques
|
||||
func PassthroughGeminiResponseNonStream(_ context.Context, _ string, originalRequestRawJSON, requestRawJSON, rawJSON []byte, _ *any) string {
|
||||
return string(rawJSON)
|
||||
}
|
||||
|
||||
func GeminiTokenCount(ctx context.Context, count int64) string {
|
||||
return fmt.Sprintf(`{"totalTokens":%d,"promptTokensDetails":[{"modality":"TEXT","tokenCount":%d}]}`, count, count)
|
||||
}
|
||||
|
||||
@@ -14,8 +14,9 @@ func init() {
|
||||
Gemini,
|
||||
ConvertGeminiRequestToGemini,
|
||||
interfaces.TranslateResponse{
|
||||
Stream: PassthroughGeminiResponseStream,
|
||||
NonStream: PassthroughGeminiResponseNonStream,
|
||||
Stream: PassthroughGeminiResponseStream,
|
||||
NonStream: PassthroughGeminiResponseNonStream,
|
||||
TokenCount: GeminiTokenCount,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user