mirror of
https://github.com/linux-do/new-api.git
synced 2025-09-22 10:16:36 +08:00
feat: 日志详情展示模型价格
This commit is contained in:
parent
4641d44615
commit
6fb1fbfe96
@ -28,6 +28,7 @@ var DefaultModelRatio = map[string]float64{
|
|||||||
"gpt-4-vision-preview": 5, // $0.01 / 1K tokens
|
"gpt-4-vision-preview": 5, // $0.01 / 1K tokens
|
||||||
"gpt-4-1106-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": 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": 0.25, // $0.0015 / 1K tokens
|
||||||
//"gpt-3.5-turbo-0301": 0.75, //deprecated
|
//"gpt-3.5-turbo-0301": 0.75, //deprecated
|
||||||
"gpt-3.5-turbo-0613": 0.75,
|
"gpt-3.5-turbo-0613": 0.75,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"html/template"
|
"html/template"
|
||||||
@ -241,3 +242,11 @@ func RandomSleep() {
|
|||||||
// Sleep for 0-3000 ms
|
// Sleep for 0-3000 ms
|
||||||
time.Sleep(time.Duration(rand.Intn(3000)) * time.Millisecond)
|
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)
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@ type Log struct {
|
|||||||
IsStream bool `json:"is_stream" gorm:"default:false"`
|
IsStream bool `json:"is_stream" gorm:"default:false"`
|
||||||
ChannelId int `json:"channel" gorm:"index"`
|
ChannelId int `json:"channel" gorm:"index"`
|
||||||
TokenId int `json:"token_id" gorm:"default:0;index"`
|
TokenId int `json:"token_id" gorm:"default:0;index"`
|
||||||
|
Other string `json:"other"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
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))
|
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 {
|
if !common.LogConsumeEnabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
username, _ := CacheGetUsername(userId)
|
username, _ := CacheGetUsername(userId)
|
||||||
|
otherStr := common.MapToJsonStr(other)
|
||||||
log := &Log{
|
log := &Log{
|
||||||
UserId: userId,
|
UserId: userId,
|
||||||
Username: username,
|
Username: username,
|
||||||
@ -78,6 +80,7 @@ func RecordConsumeLog(ctx context.Context, userId int, channelId int, promptToke
|
|||||||
TokenId: tokenId,
|
TokenId: tokenId,
|
||||||
UseTime: useTimeSeconds,
|
UseTime: useTimeSeconds,
|
||||||
IsStream: isStream,
|
IsStream: isStream,
|
||||||
|
Other: otherStr,
|
||||||
}
|
}
|
||||||
err := DB.Create(log).Error
|
err := DB.Create(log).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -196,7 +196,10 @@ func AudioHelper(c *gin.Context, relayMode int) *dto.OpenAIErrorWithStatusCode {
|
|||||||
if quota != 0 {
|
if quota != 0 {
|
||||||
tokenName := c.GetString("token_name")
|
tokenName := c.GetString("token_name")
|
||||||
logContent := fmt.Sprintf("模型倍率 %.2f,分组倍率 %.2f", modelRatio, groupRatio)
|
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)
|
model.UpdateUserUsedQuotaAndRequestCount(userId, quota)
|
||||||
channelId := c.GetInt("channel_id")
|
channelId := c.GetInt("channel_id")
|
||||||
model.UpdateChannelUsedQuota(channelId, quota)
|
model.UpdateChannelUsedQuota(channelId, quota)
|
||||||
|
@ -191,7 +191,10 @@ func RelayImageHelper(c *gin.Context, relayMode int) *dto.OpenAIErrorWithStatusC
|
|||||||
quality = "hd"
|
quality = "hd"
|
||||||
}
|
}
|
||||||
logContent := fmt.Sprintf("模型倍率 %.2f,分组倍率 %.2f, 大小 %s, 品质 %s", modelRatio, groupRatio, imageRequest.Size, quality)
|
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)
|
model.UpdateUserUsedQuotaAndRequestCount(userId, quota)
|
||||||
channelId := c.GetInt("channel_id")
|
channelId := c.GetInt("channel_id")
|
||||||
model.UpdateChannelUsedQuota(channelId, quota)
|
model.UpdateChannelUsedQuota(channelId, quota)
|
||||||
|
@ -202,7 +202,10 @@ func RelaySwapFace(c *gin.Context) *dto.MidjourneyResponse {
|
|||||||
if quota != 0 {
|
if quota != 0 {
|
||||||
tokenName := c.GetString("token_name")
|
tokenName := c.GetString("token_name")
|
||||||
logContent := fmt.Sprintf("模型固定价格 %.2f,分组倍率 %.2f,操作 %s", modelPrice, groupRatio, constant.MjActionSwapFace)
|
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)
|
model.UpdateUserUsedQuotaAndRequestCount(userId, quota)
|
||||||
channelId := c.GetInt("channel_id")
|
channelId := c.GetInt("channel_id")
|
||||||
model.UpdateChannelUsedQuota(channelId, quota)
|
model.UpdateChannelUsedQuota(channelId, quota)
|
||||||
@ -498,7 +501,10 @@ func RelayMidjourneySubmit(c *gin.Context, relayMode int) *dto.MidjourneyRespons
|
|||||||
if quota != 0 {
|
if quota != 0 {
|
||||||
tokenName := c.GetString("token_name")
|
tokenName := c.GetString("token_name")
|
||||||
logContent := fmt.Sprintf("模型固定价格 %.2f,分组倍率 %.2f,操作 %s", modelPrice, groupRatio, midjRequest.Action)
|
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)
|
model.UpdateUserUsedQuotaAndRequestCount(userId, quota)
|
||||||
channelId := c.GetInt("channel_id")
|
channelId := c.GetInt("channel_id")
|
||||||
model.UpdateChannelUsedQuota(channelId, quota)
|
model.UpdateChannelUsedQuota(channelId, quota)
|
||||||
|
@ -315,7 +315,12 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, textRe
|
|||||||
logModel = "gpt-4-gizmo-*"
|
logModel = "gpt-4-gizmo-*"
|
||||||
logContent += fmt.Sprintf(",模型 %s", textRequest.Model)
|
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 {
|
//if quota != 0 {
|
||||||
//
|
//
|
||||||
|
@ -19,9 +19,15 @@ import {
|
|||||||
Spin,
|
Spin,
|
||||||
Table,
|
Table,
|
||||||
Tag,
|
Tag,
|
||||||
|
Tooltip,
|
||||||
} from '@douyinfe/semi-ui';
|
} from '@douyinfe/semi-ui';
|
||||||
import { ITEMS_PER_PAGE } from '../constants';
|
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';
|
import Paragraph from '@douyinfe/semi-ui/lib/es/typography/paragraph';
|
||||||
|
|
||||||
const { Header } = Layout;
|
const { Header } = Layout;
|
||||||
@ -292,16 +298,44 @@ const LogsTable = () => {
|
|||||||
title: '详情',
|
title: '详情',
|
||||||
dataIndex: 'content',
|
dataIndex: 'content',
|
||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
|
if (record.other === '') {
|
||||||
|
return (
|
||||||
|
<Paragraph
|
||||||
|
ellipsis={{
|
||||||
|
rows: 2,
|
||||||
|
showTooltip: {
|
||||||
|
type: 'popover',
|
||||||
|
opts: { style: { width: 240 } },
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
style={{ maxWidth: 240 }}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Paragraph>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let other = JSON.parse(record.other);
|
||||||
|
let content = renderModelPrice(
|
||||||
|
other.model_ratio,
|
||||||
|
other.model_price,
|
||||||
|
other.completion_ratio,
|
||||||
|
other.group_ratio,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<Paragraph
|
<Tooltip content={content}>
|
||||||
ellipsis={{
|
<Paragraph
|
||||||
rows: 2,
|
ellipsis={{
|
||||||
showTooltip: { type: 'popover', opts: { style: { width: 240 } } },
|
rows: 2,
|
||||||
}}
|
showTooltip: {
|
||||||
style={{ maxWidth: 240 }}
|
type: 'popover',
|
||||||
>
|
opts: { style: { width: 240 } },
|
||||||
{text}
|
},
|
||||||
</Paragraph>
|
}}
|
||||||
|
style={{ maxWidth: 240 }}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Paragraph>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -135,6 +135,32 @@ export function renderQuota(quota, digits = 2) {
|
|||||||
return renderNumber(quota);
|
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) {
|
export function renderQuotaWithPrompt(quota, digits) {
|
||||||
let displayInCurrency = localStorage.getItem('display_in_currency');
|
let displayInCurrency = localStorage.getItem('display_in_currency');
|
||||||
displayInCurrency = displayInCurrency === 'true';
|
displayInCurrency = displayInCurrency === 'true';
|
||||||
|
Loading…
Reference in New Issue
Block a user