From a214371a0af0dc67674e08710982db2016a0b0bb Mon Sep 17 00:00:00 2001 From: MartialBE Date: Sat, 30 Dec 2023 00:37:14 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20feature:=20Add=20request=20durat?= =?UTF-8?q?ion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/relay-utils.go | 34 ++++++++---------------- middleware/request-id.go | 5 +++- model/log.go | 4 ++- web/src/views/Log/component/TableHead.js | 1 + web/src/views/Log/component/TableRow.js | 22 +++++++++++++++ 5 files changed, 41 insertions(+), 25 deletions(-) diff --git a/controller/relay-utils.go b/controller/relay-utils.go index 0a94fffe..21776ce1 100644 --- a/controller/relay-utils.go +++ b/controller/relay-utils.go @@ -14,6 +14,7 @@ import ( "one-api/types" "reflect" "strconv" + "time" "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" @@ -129,28 +130,6 @@ func shouldEnableChannel(err error, openAIErr *types.OpenAIError) bool { return true } -func postConsumeQuota(ctx context.Context, tokenId int, quotaDelta int, totalQuota int, userId int, channelId int, modelRatio float64, groupRatio float64, modelName string, tokenName string) { - // quotaDelta is remaining quota to be consumed - err := model.PostConsumeTokenQuota(tokenId, quotaDelta) - if err != nil { - common.SysError("error consuming token remain quota: " + err.Error()) - } - err = model.CacheUpdateUserQuota(userId) - if err != nil { - common.SysError("error update user quota cache: " + err.Error()) - } - // totalQuota is total quota consumed - if totalQuota != 0 { - logContent := fmt.Sprintf("模型倍率 %.2f,分组倍率 %.2f", modelRatio, groupRatio) - model.RecordConsumeLog(ctx, userId, channelId, totalQuota, 0, modelName, tokenName, totalQuota, logContent) - model.UpdateUserUsedQuotaAndRequestCount(userId, totalQuota) - model.UpdateChannelUsedQuota(channelId, totalQuota) - } - if totalQuota <= 0 { - common.LogError(ctx, fmt.Sprintf("totalQuota consumed is %d, something is wrong", totalQuota)) - } -} - func parseModelMapping(modelMapping string) (map[string]string, error) { if modelMapping == "" || modelMapping == "{}" { return nil, nil @@ -270,8 +249,17 @@ func (q *QuotaInfo) completedQuotaConsumption(usage *types.Usage, tokenName stri return errors.New("error consuming token remain quota: " + err.Error()) } if quota != 0 { + requestTime := 0 + requestStartTimeValue := ctx.Value("requestStartTime") + if requestStartTimeValue != nil { + requestStartTime, ok := requestStartTimeValue.(time.Time) + if ok { + requestTime = int(time.Since(requestStartTime).Milliseconds()) + } + } + logContent := fmt.Sprintf("模型倍率 %.2f,分组倍率 %.2f", q.modelRatio, q.groupRatio) - model.RecordConsumeLog(ctx, q.userId, q.channelId, promptTokens, completionTokens, q.modelName, tokenName, quota, logContent) + model.RecordConsumeLog(ctx, q.userId, q.channelId, promptTokens, completionTokens, q.modelName, tokenName, quota, logContent, requestTime) model.UpdateUserUsedQuotaAndRequestCount(q.userId, quota) model.UpdateChannelUsedQuota(q.channelId, quota) } diff --git a/middleware/request-id.go b/middleware/request-id.go index e623be7a..d626eeb1 100644 --- a/middleware/request-id.go +++ b/middleware/request-id.go @@ -2,8 +2,10 @@ package middleware import ( "context" - "github.com/gin-gonic/gin" "one-api/common" + "time" + + "github.com/gin-gonic/gin" ) func RequestId() func(c *gin.Context) { @@ -11,6 +13,7 @@ func RequestId() func(c *gin.Context) { id := common.GetTimeString() + common.GetRandomString(8) c.Set(common.RequestIdKey, id) ctx := context.WithValue(c.Request.Context(), common.RequestIdKey, id) + ctx = context.WithValue(ctx, "requestStartTime", time.Now()) c.Request = c.Request.WithContext(ctx) c.Header(common.RequestIdKey, id) c.Next() diff --git a/model/log.go b/model/log.go index f3858c3b..a178bf0b 100644 --- a/model/log.go +++ b/model/log.go @@ -21,6 +21,7 @@ type Log struct { PromptTokens int `json:"prompt_tokens" gorm:"default:0"` CompletionTokens int `json:"completion_tokens" gorm:"default:0"` ChannelId int `json:"channel" gorm:"index"` + RequestTime int `json:"request_time" gorm:"default:0"` } type LogStatistic struct { @@ -57,7 +58,7 @@ 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) { +func RecordConsumeLog(ctx context.Context, userId int, channelId int, promptTokens int, completionTokens int, modelName string, tokenName string, quota int, content string, requestTime int) { common.LogInfo(ctx, fmt.Sprintf("record consume log: userId=%d, channelId=%d, promptTokens=%d, completionTokens=%d, modelName=%s, tokenName=%s, quota=%d, content=%s", userId, channelId, promptTokens, completionTokens, modelName, tokenName, quota, content)) if !common.LogConsumeEnabled { return @@ -74,6 +75,7 @@ func RecordConsumeLog(ctx context.Context, userId int, channelId int, promptToke ModelName: modelName, Quota: quota, ChannelId: channelId, + RequestTime: requestTime, } err := DB.Create(log).Error if err != nil { diff --git a/web/src/views/Log/component/TableHead.js b/web/src/views/Log/component/TableHead.js index 671170ce..102986ef 100644 --- a/web/src/views/Log/component/TableHead.js +++ b/web/src/views/Log/component/TableHead.js @@ -11,6 +11,7 @@ const LogTableHead = ({ userIsAdmin }) => { 令牌 类型 模型 + 耗时 提示 补全 额度 diff --git a/web/src/views/Log/component/TableRow.js b/web/src/views/Log/component/TableRow.js index 36b6b666..b701b24c 100644 --- a/web/src/views/Log/component/TableRow.js +++ b/web/src/views/Log/component/TableRow.js @@ -25,7 +25,25 @@ function renderType(type) { } } +function requestTimeLabelOptions(request_time) { + let color = 'error'; + if (request_time === 0) { + color = 'default'; + } else if (request_time <= 1000) { + color = 'success'; + } else if (request_time <= 3000) { + color = 'primary'; + } else if (request_time <= 5000) { + color = 'secondary'; + } + + return color; +} + export default function LogTableRow({ item, userIsAdmin }) { + let request_time = item.request_time / 1000; + request_time = request_time.toFixed(2) + ' 秒'; + return ( <> @@ -54,6 +72,10 @@ export default function LogTableRow({ item, userIsAdmin }) { )} + + {' '} + + {item.prompt_tokens || ''} {item.completion_tokens || ''} {item.quota ? renderQuota(item.quota, 6) : ''}