59a93cf5c7
Route OpenAI image streaming through shared stream handling, split image/realtime/usage helpers for maintainability, and include the related image request and rate limit updates.
134 lines
4.1 KiB
Go
134 lines
4.1 KiB
Go
package openai
|
|
|
|
import (
|
|
"github.com/QuantumNous/new-api/common"
|
|
"github.com/QuantumNous/new-api/constant"
|
|
"github.com/QuantumNous/new-api/dto"
|
|
relaycommon "github.com/QuantumNous/new-api/relay/common"
|
|
)
|
|
|
|
func applyUsagePostProcessing(info *relaycommon.RelayInfo, usage *dto.Usage, responseBody []byte) {
|
|
if info == nil || usage == nil {
|
|
return
|
|
}
|
|
|
|
switch info.ChannelType {
|
|
case constant.ChannelTypeDeepSeek:
|
|
if usage.PromptTokensDetails.CachedTokens == 0 && usage.PromptCacheHitTokens != 0 {
|
|
usage.PromptTokensDetails.CachedTokens = usage.PromptCacheHitTokens
|
|
}
|
|
case constant.ChannelTypeZhipu_v4:
|
|
// 智普的cached_tokens在标准位置: usage.prompt_tokens_details.cached_tokens
|
|
if usage.PromptTokensDetails.CachedTokens == 0 {
|
|
if usage.InputTokensDetails != nil && usage.InputTokensDetails.CachedTokens > 0 {
|
|
usage.PromptTokensDetails.CachedTokens = usage.InputTokensDetails.CachedTokens
|
|
} else if cachedTokens, ok := extractCachedTokensFromBody(responseBody); ok {
|
|
usage.PromptTokensDetails.CachedTokens = cachedTokens
|
|
} else if usage.PromptCacheHitTokens > 0 {
|
|
usage.PromptTokensDetails.CachedTokens = usage.PromptCacheHitTokens
|
|
}
|
|
}
|
|
case constant.ChannelTypeMoonshot:
|
|
// Moonshot的cached_tokens在非标准位置: choices[].usage.cached_tokens
|
|
if usage.PromptTokensDetails.CachedTokens == 0 {
|
|
if usage.InputTokensDetails != nil && usage.InputTokensDetails.CachedTokens > 0 {
|
|
usage.PromptTokensDetails.CachedTokens = usage.InputTokensDetails.CachedTokens
|
|
} else if cachedTokens, ok := extractMoonshotCachedTokensFromBody(responseBody); ok {
|
|
usage.PromptTokensDetails.CachedTokens = cachedTokens
|
|
} else if cachedTokens, ok := extractCachedTokensFromBody(responseBody); ok {
|
|
usage.PromptTokensDetails.CachedTokens = cachedTokens
|
|
} else if usage.PromptCacheHitTokens > 0 {
|
|
usage.PromptTokensDetails.CachedTokens = usage.PromptCacheHitTokens
|
|
}
|
|
}
|
|
case constant.ChannelTypeOpenAI:
|
|
if usage.PromptTokensDetails.CachedTokens == 0 {
|
|
if cachedTokens, ok := extractLlamaCachedTokensFromBody(responseBody); ok {
|
|
usage.PromptTokensDetails.CachedTokens = cachedTokens
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func extractCachedTokensFromBody(body []byte) (int, bool) {
|
|
if len(body) == 0 {
|
|
return 0, false
|
|
}
|
|
|
|
var payload struct {
|
|
Usage struct {
|
|
PromptTokensDetails struct {
|
|
CachedTokens *int `json:"cached_tokens"`
|
|
} `json:"prompt_tokens_details"`
|
|
CachedTokens *int `json:"cached_tokens"`
|
|
PromptCacheHitTokens *int `json:"prompt_cache_hit_tokens"`
|
|
} `json:"usage"`
|
|
}
|
|
|
|
if err := common.Unmarshal(body, &payload); err != nil {
|
|
return 0, false
|
|
}
|
|
|
|
if payload.Usage.PromptTokensDetails.CachedTokens != nil {
|
|
return *payload.Usage.PromptTokensDetails.CachedTokens, true
|
|
}
|
|
if payload.Usage.CachedTokens != nil {
|
|
return *payload.Usage.CachedTokens, true
|
|
}
|
|
if payload.Usage.PromptCacheHitTokens != nil {
|
|
return *payload.Usage.PromptCacheHitTokens, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// extractMoonshotCachedTokensFromBody 从Moonshot的非标准位置提取cached_tokens
|
|
// Moonshot的流式响应格式: {"choices":[{"usage":{"cached_tokens":111}}]}
|
|
func extractMoonshotCachedTokensFromBody(body []byte) (int, bool) {
|
|
if len(body) == 0 {
|
|
return 0, false
|
|
}
|
|
|
|
var payload struct {
|
|
Choices []struct {
|
|
Usage struct {
|
|
CachedTokens *int `json:"cached_tokens"`
|
|
} `json:"usage"`
|
|
} `json:"choices"`
|
|
}
|
|
|
|
if err := common.Unmarshal(body, &payload); err != nil {
|
|
return 0, false
|
|
}
|
|
|
|
// 遍历choices查找cached_tokens
|
|
for _, choice := range payload.Choices {
|
|
if choice.Usage.CachedTokens != nil && *choice.Usage.CachedTokens > 0 {
|
|
return *choice.Usage.CachedTokens, true
|
|
}
|
|
}
|
|
|
|
return 0, false
|
|
}
|
|
|
|
// extractLlamaCachedTokensFromBody 从llama.cpp的非标准位置提取cache_n
|
|
func extractLlamaCachedTokensFromBody(body []byte) (int, bool) {
|
|
if len(body) == 0 {
|
|
return 0, false
|
|
}
|
|
|
|
var payload struct {
|
|
Timings struct {
|
|
CachedTokens *int `json:"cache_n"`
|
|
} `json:"timings"`
|
|
}
|
|
|
|
if err := common.Unmarshal(body, &payload); err != nil {
|
|
return 0, false
|
|
}
|
|
|
|
if payload.Timings.CachedTokens == nil {
|
|
return 0, false
|
|
}
|
|
return *payload.Timings.CachedTokens, true
|
|
}
|