mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-02 08:41:45 +00:00
Compare commits
7 Commits
v0.9.16
...
task-model
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
797c7acd13 | ||
|
|
f15b85f745 | ||
|
|
10a473993b | ||
|
|
ff11c92713 | ||
|
|
347ad047f9 | ||
|
|
c651727bab | ||
|
|
7fc25a57cf |
@@ -510,44 +510,11 @@ func (c *ClaudeResponse) GetClaudeError() *types.ClaudeError {
|
||||
}
|
||||
|
||||
type ClaudeUsage struct {
|
||||
InputTokens int `json:"input_tokens"`
|
||||
CacheCreationInputTokens int `json:"cache_creation_input_tokens"`
|
||||
CacheReadInputTokens int `json:"cache_read_input_tokens"`
|
||||
OutputTokens int `json:"output_tokens"`
|
||||
CacheCreation *ClaudeCacheCreationUsage `json:"cache_creation,omitempty"`
|
||||
// claude cache 1h
|
||||
ClaudeCacheCreation5mTokens int `json:"claude_cache_creation_5_m_tokens"`
|
||||
ClaudeCacheCreation1hTokens int `json:"claude_cache_creation_1_h_tokens"`
|
||||
ServerToolUse *ClaudeServerToolUse `json:"server_tool_use,omitempty"`
|
||||
}
|
||||
|
||||
type ClaudeCacheCreationUsage struct {
|
||||
Ephemeral5mInputTokens int `json:"ephemeral_5m_input_tokens,omitempty"`
|
||||
Ephemeral1hInputTokens int `json:"ephemeral_1h_input_tokens,omitempty"`
|
||||
}
|
||||
|
||||
func (u *ClaudeUsage) GetCacheCreation5mTokens() int {
|
||||
if u == nil || u.CacheCreation == nil {
|
||||
return 0
|
||||
}
|
||||
return u.CacheCreation.Ephemeral5mInputTokens
|
||||
}
|
||||
|
||||
func (u *ClaudeUsage) GetCacheCreation1hTokens() int {
|
||||
if u == nil || u.CacheCreation == nil {
|
||||
return 0
|
||||
}
|
||||
return u.CacheCreation.Ephemeral1hInputTokens
|
||||
}
|
||||
|
||||
func (u *ClaudeUsage) GetCacheCreationTotalTokens() int {
|
||||
if u == nil {
|
||||
return 0
|
||||
}
|
||||
if u.CacheCreationInputTokens > 0 {
|
||||
return u.CacheCreationInputTokens
|
||||
}
|
||||
return u.GetCacheCreation5mTokens() + u.GetCacheCreation1hTokens()
|
||||
InputTokens int `json:"input_tokens"`
|
||||
CacheCreationInputTokens int `json:"cache_creation_input_tokens"`
|
||||
CacheReadInputTokens int `json:"cache_read_input_tokens"`
|
||||
OutputTokens int `json:"output_tokens"`
|
||||
ServerToolUse *ClaudeServerToolUse `json:"server_tool_use,omitempty"`
|
||||
}
|
||||
|
||||
type ClaudeServerToolUse struct {
|
||||
|
||||
@@ -230,11 +230,6 @@ type Usage struct {
|
||||
InputTokens int `json:"input_tokens"`
|
||||
OutputTokens int `json:"output_tokens"`
|
||||
InputTokensDetails *InputTokenDetails `json:"input_tokens_details"`
|
||||
|
||||
// claude cache 1h
|
||||
ClaudeCacheCreation5mTokens int `json:"claude_cache_creation_5_m_tokens"`
|
||||
ClaudeCacheCreation1hTokens int `json:"claude_cache_creation_1_h_tokens"`
|
||||
|
||||
// OpenRouter Params
|
||||
Cost any `json:"cost,omitempty"`
|
||||
}
|
||||
|
||||
@@ -98,9 +98,9 @@ func oaiFormEdit2AliImageEdit(c *gin.Context, info *relaycommon.RelayInfo, reque
|
||||
return nil, errors.New("image is required")
|
||||
}
|
||||
|
||||
//if len(imageFiles) > 1 {
|
||||
// return nil, errors.New("only one image is supported for qwen edit")
|
||||
//}
|
||||
if len(imageFiles) > 1 {
|
||||
return nil, errors.New("only one image is supported for qwen edit")
|
||||
}
|
||||
|
||||
// 获取base64编码的图片
|
||||
var imageBase64s []string
|
||||
|
||||
@@ -596,8 +596,6 @@ func FormatClaudeResponseInfo(requestMode int, claudeResponse *dto.ClaudeRespons
|
||||
claudeInfo.Usage.PromptTokens = claudeResponse.Message.Usage.InputTokens
|
||||
claudeInfo.Usage.PromptTokensDetails.CachedTokens = claudeResponse.Message.Usage.CacheReadInputTokens
|
||||
claudeInfo.Usage.PromptTokensDetails.CachedCreationTokens = claudeResponse.Message.Usage.CacheCreationInputTokens
|
||||
claudeInfo.Usage.ClaudeCacheCreation5mTokens = claudeResponse.Message.Usage.GetCacheCreation5mTokens()
|
||||
claudeInfo.Usage.ClaudeCacheCreation1hTokens = claudeResponse.Message.Usage.GetCacheCreation1hTokens()
|
||||
claudeInfo.Usage.CompletionTokens = claudeResponse.Message.Usage.OutputTokens
|
||||
} else if claudeResponse.Type == "content_block_delta" {
|
||||
if claudeResponse.Delta.Text != nil {
|
||||
@@ -742,8 +740,6 @@ func HandleClaudeResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud
|
||||
claudeInfo.Usage.TotalTokens = claudeResponse.Usage.InputTokens + claudeResponse.Usage.OutputTokens
|
||||
claudeInfo.Usage.PromptTokensDetails.CachedTokens = claudeResponse.Usage.CacheReadInputTokens
|
||||
claudeInfo.Usage.PromptTokensDetails.CachedCreationTokens = claudeResponse.Usage.CacheCreationInputTokens
|
||||
claudeInfo.Usage.ClaudeCacheCreation5mTokens = claudeResponse.Usage.GetCacheCreation5mTokens()
|
||||
claudeInfo.Usage.ClaudeCacheCreation1hTokens = claudeResponse.Usage.GetCacheCreation1hTokens()
|
||||
}
|
||||
var responseData []byte
|
||||
switch info.RelayFormat {
|
||||
|
||||
@@ -122,10 +122,6 @@ func OaiStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Re
|
||||
var usage = &dto.Usage{}
|
||||
var streamItems []string // store stream items
|
||||
var lastStreamData string
|
||||
var secondLastStreamData string // 存储倒数第二个stream data,用于音频模型
|
||||
|
||||
// 检查是否为音频模型
|
||||
isAudioModel := strings.Contains(strings.ToLower(model), "audio")
|
||||
|
||||
helper.StreamScannerHandler(c, resp, info, func(data string) bool {
|
||||
if lastStreamData != "" {
|
||||
@@ -135,35 +131,12 @@ func OaiStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Re
|
||||
}
|
||||
}
|
||||
if len(data) > 0 {
|
||||
// 对音频模型,保存倒数第二个stream data
|
||||
if isAudioModel && lastStreamData != "" {
|
||||
secondLastStreamData = lastStreamData
|
||||
}
|
||||
|
||||
lastStreamData = data
|
||||
streamItems = append(streamItems, data)
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
// 对音频模型,从倒数第二个stream data中提取usage信息
|
||||
if isAudioModel && secondLastStreamData != "" {
|
||||
var streamResp struct {
|
||||
Usage *dto.Usage `json:"usage"`
|
||||
}
|
||||
err := json.Unmarshal([]byte(secondLastStreamData), &streamResp)
|
||||
if err == nil && streamResp.Usage != nil && service.ValidUsage(streamResp.Usage) {
|
||||
usage = streamResp.Usage
|
||||
containStreamUsage = true
|
||||
|
||||
if common.DebugEnabled {
|
||||
logger.LogDebug(c, fmt.Sprintf("Audio model usage extracted from second last SSE: PromptTokens=%d, CompletionTokens=%d, TotalTokens=%d, InputTokens=%d, OutputTokens=%d",
|
||||
usage.PromptTokens, usage.CompletionTokens, usage.TotalTokens,
|
||||
usage.InputTokens, usage.OutputTokens))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理最后的响应
|
||||
shouldSendLastResp := true
|
||||
if err := handleLastResponse(lastStreamData, &responseId, &createAt, &systemFingerprint, &model, &usage,
|
||||
|
||||
@@ -5,12 +5,10 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/QuantumNous/new-api/dto"
|
||||
"github.com/QuantumNous/new-api/logger"
|
||||
"github.com/QuantumNous/new-api/model"
|
||||
"github.com/QuantumNous/new-api/relay/channel"
|
||||
relaycommon "github.com/QuantumNous/new-api/relay/common"
|
||||
@@ -110,7 +108,6 @@ type TaskAdaptor struct {
|
||||
ChannelType int
|
||||
apiKey string
|
||||
baseURL string
|
||||
aliReq *AliVideoRequest
|
||||
}
|
||||
|
||||
func (a *TaskAdaptor) Init(info *relaycommon.RelayInfo) {
|
||||
@@ -121,16 +118,6 @@ func (a *TaskAdaptor) Init(info *relaycommon.RelayInfo) {
|
||||
|
||||
func (a *TaskAdaptor) ValidateRequestAndSetAction(c *gin.Context, info *relaycommon.RelayInfo) (taskErr *dto.TaskError) {
|
||||
// 阿里通义万相支持 JSON 格式,不使用 multipart
|
||||
var taskReq relaycommon.TaskSubmitReq
|
||||
if err := common.UnmarshalBodyReusable(c, &taskReq); err != nil {
|
||||
return service.TaskErrorWrapper(err, "unmarshal_task_request_failed", http.StatusBadRequest)
|
||||
}
|
||||
aliReq, err := a.convertToAliRequest(info, taskReq)
|
||||
if err != nil {
|
||||
return service.TaskErrorWrapper(err, "convert_to_ali_request_failed", http.StatusInternalServerError)
|
||||
}
|
||||
a.aliReq = aliReq
|
||||
logger.LogJson(c, "ali video request body", aliReq)
|
||||
return relaycommon.ValidateMultipartDirect(c, info)
|
||||
}
|
||||
|
||||
@@ -147,7 +134,13 @@ func (a *TaskAdaptor) BuildRequestHeader(c *gin.Context, req *http.Request, info
|
||||
}
|
||||
|
||||
func (a *TaskAdaptor) BuildRequestBody(c *gin.Context, info *relaycommon.RelayInfo) (io.Reader, error) {
|
||||
bodyBytes, err := common.Marshal(a.aliReq)
|
||||
var taskReq relaycommon.TaskSubmitReq
|
||||
if err := common.UnmarshalBodyReusable(c, &taskReq); err != nil {
|
||||
return nil, errors.Wrap(err, "unmarshal_task_request_failed")
|
||||
}
|
||||
aliReq := a.convertToAliRequest(taskReq)
|
||||
|
||||
bodyBytes, err := common.Marshal(aliReq)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "marshal_ali_request_failed")
|
||||
}
|
||||
@@ -155,31 +148,7 @@ func (a *TaskAdaptor) BuildRequestBody(c *gin.Context, info *relaycommon.RelayIn
|
||||
return bytes.NewReader(bodyBytes), nil
|
||||
}
|
||||
|
||||
func (a *TaskAdaptor) convertToAliRequest(info *relaycommon.RelayInfo, req relaycommon.TaskSubmitReq) (*AliVideoRequest, error) {
|
||||
otherRatios := map[string]map[string]float64{
|
||||
"wan2.5-i2v-preview": {
|
||||
"480P": 1,
|
||||
"720P": 2,
|
||||
"1080P": 1 / 0.3,
|
||||
},
|
||||
"wan2.2-i2v-plus": {
|
||||
"480P": 1,
|
||||
"1080P": 0.7 / 0.14,
|
||||
},
|
||||
"wan2.2-kf2v-flash": {
|
||||
"480P": 1,
|
||||
"720P": 2,
|
||||
"1080P": 4.8,
|
||||
},
|
||||
"wan2.2-i2v-flash": {
|
||||
"480P": 1,
|
||||
"720P": 2,
|
||||
},
|
||||
"wan2.2-s2v": {
|
||||
"480P": 1,
|
||||
"720P": 0.9 / 0.5,
|
||||
},
|
||||
}
|
||||
func (a *TaskAdaptor) convertToAliRequest(req relaycommon.TaskSubmitReq) *AliVideoRequest {
|
||||
aliReq := &AliVideoRequest{
|
||||
Model: req.Model,
|
||||
Input: AliVideoInput{
|
||||
@@ -216,13 +185,6 @@ func (a *TaskAdaptor) convertToAliRequest(info *relaycommon.RelayInfo, req relay
|
||||
// 处理时长
|
||||
if req.Duration > 0 {
|
||||
aliReq.Parameters.Duration = req.Duration
|
||||
} else if req.Seconds != "" {
|
||||
seconds, err := strconv.Atoi(req.Seconds)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "convert seconds to int failed")
|
||||
} else {
|
||||
aliReq.Parameters.Duration = seconds
|
||||
}
|
||||
} else {
|
||||
aliReq.Parameters.Duration = 5 // 默认5秒
|
||||
}
|
||||
@@ -230,32 +192,11 @@ func (a *TaskAdaptor) convertToAliRequest(info *relaycommon.RelayInfo, req relay
|
||||
// 从 metadata 中提取额外参数
|
||||
if req.Metadata != nil {
|
||||
if metadataBytes, err := common.Marshal(req.Metadata); err == nil {
|
||||
err = common.Unmarshal(metadataBytes, aliReq)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unmarshal metadata failed")
|
||||
}
|
||||
} else {
|
||||
return nil, errors.Wrap(err, "marshal metadata failed")
|
||||
_ = common.Unmarshal(metadataBytes, aliReq)
|
||||
}
|
||||
}
|
||||
|
||||
if aliReq.Model != req.Model {
|
||||
return nil, errors.New("can't change model with metadata")
|
||||
}
|
||||
|
||||
info.PriceData.OtherRatios = map[string]float64{
|
||||
"seconds": float64(aliReq.Parameters.Duration),
|
||||
}
|
||||
|
||||
if otherRatio, ok := otherRatios[req.Model]; ok {
|
||||
if ratio, ok := otherRatio[aliReq.Parameters.Resolution]; ok {
|
||||
info.PriceData.OtherRatios[fmt.Sprintf("resolution-%s", aliReq.Parameters.Resolution)] = ratio
|
||||
}
|
||||
}
|
||||
|
||||
// println(fmt.Sprintf("other ratios: %v", info.PriceData.OtherRatios))
|
||||
|
||||
return aliReq, nil
|
||||
return aliReq
|
||||
}
|
||||
|
||||
// DoRequest delegates to common helper
|
||||
|
||||
@@ -2,9 +2,13 @@ package sora
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/QuantumNous/new-api/dto"
|
||||
@@ -87,9 +91,107 @@ func (a *TaskAdaptor) BuildRequestBody(c *gin.Context, info *relaycommon.RelayIn
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get_request_body_failed")
|
||||
}
|
||||
|
||||
// 检查是否需要模型重定向
|
||||
if !info.IsModelMapped {
|
||||
// 如果不需要重定向,直接返回原始请求体
|
||||
return bytes.NewReader(cachedBody), nil
|
||||
}
|
||||
|
||||
contentType := c.Request.Header.Get("Content-Type")
|
||||
|
||||
// 处理multipart/form-data请求
|
||||
if strings.Contains(contentType, "multipart/form-data") {
|
||||
return buildRequestBodyWithMappedModel(cachedBody, contentType, info.UpstreamModelName)
|
||||
}
|
||||
// 处理JSON请求
|
||||
if strings.Contains(contentType, "application/json") {
|
||||
var jsonData map[string]interface{}
|
||||
if err := json.Unmarshal(cachedBody, &jsonData); err != nil {
|
||||
return nil, errors.Wrap(err, "unmarshal_json_failed")
|
||||
}
|
||||
|
||||
// 替换model字段为映射后的模型名
|
||||
jsonData["model"] = info.UpstreamModelName
|
||||
|
||||
// 重新编码为JSON
|
||||
newBody, err := json.Marshal(jsonData)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "marshal_json_failed")
|
||||
}
|
||||
|
||||
return bytes.NewReader(newBody), nil
|
||||
}
|
||||
|
||||
return bytes.NewReader(cachedBody), nil
|
||||
}
|
||||
|
||||
func buildRequestBodyWithMappedModel(originalBody []byte, contentType, redirectedModel string) (io.Reader, error) {
|
||||
newBuffer := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(newBuffer)
|
||||
|
||||
_, params, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "parse_content_type_failed")
|
||||
}
|
||||
boundary, ok := params["boundary"]
|
||||
if !ok {
|
||||
return nil, errors.New("boundary_not_found_in_content_type")
|
||||
}
|
||||
if err := writer.SetBoundary(boundary); err != nil {
|
||||
return nil, errors.Wrap(err, "set_boundary_failed")
|
||||
}
|
||||
r := multipart.NewReader(bytes.NewReader(originalBody), boundary)
|
||||
|
||||
for {
|
||||
part, err := r.NextPart()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "read_multipart_part_failed")
|
||||
}
|
||||
|
||||
fieldName := part.FormName()
|
||||
|
||||
if fieldName == "model" {
|
||||
// 修改 model 字段为映射后的模型名
|
||||
if err := writer.WriteField("model", redirectedModel); err != nil {
|
||||
return nil, errors.Wrap(err, "write_model_field_failed")
|
||||
}
|
||||
} else {
|
||||
// 对于其他字段,保留原始内容
|
||||
if part.FileName() != "" {
|
||||
newPart, err := writer.CreatePart(part.Header)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "create_form_file_failed")
|
||||
}
|
||||
if _, err := io.Copy(newPart, part); err != nil {
|
||||
return nil, errors.Wrap(err, "copy_file_content_failed")
|
||||
}
|
||||
} else {
|
||||
newPart, err := writer.CreatePart(part.Header)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "create_form_field_failed")
|
||||
}
|
||||
if _, err := io.Copy(newPart, part); err != nil {
|
||||
return nil, errors.Wrap(err, "copy_field_content_failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := part.Close(); err != nil {
|
||||
return nil, errors.Wrap(err, "close_part_failed")
|
||||
}
|
||||
}
|
||||
|
||||
if err := writer.Close(); err != nil {
|
||||
return nil, errors.Wrap(err, "close_multipart_writer_failed")
|
||||
}
|
||||
|
||||
return newBuffer, nil
|
||||
}
|
||||
|
||||
// DoRequest delegates to common helper.
|
||||
func (a *TaskAdaptor) DoRequest(c *gin.Context, info *relaycommon.RelayInfo, requestBody io.Reader) (*http.Response, error) {
|
||||
return channel.DoTaskApiRequest(a, c, info, requestBody)
|
||||
|
||||
@@ -121,7 +121,6 @@ func ValidateMultipartDirect(c *gin.Context, info *RelayInfo) *dto.TaskError {
|
||||
|
||||
prompt = req.Prompt
|
||||
model = req.Model
|
||||
size = req.Size
|
||||
seconds, _ = strconv.Atoi(req.Seconds)
|
||||
if seconds == 0 {
|
||||
seconds = req.Duration
|
||||
@@ -224,6 +223,11 @@ func ValidateBasicTaskRequest(c *gin.Context, info *RelayInfo, action string) *d
|
||||
}
|
||||
}
|
||||
|
||||
// 模型映射
|
||||
if info.IsModelMapped {
|
||||
req.Model = info.UpstreamModelName
|
||||
}
|
||||
|
||||
storeTaskRequest(c, info, action, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,9 +13,6 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// https://docs.claude.com/en/docs/build-with-claude/prompt-caching#1-hour-cache-duration
|
||||
const claudeCacheCreation1hMultiplier = 6 / 3.75
|
||||
|
||||
// HandleGroupRatio checks for "auto_group" in the context and updates the group ratio and relayInfo.UsingGroup if present
|
||||
func HandleGroupRatio(ctx *gin.Context, relayInfo *relaycommon.RelayInfo) types.GroupRatioInfo {
|
||||
groupRatioInfo := types.GroupRatioInfo{
|
||||
@@ -56,8 +53,6 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
|
||||
var cacheRatio float64
|
||||
var imageRatio float64
|
||||
var cacheCreationRatio float64
|
||||
var cacheCreationRatio5m float64
|
||||
var cacheCreationRatio1h float64
|
||||
var audioRatio float64
|
||||
var audioCompletionRatio float64
|
||||
var freeModel bool
|
||||
@@ -81,9 +76,6 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
|
||||
completionRatio = ratio_setting.GetCompletionRatio(info.OriginModelName)
|
||||
cacheRatio, _ = ratio_setting.GetCacheRatio(info.OriginModelName)
|
||||
cacheCreationRatio, _ = ratio_setting.GetCreateCacheRatio(info.OriginModelName)
|
||||
cacheCreationRatio5m = cacheCreationRatio
|
||||
// 固定1h和5min缓存写入价格的比例
|
||||
cacheCreationRatio1h = cacheCreationRatio * claudeCacheCreation1hMultiplier
|
||||
imageRatio, _ = ratio_setting.GetImageRatio(info.OriginModelName)
|
||||
audioRatio = ratio_setting.GetAudioRatio(info.OriginModelName)
|
||||
audioCompletionRatio = ratio_setting.GetAudioCompletionRatio(info.OriginModelName)
|
||||
@@ -124,8 +116,6 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
|
||||
AudioRatio: audioRatio,
|
||||
AudioCompletionRatio: audioCompletionRatio,
|
||||
CacheCreationRatio: cacheCreationRatio,
|
||||
CacheCreation5mRatio: cacheCreationRatio5m,
|
||||
CacheCreation1hRatio: cacheCreationRatio1h,
|
||||
QuotaToPreConsume: preConsumedQuota,
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/QuantumNous/new-api/relay/channel"
|
||||
relaycommon "github.com/QuantumNous/new-api/relay/common"
|
||||
relayconstant "github.com/QuantumNous/new-api/relay/constant"
|
||||
"github.com/QuantumNous/new-api/relay/helper"
|
||||
"github.com/QuantumNous/new-api/service"
|
||||
"github.com/QuantumNous/new-api/setting/ratio_setting"
|
||||
|
||||
@@ -38,6 +39,11 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (taskErr *dto.
|
||||
}
|
||||
|
||||
info.InitChannelMeta(c)
|
||||
|
||||
// 模型映射
|
||||
if err := helper.ModelMappedHelper(c, info, nil); err != nil {
|
||||
return service.TaskErrorWrapper(err, "model_mapped_failed", http.StatusBadRequest)
|
||||
}
|
||||
adaptor := GetTaskAdaptor(platform)
|
||||
if adaptor == nil {
|
||||
return service.TaskErrorWrapperLocal(fmt.Errorf("invalid api platform: %s", platform), "invalid_api_platform", http.StatusBadRequest)
|
||||
@@ -208,6 +214,10 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (taskErr *dto.
|
||||
task.Quota = quota
|
||||
task.Data = taskData
|
||||
task.Action = info.Action
|
||||
task.Properties = model.Properties{
|
||||
UpstreamModelName: info.UpstreamModelName,
|
||||
OriginModelName: info.OriginModelName,
|
||||
}
|
||||
err = task.Insert()
|
||||
if err != nil {
|
||||
taskErr = service.TaskErrorWrapper(err, "insert_task_failed", http.StatusInternalServerError)
|
||||
|
||||
@@ -92,23 +92,11 @@ func GenerateAudioOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
|
||||
}
|
||||
|
||||
func GenerateClaudeOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, modelRatio, groupRatio, completionRatio float64,
|
||||
cacheTokens int, cacheRatio float64,
|
||||
cacheCreationTokens int, cacheCreationRatio float64,
|
||||
cacheCreationTokens5m int, cacheCreationRatio5m float64,
|
||||
cacheCreationTokens1h int, cacheCreationRatio1h float64,
|
||||
modelPrice float64, userGroupRatio float64) map[string]interface{} {
|
||||
cacheTokens int, cacheRatio float64, cacheCreationTokens int, cacheCreationRatio float64, modelPrice float64, userGroupRatio float64) map[string]interface{} {
|
||||
info := GenerateTextOtherInfo(ctx, relayInfo, modelRatio, groupRatio, completionRatio, cacheTokens, cacheRatio, modelPrice, userGroupRatio)
|
||||
info["claude"] = true
|
||||
info["cache_creation_tokens"] = cacheCreationTokens
|
||||
info["cache_creation_ratio"] = cacheCreationRatio
|
||||
if cacheCreationTokens5m != 0 {
|
||||
info["cache_creation_tokens_5m"] = cacheCreationTokens5m
|
||||
info["cache_creation_ratio_5m"] = cacheCreationRatio5m
|
||||
}
|
||||
if cacheCreationTokens1h != 0 {
|
||||
info["cache_creation_tokens_1h"] = cacheCreationTokens1h
|
||||
info["cache_creation_ratio_1h"] = cacheCreationRatio1h
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
|
||||
@@ -251,11 +251,7 @@ func PostClaudeConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
|
||||
cacheTokens := usage.PromptTokensDetails.CachedTokens
|
||||
|
||||
cacheCreationRatio := relayInfo.PriceData.CacheCreationRatio
|
||||
cacheCreationRatio5m := relayInfo.PriceData.CacheCreation5mRatio
|
||||
cacheCreationRatio1h := relayInfo.PriceData.CacheCreation1hRatio
|
||||
cacheCreationTokens := usage.PromptTokensDetails.CachedCreationTokens
|
||||
cacheCreationTokens5m := usage.ClaudeCacheCreation5mTokens
|
||||
cacheCreationTokens1h := usage.ClaudeCacheCreation1hTokens
|
||||
|
||||
if relayInfo.ChannelType == constant.ChannelTypeOpenRouter {
|
||||
promptTokens -= cacheTokens
|
||||
@@ -273,12 +269,7 @@ func PostClaudeConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
|
||||
if !relayInfo.PriceData.UsePrice {
|
||||
calculateQuota = float64(promptTokens)
|
||||
calculateQuota += float64(cacheTokens) * cacheRatio
|
||||
calculateQuota += float64(cacheCreationTokens5m) * cacheCreationRatio5m
|
||||
calculateQuota += float64(cacheCreationTokens1h) * cacheCreationRatio1h
|
||||
remainingCacheCreationTokens := cacheCreationTokens - cacheCreationTokens5m - cacheCreationTokens1h
|
||||
if remainingCacheCreationTokens > 0 {
|
||||
calculateQuota += float64(remainingCacheCreationTokens) * cacheCreationRatio
|
||||
}
|
||||
calculateQuota += float64(cacheCreationTokens) * cacheCreationRatio
|
||||
calculateQuota += float64(completionTokens) * completionRatio
|
||||
calculateQuota = calculateQuota * groupRatio * modelRatio
|
||||
} else {
|
||||
@@ -331,11 +322,7 @@ func PostClaudeConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
|
||||
}
|
||||
|
||||
other := GenerateClaudeOtherInfo(ctx, relayInfo, modelRatio, groupRatio, completionRatio,
|
||||
cacheTokens, cacheRatio,
|
||||
cacheCreationTokens, cacheCreationRatio,
|
||||
cacheCreationTokens5m, cacheCreationRatio5m,
|
||||
cacheCreationTokens1h, cacheCreationRatio1h,
|
||||
modelPrice, relayInfo.PriceData.GroupRatioInfo.GroupSpecialRatio)
|
||||
cacheTokens, cacheRatio, cacheCreationTokens, cacheCreationRatio, modelPrice, relayInfo.PriceData.GroupRatioInfo.GroupSpecialRatio)
|
||||
model.RecordConsumeLog(ctx, relayInfo.UserId, model.RecordConsumeLogParams{
|
||||
ChannelId: relayInfo.ChannelId,
|
||||
PromptTokens: promptTokens,
|
||||
|
||||
@@ -15,8 +15,6 @@ type PriceData struct {
|
||||
CompletionRatio float64
|
||||
CacheRatio float64
|
||||
CacheCreationRatio float64
|
||||
CacheCreation5mRatio float64
|
||||
CacheCreation1hRatio float64
|
||||
ImageRatio float64
|
||||
AudioRatio float64
|
||||
AudioCompletionRatio float64
|
||||
@@ -33,5 +31,5 @@ type PerCallPriceData struct {
|
||||
}
|
||||
|
||||
func (p PriceData) ToSetting() string {
|
||||
return fmt.Sprintf("ModelPrice: %f, ModelRatio: %f, CompletionRatio: %f, CacheRatio: %f, GroupRatio: %f, UsePrice: %t, CacheCreationRatio: %f, CacheCreation5mRatio: %f, CacheCreation1hRatio: %f, QuotaToPreConsume: %d, ImageRatio: %f, AudioRatio: %f, AudioCompletionRatio: %f", p.ModelPrice, p.ModelRatio, p.CompletionRatio, p.CacheRatio, p.GroupRatioInfo.GroupRatio, p.UsePrice, p.CacheCreationRatio, p.CacheCreation5mRatio, p.CacheCreation1hRatio, p.QuotaToPreConsume, p.ImageRatio, p.AudioRatio, p.AudioCompletionRatio)
|
||||
return fmt.Sprintf("ModelPrice: %f, ModelRatio: %f, CompletionRatio: %f, CacheRatio: %f, GroupRatio: %f, UsePrice: %t, CacheCreationRatio: %f, QuotaToPreConsume: %d, ImageRatio: %f, AudioRatio: %f, AudioCompletionRatio: %f", p.ModelPrice, p.ModelRatio, p.CompletionRatio, p.CacheRatio, p.GroupRatioInfo.GroupRatio, p.UsePrice, p.CacheCreationRatio, p.QuotaToPreConsume, p.ImageRatio, p.AudioRatio, p.AudioCompletionRatio)
|
||||
}
|
||||
|
||||
@@ -551,10 +551,6 @@ export const getLogsColumns = ({
|
||||
other.cache_ratio || 1.0,
|
||||
other.cache_creation_tokens || 0,
|
||||
other.cache_creation_ratio || 1.0,
|
||||
other.cache_creation_tokens_5m || 0,
|
||||
other.cache_creation_ratio_5m || other.cache_creation_ratio || 1.0,
|
||||
other.cache_creation_tokens_1h || 0,
|
||||
other.cache_creation_ratio_1h || other.cache_creation_ratio || 1.0,
|
||||
false,
|
||||
1.0,
|
||||
other?.is_system_prompt_overwritten,
|
||||
@@ -569,10 +565,6 @@ export const getLogsColumns = ({
|
||||
other.cache_ratio || 1.0,
|
||||
0,
|
||||
1.0,
|
||||
0,
|
||||
1.0,
|
||||
0,
|
||||
1.0,
|
||||
false,
|
||||
1.0,
|
||||
other?.is_system_prompt_overwritten,
|
||||
|
||||
@@ -1046,10 +1046,6 @@ function renderPriceSimpleCore({
|
||||
cacheRatio = 1.0,
|
||||
cacheCreationTokens = 0,
|
||||
cacheCreationRatio = 1.0,
|
||||
cacheCreationTokens5m = 0,
|
||||
cacheCreationRatio5m = 1.0,
|
||||
cacheCreationTokens1h = 0,
|
||||
cacheCreationRatio1h = 1.0,
|
||||
image = false,
|
||||
imageRatio = 1.0,
|
||||
isSystemPromptOverride = false,
|
||||
@@ -1068,40 +1064,17 @@ function renderPriceSimpleCore({
|
||||
});
|
||||
}
|
||||
|
||||
const hasSplitCacheCreation =
|
||||
cacheCreationTokens5m > 0 || cacheCreationTokens1h > 0;
|
||||
|
||||
const shouldShowLegacyCacheCreation =
|
||||
!hasSplitCacheCreation && cacheCreationTokens !== 0;
|
||||
|
||||
const shouldShowCache = cacheTokens !== 0;
|
||||
const shouldShowCacheCreation5m =
|
||||
hasSplitCacheCreation && cacheCreationTokens5m > 0;
|
||||
const shouldShowCacheCreation1h =
|
||||
hasSplitCacheCreation && cacheCreationTokens1h > 0;
|
||||
|
||||
const parts = [];
|
||||
// base: model ratio
|
||||
parts.push(i18next.t('模型: {{ratio}}'));
|
||||
|
||||
// cache part (label differs when with image)
|
||||
if (shouldShowCache) {
|
||||
if (cacheTokens !== 0) {
|
||||
parts.push(i18next.t('缓存: {{cacheRatio}}'));
|
||||
}
|
||||
|
||||
if (hasSplitCacheCreation) {
|
||||
if (shouldShowCacheCreation5m && shouldShowCacheCreation1h) {
|
||||
parts.push(
|
||||
i18next.t(
|
||||
'缓存创建: 5m {{cacheCreationRatio5m}} / 1h {{cacheCreationRatio1h}}',
|
||||
),
|
||||
);
|
||||
} else if (shouldShowCacheCreation5m) {
|
||||
parts.push(i18next.t('缓存创建: 5m {{cacheCreationRatio5m}}'));
|
||||
} else if (shouldShowCacheCreation1h) {
|
||||
parts.push(i18next.t('缓存创建: 1h {{cacheCreationRatio1h}}'));
|
||||
}
|
||||
} else if (shouldShowLegacyCacheCreation) {
|
||||
// cache creation part (Claude specific if passed)
|
||||
if (cacheCreationTokens !== 0) {
|
||||
parts.push(i18next.t('缓存创建: {{cacheCreationRatio}}'));
|
||||
}
|
||||
|
||||
@@ -1118,8 +1091,6 @@ function renderPriceSimpleCore({
|
||||
groupRatio: finalGroupRatio,
|
||||
cacheRatio: cacheRatio,
|
||||
cacheCreationRatio: cacheCreationRatio,
|
||||
cacheCreationRatio5m: cacheCreationRatio5m,
|
||||
cacheCreationRatio1h: cacheCreationRatio1h,
|
||||
imageRatio: imageRatio,
|
||||
});
|
||||
|
||||
@@ -1479,10 +1450,6 @@ export function renderModelPriceSimple(
|
||||
cacheRatio = 1.0,
|
||||
cacheCreationTokens = 0,
|
||||
cacheCreationRatio = 1.0,
|
||||
cacheCreationTokens5m = 0,
|
||||
cacheCreationRatio5m = 1.0,
|
||||
cacheCreationTokens1h = 0,
|
||||
cacheCreationRatio1h = 1.0,
|
||||
image = false,
|
||||
imageRatio = 1.0,
|
||||
isSystemPromptOverride = false,
|
||||
@@ -1497,10 +1464,6 @@ export function renderModelPriceSimple(
|
||||
cacheRatio,
|
||||
cacheCreationTokens,
|
||||
cacheCreationRatio,
|
||||
cacheCreationTokens5m,
|
||||
cacheCreationRatio5m,
|
||||
cacheCreationTokens1h,
|
||||
cacheCreationRatio1h,
|
||||
image,
|
||||
imageRatio,
|
||||
isSystemPromptOverride,
|
||||
@@ -1718,10 +1681,6 @@ export function renderClaudeModelPrice(
|
||||
cacheRatio = 1.0,
|
||||
cacheCreationTokens = 0,
|
||||
cacheCreationRatio = 1.0,
|
||||
cacheCreationTokens5m = 0,
|
||||
cacheCreationRatio5m = 1.0,
|
||||
cacheCreationTokens1h = 0,
|
||||
cacheCreationRatio1h = 1.0,
|
||||
) {
|
||||
const { ratio: effectiveGroupRatio, label: ratioLabel } = getEffectiveRatio(
|
||||
groupRatio,
|
||||
@@ -1751,121 +1710,20 @@ export function renderClaudeModelPrice(
|
||||
const completionRatioValue = completionRatio || 0;
|
||||
const inputRatioPrice = modelRatio * 2.0;
|
||||
const completionRatioPrice = modelRatio * 2.0 * completionRatioValue;
|
||||
const cacheRatioPrice = modelRatio * 2.0 * cacheRatio;
|
||||
const cacheCreationRatioPrice = modelRatio * 2.0 * cacheCreationRatio;
|
||||
const cacheCreationRatioPrice5m = modelRatio * 2.0 * cacheCreationRatio5m;
|
||||
const cacheCreationRatioPrice1h = modelRatio * 2.0 * cacheCreationRatio1h;
|
||||
|
||||
const hasSplitCacheCreation =
|
||||
cacheCreationTokens5m > 0 || cacheCreationTokens1h > 0;
|
||||
|
||||
const shouldShowCache = cacheTokens > 0;
|
||||
const shouldShowLegacyCacheCreation =
|
||||
!hasSplitCacheCreation && cacheCreationTokens > 0;
|
||||
const shouldShowCacheCreation5m =
|
||||
hasSplitCacheCreation && cacheCreationTokens5m > 0;
|
||||
const shouldShowCacheCreation1h =
|
||||
hasSplitCacheCreation && cacheCreationTokens1h > 0;
|
||||
let cacheRatioPrice = (modelRatio * 2.0 * cacheRatio).toFixed(2);
|
||||
let cacheCreationRatioPrice = modelRatio * 2.0 * cacheCreationRatio;
|
||||
|
||||
// Calculate effective input tokens (non-cached + cached with ratio applied + cache creation with ratio applied)
|
||||
const nonCachedTokens = inputTokens;
|
||||
const effectiveInputTokens =
|
||||
nonCachedTokens +
|
||||
cacheTokens * cacheRatio +
|
||||
cacheCreationTokens * cacheCreationRatio +
|
||||
cacheCreationTokens5m * cacheCreationRatio5m +
|
||||
cacheCreationTokens1h * cacheCreationRatio1h;
|
||||
cacheCreationTokens * cacheCreationRatio;
|
||||
|
||||
let price =
|
||||
(effectiveInputTokens / 1000000) * inputRatioPrice * groupRatio +
|
||||
(completionTokens / 1000000) * completionRatioPrice * groupRatio;
|
||||
|
||||
const inputUnitPrice = inputRatioPrice * rate;
|
||||
const completionUnitPrice = completionRatioPrice * rate;
|
||||
const cacheUnitPrice = cacheRatioPrice * rate;
|
||||
const cacheCreationUnitPrice = cacheCreationRatioPrice * rate;
|
||||
const cacheCreationUnitPrice5m = cacheCreationRatioPrice5m * rate;
|
||||
const cacheCreationUnitPrice1h = cacheCreationRatioPrice1h * rate;
|
||||
const cacheCreationUnitPriceTotal =
|
||||
cacheCreationUnitPrice5m + cacheCreationUnitPrice1h;
|
||||
|
||||
const breakdownSegments = [
|
||||
i18next.t('提示 {{input}} tokens / 1M tokens * {{symbol}}{{price}}', {
|
||||
input: inputTokens,
|
||||
symbol,
|
||||
price: inputUnitPrice.toFixed(6),
|
||||
}),
|
||||
];
|
||||
|
||||
if (shouldShowCache) {
|
||||
breakdownSegments.push(
|
||||
i18next.t(
|
||||
'缓存 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}} (倍率: {{ratio}})',
|
||||
{
|
||||
tokens: cacheTokens,
|
||||
symbol,
|
||||
price: cacheUnitPrice.toFixed(6),
|
||||
ratio: cacheRatio,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (shouldShowLegacyCacheCreation) {
|
||||
breakdownSegments.push(
|
||||
i18next.t(
|
||||
'缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}} (倍率: {{ratio}})',
|
||||
{
|
||||
tokens: cacheCreationTokens,
|
||||
symbol,
|
||||
price: cacheCreationUnitPrice.toFixed(6),
|
||||
ratio: cacheCreationRatio,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (shouldShowCacheCreation5m) {
|
||||
breakdownSegments.push(
|
||||
i18next.t(
|
||||
'5m缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}} (倍率: {{ratio}})',
|
||||
{
|
||||
tokens: cacheCreationTokens5m,
|
||||
symbol,
|
||||
price: cacheCreationUnitPrice5m.toFixed(6),
|
||||
ratio: cacheCreationRatio5m,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (shouldShowCacheCreation1h) {
|
||||
breakdownSegments.push(
|
||||
i18next.t(
|
||||
'1h缓存创建 {{tokens}} tokens / 1M tokens * {{symbol}}{{price}} (倍率: {{ratio}})',
|
||||
{
|
||||
tokens: cacheCreationTokens1h,
|
||||
symbol,
|
||||
price: cacheCreationUnitPrice1h.toFixed(6),
|
||||
ratio: cacheCreationRatio1h,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
breakdownSegments.push(
|
||||
i18next.t(
|
||||
'补全 {{completion}} tokens / 1M tokens * {{symbol}}{{price}}',
|
||||
{
|
||||
completion: completionTokens,
|
||||
symbol,
|
||||
price: completionUnitPrice.toFixed(6),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const breakdownText = breakdownSegments.join(' + ');
|
||||
|
||||
return (
|
||||
<>
|
||||
<article>
|
||||
@@ -1886,7 +1744,7 @@ export function renderClaudeModelPrice(
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
{shouldShowCache && (
|
||||
{cacheTokens > 0 && (
|
||||
<p>
|
||||
{i18next.t(
|
||||
'缓存价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存倍率: {{cacheRatio}})',
|
||||
@@ -1894,13 +1752,13 @@ export function renderClaudeModelPrice(
|
||||
symbol: symbol,
|
||||
price: (inputRatioPrice * rate).toFixed(6),
|
||||
ratio: cacheRatio,
|
||||
total: cacheUnitPrice.toFixed(6),
|
||||
total: (cacheRatioPrice * rate).toFixed(2),
|
||||
cacheRatio: cacheRatio,
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{shouldShowLegacyCacheCreation && (
|
||||
{cacheCreationTokens > 0 && (
|
||||
<p>
|
||||
{i18next.t(
|
||||
'缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})',
|
||||
@@ -1908,65 +1766,49 @@ export function renderClaudeModelPrice(
|
||||
symbol: symbol,
|
||||
price: (inputRatioPrice * rate).toFixed(6),
|
||||
ratio: cacheCreationRatio,
|
||||
total: cacheCreationUnitPrice.toFixed(6),
|
||||
total: (cacheCreationRatioPrice * rate).toFixed(6),
|
||||
cacheCreationRatio: cacheCreationRatio,
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{shouldShowCacheCreation5m && (
|
||||
<p>
|
||||
{i18next.t(
|
||||
'5m缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (5m缓存创建倍率: {{cacheCreationRatio5m}})',
|
||||
{
|
||||
symbol: symbol,
|
||||
price: (inputRatioPrice * rate).toFixed(6),
|
||||
ratio: cacheCreationRatio5m,
|
||||
total: cacheCreationUnitPrice5m.toFixed(6),
|
||||
cacheCreationRatio5m: cacheCreationRatio5m,
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{shouldShowCacheCreation1h && (
|
||||
<p>
|
||||
{i18next.t(
|
||||
'1h缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (1h缓存创建倍率: {{cacheCreationRatio1h}})',
|
||||
{
|
||||
symbol: symbol,
|
||||
price: (inputRatioPrice * rate).toFixed(6),
|
||||
ratio: cacheCreationRatio1h,
|
||||
total: cacheCreationUnitPrice1h.toFixed(6),
|
||||
cacheCreationRatio1h: cacheCreationRatio1h,
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{shouldShowCacheCreation5m && shouldShowCacheCreation1h && (
|
||||
<p>
|
||||
{i18next.t(
|
||||
'缓存创建价格合计:5m {{symbol}}{{five}} + 1h {{symbol}}{{one}} = {{symbol}}{{total}} / 1M tokens',
|
||||
{
|
||||
symbol: symbol,
|
||||
five: cacheCreationUnitPrice5m.toFixed(6),
|
||||
one: cacheCreationUnitPrice1h.toFixed(6),
|
||||
total: cacheCreationUnitPriceTotal.toFixed(6),
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
<p></p>
|
||||
<p>
|
||||
{i18next.t(
|
||||
'{{breakdown}} * {{ratioType}} {{ratio}} = {{symbol}}{{total}}',
|
||||
{
|
||||
breakdown: breakdownText,
|
||||
ratioType: ratioLabel,
|
||||
ratio: groupRatio,
|
||||
symbol: symbol,
|
||||
total: (price * rate).toFixed(6),
|
||||
},
|
||||
)}
|
||||
{cacheTokens > 0 || cacheCreationTokens > 0
|
||||
? i18next.t(
|
||||
'提示 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}} + 缓存创建 {{cacheCreationInput}} tokens / 1M tokens * {{symbol}}{{cacheCreationPrice}} + 补全 {{completion}} tokens / 1M tokens * {{symbol}}{{compPrice}} * {{ratioType}} {{ratio}} = {{symbol}}{{total}}',
|
||||
{
|
||||
nonCacheInput: nonCachedTokens,
|
||||
cacheInput: cacheTokens,
|
||||
cacheRatio: cacheRatio,
|
||||
cacheCreationInput: cacheCreationTokens,
|
||||
cacheCreationRatio: cacheCreationRatio,
|
||||
symbol: symbol,
|
||||
cachePrice: (cacheRatioPrice * rate).toFixed(2),
|
||||
cacheCreationPrice: (
|
||||
cacheCreationRatioPrice * rate
|
||||
).toFixed(6),
|
||||
price: (inputRatioPrice * rate).toFixed(6),
|
||||
completion: completionTokens,
|
||||
compPrice: (completionRatioPrice * rate).toFixed(6),
|
||||
ratio: groupRatio,
|
||||
ratioType: ratioLabel,
|
||||
total: (price * rate).toFixed(6),
|
||||
},
|
||||
)
|
||||
: i18next.t(
|
||||
'提示 {{input}} tokens / 1M tokens * {{symbol}}{{price}} + 补全 {{completion}} tokens / 1M tokens * {{symbol}}{{compPrice}} * {{ratioType}} {{ratio}} = {{symbol}}{{total}}',
|
||||
{
|
||||
input: inputTokens,
|
||||
symbol: symbol,
|
||||
price: (inputRatioPrice * rate).toFixed(6),
|
||||
completion: completionTokens,
|
||||
compPrice: (completionRatioPrice * rate).toFixed(6),
|
||||
ratio: groupRatio,
|
||||
ratioType: ratioLabel,
|
||||
total: (price * rate).toFixed(6),
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
<p>{i18next.t('仅供参考,以实际扣费为准')}</p>
|
||||
</article>
|
||||
@@ -1983,10 +1825,6 @@ export function renderClaudeLogContent(
|
||||
user_group_ratio,
|
||||
cacheRatio = 1.0,
|
||||
cacheCreationRatio = 1.0,
|
||||
cacheCreationTokens5m = 0,
|
||||
cacheCreationRatio5m = 1.0,
|
||||
cacheCreationTokens1h = 0,
|
||||
cacheCreationRatio1h = 1.0,
|
||||
) {
|
||||
const { ratio: effectiveGroupRatio, label: ratioLabel } = getEffectiveRatio(
|
||||
groupRatio,
|
||||
@@ -2005,58 +1843,17 @@ export function renderClaudeLogContent(
|
||||
ratio: groupRatio,
|
||||
});
|
||||
} else {
|
||||
const hasSplitCacheCreation =
|
||||
cacheCreationTokens5m > 0 || cacheCreationTokens1h > 0;
|
||||
const shouldShowCacheCreation5m =
|
||||
hasSplitCacheCreation && cacheCreationTokens5m > 0;
|
||||
const shouldShowCacheCreation1h =
|
||||
hasSplitCacheCreation && cacheCreationTokens1h > 0;
|
||||
|
||||
let cacheCreationPart = null;
|
||||
if (hasSplitCacheCreation) {
|
||||
if (shouldShowCacheCreation5m && shouldShowCacheCreation1h) {
|
||||
cacheCreationPart = i18next.t(
|
||||
'缓存创建倍率 5m {{cacheCreationRatio5m}} / 1h {{cacheCreationRatio1h}}',
|
||||
{
|
||||
cacheCreationRatio5m,
|
||||
cacheCreationRatio1h,
|
||||
},
|
||||
);
|
||||
} else if (shouldShowCacheCreation5m) {
|
||||
cacheCreationPart = i18next.t(
|
||||
'缓存创建倍率 5m {{cacheCreationRatio5m}}',
|
||||
{
|
||||
cacheCreationRatio5m,
|
||||
},
|
||||
);
|
||||
} else if (shouldShowCacheCreation1h) {
|
||||
cacheCreationPart = i18next.t(
|
||||
'缓存创建倍率 1h {{cacheCreationRatio1h}}',
|
||||
{
|
||||
cacheCreationRatio1h,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cacheCreationPart) {
|
||||
cacheCreationPart = i18next.t('缓存创建倍率 {{cacheCreationRatio}}', {
|
||||
cacheCreationRatio,
|
||||
});
|
||||
}
|
||||
|
||||
const parts = [
|
||||
i18next.t('模型倍率 {{modelRatio}}', { modelRatio }),
|
||||
i18next.t('输出倍率 {{completionRatio}}', { completionRatio }),
|
||||
i18next.t('缓存倍率 {{cacheRatio}}', { cacheRatio }),
|
||||
cacheCreationPart,
|
||||
i18next.t('{{ratioType}} {{ratio}}', {
|
||||
return i18next.t(
|
||||
'模型倍率 {{modelRatio}},输出倍率 {{completionRatio}},缓存倍率 {{cacheRatio}},缓存创建倍率 {{cacheCreationRatio}},{{ratioType}} {{ratio}}',
|
||||
{
|
||||
modelRatio: modelRatio,
|
||||
completionRatio: completionRatio,
|
||||
cacheRatio: cacheRatio,
|
||||
cacheCreationRatio: cacheCreationRatio,
|
||||
ratioType: ratioLabel,
|
||||
ratio: groupRatio,
|
||||
}),
|
||||
];
|
||||
|
||||
return parts.join(',');
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -361,10 +361,6 @@ export const useLogsData = () => {
|
||||
other?.user_group_ratio,
|
||||
other.cache_ratio || 1.0,
|
||||
other.cache_creation_ratio || 1.0,
|
||||
other.cache_creation_tokens_5m || 0,
|
||||
other.cache_creation_ratio_5m || other.cache_creation_ratio || 1.0,
|
||||
other.cache_creation_tokens_1h || 0,
|
||||
other.cache_creation_ratio_1h || other.cache_creation_ratio || 1.0,
|
||||
)
|
||||
: renderLogContent(
|
||||
other?.model_ratio,
|
||||
@@ -433,10 +429,6 @@ export const useLogsData = () => {
|
||||
other.cache_ratio || 1.0,
|
||||
other.cache_creation_tokens || 0,
|
||||
other.cache_creation_ratio || 1.0,
|
||||
other.cache_creation_tokens_5m || 0,
|
||||
other.cache_creation_ratio_5m || other.cache_creation_ratio || 1.0,
|
||||
other.cache_creation_tokens_1h || 0,
|
||||
other.cache_creation_ratio_1h || other.cache_creation_ratio || 1.0,
|
||||
);
|
||||
} else {
|
||||
content = renderModelPrice(
|
||||
|
||||
@@ -1516,10 +1516,6 @@
|
||||
"缓存倍率": "Cache ratio",
|
||||
"缓存创建 Tokens": "Cache Creation Tokens",
|
||||
"缓存创建: {{cacheCreationRatio}}": "Cache creation: {{cacheCreationRatio}}",
|
||||
"缓存创建: 5m {{cacheCreationRatio5m}}": "Cache creation: 5m {{cacheCreationRatio5m}}",
|
||||
"缓存创建: 1h {{cacheCreationRatio1h}}": "Cache creation: 1h {{cacheCreationRatio1h}}",
|
||||
"缓存创建倍率 5m {{cacheCreationRatio5m}}": "Cache creation multiplier 5m {{cacheCreationRatio5m}}",
|
||||
"缓存创建倍率 1h {{cacheCreationRatio1h}}": "Cache creation multiplier 1h {{cacheCreationRatio1h}}",
|
||||
"缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})": "Cache creation price: {{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (Cache creation ratio: {{cacheCreationRatio}})",
|
||||
"编辑": "Edit",
|
||||
"编辑API": "Edit API",
|
||||
@@ -2108,4 +2104,4 @@
|
||||
"统一的": "The Unified",
|
||||
"大模型接口网关": "LLM API Gateway"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1525,10 +1525,6 @@
|
||||
"缓存倍率": "Ratio de cache",
|
||||
"缓存创建 Tokens": "Jetons de création de cache",
|
||||
"缓存创建: {{cacheCreationRatio}}": "Création de cache : {{cacheCreationRatio}}",
|
||||
"缓存创建: 5m {{cacheCreationRatio5m}}": "Création de cache : 5m {{cacheCreationRatio5m}}",
|
||||
"缓存创建: 1h {{cacheCreationRatio1h}}": "Création de cache : 1h {{cacheCreationRatio1h}}",
|
||||
"缓存创建倍率 5m {{cacheCreationRatio5m}}": "Multiplicateur de création de cache 5m {{cacheCreationRatio5m}}",
|
||||
"缓存创建倍率 1h {{cacheCreationRatio1h}}": "Multiplicateur de création de cache 1h {{cacheCreationRatio1h}}",
|
||||
"缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})": "Prix de création du cache : {{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (taux de création de cache : {{cacheCreationRatio}})",
|
||||
"编辑": "Modifier",
|
||||
"编辑API": "Modifier l'API",
|
||||
|
||||
@@ -1516,10 +1516,6 @@
|
||||
"缓存倍率": "キャッシュ倍率",
|
||||
"缓存创建 Tokens": "キャッシュ作成トークン",
|
||||
"缓存创建: {{cacheCreationRatio}}": "キャッシュ作成:{{cacheCreationRatio}}",
|
||||
"缓存创建: 5m {{cacheCreationRatio5m}}": "キャッシュ作成:5m {{cacheCreationRatio5m}}",
|
||||
"缓存创建: 1h {{cacheCreationRatio1h}}": "キャッシュ作成:1h {{cacheCreationRatio1h}}",
|
||||
"缓存创建倍率 5m {{cacheCreationRatio5m}}": "キャッシュ作成倍率 5m {{cacheCreationRatio5m}}",
|
||||
"缓存创建倍率 1h {{cacheCreationRatio1h}}": "キャッシュ作成倍率 1h {{cacheCreationRatio1h}}",
|
||||
"缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})": "キャッシュ作成料金:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1Mtokens(キャッシュ作成倍率:{{cacheCreationRatio}})",
|
||||
"编辑": "編集",
|
||||
"编辑API": "API編集",
|
||||
@@ -2079,4 +2075,4 @@
|
||||
"统一的": "統合型",
|
||||
"大模型接口网关": "LLM APIゲートウェイ"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1534,10 +1534,6 @@
|
||||
"缓存倍率": "Коэффициент кэширования",
|
||||
"缓存创建 Tokens": "Создание кэша токенов",
|
||||
"缓存创建: {{cacheCreationRatio}}": "Создание кэша: {{cacheCreationRatio}}",
|
||||
"缓存创建: 5m {{cacheCreationRatio5m}}": "Создание кэша: 5m {{cacheCreationRatio5m}}",
|
||||
"缓存创建: 1h {{cacheCreationRatio1h}}": "Создание кэша: 1h {{cacheCreationRatio1h}}",
|
||||
"缓存创建倍率 5m {{cacheCreationRatio5m}}": "Множитель создания кэша 5m {{cacheCreationRatio5m}}",
|
||||
"缓存创建倍率 1h {{cacheCreationRatio1h}}": "Множитель создания кэша 1h {{cacheCreationRatio1h}}",
|
||||
"缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})": "Цена создания кэша: {{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M токенов (коэффициент создания кэша: {{cacheCreationRatio}})",
|
||||
"编辑": "Редактировать",
|
||||
"编辑API": "Редактировать API",
|
||||
|
||||
@@ -1507,10 +1507,6 @@
|
||||
"缓存倍率": "缓存倍率",
|
||||
"缓存创建 Tokens": "缓存创建 Tokens",
|
||||
"缓存创建: {{cacheCreationRatio}}": "缓存创建: {{cacheCreationRatio}}",
|
||||
"缓存创建: 5m {{cacheCreationRatio5m}}": "缓存创建: 5m {{cacheCreationRatio5m}}",
|
||||
"缓存创建: 1h {{cacheCreationRatio1h}}": "缓存创建: 1h {{cacheCreationRatio1h}}",
|
||||
"缓存创建倍率 5m {{cacheCreationRatio5m}}": "缓存创建倍率 5m {{cacheCreationRatio5m}}",
|
||||
"缓存创建倍率 1h {{cacheCreationRatio1h}}": "缓存创建倍率 1h {{cacheCreationRatio1h}}",
|
||||
"缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})": "缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})",
|
||||
"编辑": "编辑",
|
||||
"编辑API": "编辑API",
|
||||
@@ -2070,4 +2066,4 @@
|
||||
"Creem 介绍": "Creem 是一个简单的支付处理平台,支持固定金额产品销售,以及订阅销售。",
|
||||
"Creem Setting Tips": "Creem 只支持预设的固定金额产品,这产品以及价格需要提前在Creem网站内创建配置,所以不支持自定义动态金额充值。在Creem端配置产品的名字以及价格,获取Product Id 后填到下面的产品,在new-api为该产品设置充值额度,以及展示价格。"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user