diff --git a/common/model-ratio.go b/common/model-ratio.go index b0a97c0..9ddbe12 100644 --- a/common/model-ratio.go +++ b/common/model-ratio.go @@ -28,6 +28,7 @@ var DefaultModelRatio = map[string]float64{ "gpt-4-vision-preview": 5, // $0.01 / 1K tokens "gpt-4-1106-vision-preview": 5, // $0.01 / 1K tokens "gpt-4-turbo": 5, // $0.01 / 1K tokens + "gpt-4-turbo-2024-04-09": 5, // $0.01 / 1K tokens "gpt-3.5-turbo": 0.25, // $0.0015 / 1K tokens //"gpt-3.5-turbo-0301": 0.75, //deprecated "gpt-3.5-turbo-0613": 0.75, diff --git a/common/utils.go b/common/utils.go index d540c2e..657ffd4 100644 --- a/common/utils.go +++ b/common/utils.go @@ -1,6 +1,7 @@ package common import ( + "encoding/json" "fmt" "github.com/google/uuid" "html/template" @@ -241,3 +242,11 @@ func RandomSleep() { // Sleep for 0-3000 ms time.Sleep(time.Duration(rand.Intn(3000)) * time.Millisecond) } + +func MapToJsonStr(m map[string]interface{}) string { + bytes, err := json.Marshal(m) + if err != nil { + return "" + } + return string(bytes) +} diff --git a/model/log.go b/model/log.go index 2740c5a..57c64d0 100644 --- a/model/log.go +++ b/model/log.go @@ -24,6 +24,7 @@ type Log struct { IsStream bool `json:"is_stream" gorm:"default:false"` ChannelId int `json:"channel" gorm:"index"` TokenId int `json:"token_id" gorm:"default:0;index"` + Other string `json:"other"` } const ( @@ -57,12 +58,13 @@ func RecordLog(userId int, logType int, content string) { } } -func RecordConsumeLog(ctx context.Context, userId int, channelId int, promptTokens int, completionTokens int, modelName string, tokenName string, quota int, content string, tokenId int, userQuota int, useTimeSeconds int, isStream bool) { +func RecordConsumeLog(ctx context.Context, userId int, channelId int, promptTokens int, completionTokens int, modelName string, tokenName string, quota int, content string, tokenId int, userQuota int, useTimeSeconds int, isStream bool, other map[string]interface{}) { common.LogInfo(ctx, fmt.Sprintf("record consume log: userId=%d, 用户调用前余额=%d, channelId=%d, promptTokens=%d, completionTokens=%d, modelName=%s, tokenName=%s, quota=%d, content=%s", userId, userQuota, channelId, promptTokens, completionTokens, modelName, tokenName, quota, content)) if !common.LogConsumeEnabled { return } username, _ := CacheGetUsername(userId) + otherStr := common.MapToJsonStr(other) log := &Log{ UserId: userId, Username: username, @@ -78,6 +80,7 @@ func RecordConsumeLog(ctx context.Context, userId int, channelId int, promptToke TokenId: tokenId, UseTime: useTimeSeconds, IsStream: isStream, + Other: otherStr, } err := DB.Create(log).Error if err != nil { diff --git a/relay/relay-audio.go b/relay/relay-audio.go index 09ac2a0..ef89597 100644 --- a/relay/relay-audio.go +++ b/relay/relay-audio.go @@ -196,7 +196,10 @@ func AudioHelper(c *gin.Context, relayMode int) *dto.OpenAIErrorWithStatusCode { if quota != 0 { tokenName := c.GetString("token_name") logContent := fmt.Sprintf("模型倍率 %.2f,分组倍率 %.2f", modelRatio, groupRatio) - model.RecordConsumeLog(ctx, userId, channelId, promptTokens, 0, audioRequest.Model, tokenName, quota, logContent, tokenId, userQuota, int(useTimeSeconds), false) + other := make(map[string]interface{}) + other["model_ratio"] = modelRatio + other["group_ratio"] = groupRatio + model.RecordConsumeLog(ctx, userId, channelId, promptTokens, 0, audioRequest.Model, tokenName, quota, logContent, tokenId, userQuota, int(useTimeSeconds), false, other) model.UpdateUserUsedQuotaAndRequestCount(userId, quota) channelId := c.GetInt("channel_id") model.UpdateChannelUsedQuota(channelId, quota) diff --git a/relay/relay-image.go b/relay/relay-image.go index ce072d1..7f8cd9e 100644 --- a/relay/relay-image.go +++ b/relay/relay-image.go @@ -191,7 +191,10 @@ func RelayImageHelper(c *gin.Context, relayMode int) *dto.OpenAIErrorWithStatusC quality = "hd" } logContent := fmt.Sprintf("模型倍率 %.2f,分组倍率 %.2f, 大小 %s, 品质 %s", modelRatio, groupRatio, imageRequest.Size, quality) - model.RecordConsumeLog(ctx, userId, channelId, 0, 0, imageRequest.Model, tokenName, quota, logContent, tokenId, userQuota, int(useTimeSeconds), false) + other := make(map[string]interface{}) + other["model_ratio"] = modelRatio + other["group_ratio"] = groupRatio + model.RecordConsumeLog(ctx, userId, channelId, 0, 0, imageRequest.Model, tokenName, quota, logContent, tokenId, userQuota, int(useTimeSeconds), false, other) model.UpdateUserUsedQuotaAndRequestCount(userId, quota) channelId := c.GetInt("channel_id") model.UpdateChannelUsedQuota(channelId, quota) diff --git a/relay/relay-mj.go b/relay/relay-mj.go index 27b4c6d..16ad412 100644 --- a/relay/relay-mj.go +++ b/relay/relay-mj.go @@ -202,7 +202,10 @@ func RelaySwapFace(c *gin.Context) *dto.MidjourneyResponse { if quota != 0 { tokenName := c.GetString("token_name") logContent := fmt.Sprintf("模型固定价格 %.2f,分组倍率 %.2f,操作 %s", modelPrice, groupRatio, constant.MjActionSwapFace) - model.RecordConsumeLog(ctx, userId, channelId, 0, 0, modelName, tokenName, quota, logContent, tokenId, userQuota, 0, false) + other := make(map[string]interface{}) + other["model_price"] = modelPrice + other["group_ratio"] = groupRatio + model.RecordConsumeLog(ctx, userId, channelId, 0, 0, modelName, tokenName, quota, logContent, tokenId, userQuota, 0, false, other) model.UpdateUserUsedQuotaAndRequestCount(userId, quota) channelId := c.GetInt("channel_id") model.UpdateChannelUsedQuota(channelId, quota) @@ -498,7 +501,10 @@ func RelayMidjourneySubmit(c *gin.Context, relayMode int) *dto.MidjourneyRespons if quota != 0 { tokenName := c.GetString("token_name") logContent := fmt.Sprintf("模型固定价格 %.2f,分组倍率 %.2f,操作 %s", modelPrice, groupRatio, midjRequest.Action) - model.RecordConsumeLog(ctx, userId, channelId, 0, 0, modelName, tokenName, quota, logContent, tokenId, userQuota, 0, false) + other := make(map[string]interface{}) + other["model_price"] = modelPrice + other["group_ratio"] = groupRatio + model.RecordConsumeLog(ctx, userId, channelId, 0, 0, modelName, tokenName, quota, logContent, tokenId, userQuota, 0, false, other) model.UpdateUserUsedQuotaAndRequestCount(userId, quota) channelId := c.GetInt("channel_id") model.UpdateChannelUsedQuota(channelId, quota) diff --git a/relay/relay-text.go b/relay/relay-text.go index 7c2720e..9010381 100644 --- a/relay/relay-text.go +++ b/relay/relay-text.go @@ -315,7 +315,12 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, textRe logModel = "gpt-4-gizmo-*" logContent += fmt.Sprintf(",模型 %s", textRequest.Model) } - model.RecordConsumeLog(ctx, relayInfo.UserId, relayInfo.ChannelId, promptTokens, completionTokens, logModel, tokenName, quota, logContent, relayInfo.TokenId, userQuota, int(useTimeSeconds), relayInfo.IsStream) + other := make(map[string]interface{}) + other["model_ratio"] = modelRatio + other["group_ratio"] = groupRatio + other["completion_ratio"] = completionRatio + other["model_price"] = modelPrice + model.RecordConsumeLog(ctx, relayInfo.UserId, relayInfo.ChannelId, promptTokens, completionTokens, logModel, tokenName, quota, logContent, relayInfo.TokenId, userQuota, int(useTimeSeconds), relayInfo.IsStream, other) //if quota != 0 { // diff --git a/web/src/components/LogsTable.js b/web/src/components/LogsTable.js index 9331fa7..0de3632 100644 --- a/web/src/components/LogsTable.js +++ b/web/src/components/LogsTable.js @@ -19,9 +19,15 @@ import { Spin, Table, Tag, + Tooltip, } from '@douyinfe/semi-ui'; import { ITEMS_PER_PAGE } from '../constants'; -import { renderNumber, renderQuota, stringToColor } from '../helpers/render'; +import { + renderModelPrice, + renderNumber, + renderQuota, + stringToColor, +} from '../helpers/render'; import Paragraph from '@douyinfe/semi-ui/lib/es/typography/paragraph'; const { Header } = Layout; @@ -292,16 +298,44 @@ const LogsTable = () => { title: '详情', dataIndex: 'content', render: (text, record, index) => { + if (record.other === '') { + return ( + + {text} + + ); + } + let other = JSON.parse(record.other); + let content = renderModelPrice( + other.model_ratio, + other.model_price, + other.completion_ratio, + other.group_ratio, + ); return ( - - {text} - + + + {text} + + ); }, }, diff --git a/web/src/helpers/render.js b/web/src/helpers/render.js index 8cea432..9d36682 100644 --- a/web/src/helpers/render.js +++ b/web/src/helpers/render.js @@ -135,6 +135,32 @@ export function renderQuota(quota, digits = 2) { return renderNumber(quota); } +export function renderModelPrice( + modelRatio, + modelPrice = -1, + completionRatio, + groupRatio, +) { + // 1 ratio = $0.002 / 1K tokens + if (modelPrice !== -1) { + return '模型价格:$' + modelPrice * groupRatio; + } else { + if (completionRatio === undefined) { + completionRatio = 0; + } + let inputRatioPrice = modelRatio * 0.002 * groupRatio; + let completionRatioPrice = + modelRatio * completionRatio * 0.002 * groupRatio; + return ( + '输入:$' + + inputRatioPrice.toFixed(3) + + '/1K tokens,补全:$' + + completionRatioPrice.toFixed(3) + + '/1K tokens' + ); + } +} + export function renderQuotaWithPrompt(quota, digits) { let displayInCurrency = localStorage.getItem('display_in_currency'); displayInCurrency = displayInCurrency === 'true';