feat(server): API relay gateway backend M0-M4
Gin + GORM + pure-Go SQLite. Users/auth (JWT), API key management with quotas, proxy gateway with weighted channel failover and health checks, usage/billing ledger, cross-protocol conversion (Anthropic Messages / OpenAI Chat Completions / OpenAI Responses), and channel/model admin API. Channels declare native API formats and auto-convert the rest. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b0c7439c01
commit
d0e31b198f
@@ -0,0 +1,48 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"openteam/server/internal/proxy/claude"
|
||||
"openteam/server/internal/proxy/openai"
|
||||
"openteam/server/internal/proxy/responses"
|
||||
)
|
||||
|
||||
// parseUsageForProtocol extracts token usage from a non-stream response body.
|
||||
func parseUsageForProtocol(proto Protocol, body []byte) *tokenUsage {
|
||||
switch proto {
|
||||
case ProtocolAnthropic:
|
||||
var mr claude.MessageResponse
|
||||
if err := json.Unmarshal(body, &mr); err != nil || mr.Usage == nil {
|
||||
return nil
|
||||
}
|
||||
return &tokenUsage{
|
||||
input: mr.Usage.InputTokens,
|
||||
output: mr.Usage.OutputTokens,
|
||||
cacheRead: mr.Usage.CacheReadInputTokens,
|
||||
cacheCreation: mr.Usage.CacheCreationInputTokens,
|
||||
}
|
||||
case ProtocolOpenAIResponses:
|
||||
var r responses.Response
|
||||
if err := json.Unmarshal(body, &r); err != nil || r.Usage == nil {
|
||||
return nil
|
||||
}
|
||||
return &tokenUsage{
|
||||
input: r.Usage.InputTokens,
|
||||
output: r.Usage.OutputTokens,
|
||||
cacheRead: r.Usage.InputTokensDetails.CachedTokens,
|
||||
}
|
||||
default:
|
||||
var cc openai.ChatCompletion
|
||||
if err := json.Unmarshal(body, &cc); err != nil || cc.Usage == nil {
|
||||
return nil
|
||||
}
|
||||
return &tokenUsage{input: cc.Usage.PromptTokens, output: cc.Usage.CompletionTokens}
|
||||
}
|
||||
}
|
||||
|
||||
// estimateTokensFromText is a coarse fallback used when the upstream omits usage.
|
||||
func estimateTokensFromText(s string) int64 {
|
||||
// ~4 chars per token, per OpenAI's common heuristic.
|
||||
return int64(len(s)/4 + 1)
|
||||
}
|
||||
Reference in New Issue
Block a user