From 6fb1fbfe96962e72341e6f59657de6369667f74e Mon Sep 17 00:00:00 2001
From: CaIon <1808837298@qq.com>
Date: Sun, 12 May 2024 15:35:57 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=97=A5=E5=BF=97=E8=AF=A6=E6=83=85?=
=?UTF-8?q?=E5=B1=95=E7=A4=BA=E6=A8=A1=E5=9E=8B=E4=BB=B7=E6=A0=BC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
common/model-ratio.go | 1 +
common/utils.go | 9 ++++++
model/log.go | 5 ++-
relay/relay-audio.go | 5 ++-
relay/relay-image.go | 5 ++-
relay/relay-mj.go | 10 ++++--
relay/relay-text.go | 7 ++++-
web/src/components/LogsTable.js | 54 +++++++++++++++++++++++++++------
web/src/helpers/render.js | 26 ++++++++++++++++
9 files changed, 106 insertions(+), 16 deletions(-)
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';