feat: 日志新增rpm和tpm数据。(close #384)

This commit is contained in:
CalciumIon 2024-08-01 16:13:08 +08:00
parent 1501ccb919
commit c92ab3b569
3 changed files with 57 additions and 26 deletions

View File

@ -7,6 +7,7 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
"one-api/common" "one-api/common"
"strings" "strings"
"time"
) )
type Log struct { type Log struct {
@ -172,12 +173,18 @@ type Stat struct {
} }
func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, channel int) (stat Stat) { func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, channel int) (stat Stat) {
tx := DB.Table("logs").Select("sum(quota) quota, count(*) rpm, sum(prompt_tokens) + sum(completion_tokens) tpm") tx := DB.Table("logs").Select("sum(quota) quota")
// 为rpm和tpm创建单独的查询
rpmTpmQuery := DB.Table("logs").Select("count(*) rpm, sum(prompt_tokens) + sum(completion_tokens) tpm")
if username != "" { if username != "" {
tx = tx.Where("username = ?", username) tx = tx.Where("username = ?", username)
rpmTpmQuery = rpmTpmQuery.Where("username = ?", username)
} }
if tokenName != "" { if tokenName != "" {
tx = tx.Where("token_name = ?", tokenName) tx = tx.Where("token_name = ?", tokenName)
rpmTpmQuery = rpmTpmQuery.Where("token_name = ?", tokenName)
} }
if startTimestamp != 0 { if startTimestamp != 0 {
tx = tx.Where("created_at >= ?", startTimestamp) tx = tx.Where("created_at >= ?", startTimestamp)
@ -187,11 +194,23 @@ func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelNa
} }
if modelName != "" { if modelName != "" {
tx = tx.Where("model_name = ?", modelName) tx = tx.Where("model_name = ?", modelName)
rpmTpmQuery = rpmTpmQuery.Where("model_name = ?", modelName)
} }
if channel != 0 { if channel != 0 {
tx = tx.Where("channel_id = ?", channel) tx = tx.Where("channel_id = ?", channel)
rpmTpmQuery = rpmTpmQuery.Where("channel_id = ?", channel)
} }
tx.Where("type = ?", LogTypeConsume).Scan(&stat)
tx = tx.Where("type = ?", LogTypeConsume)
rpmTpmQuery = rpmTpmQuery.Where("type = ?", LogTypeConsume)
// 只统计最近60秒的rpm和tpm
rpmTpmQuery = rpmTpmQuery.Where("created_at >= ?", time.Now().Add(-60*time.Second).Unix())
// 执行查询
tx.Scan(&stat)
rpmTpmQuery.Scan(&stat)
return stat return stat
} }

View File

@ -286,7 +286,14 @@ func returnPreConsumedQuota(c *gin.Context, tokenId int, userQuota int, preConsu
func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, modelName string, func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, modelName string,
usage *dto.Usage, ratio float64, preConsumedQuota int, userQuota int, modelRatio float64, groupRatio float64, usage *dto.Usage, ratio float64, preConsumedQuota int, userQuota int, modelRatio float64, groupRatio float64,
modelPrice float64, usePrice bool, extraContent string) { modelPrice float64, usePrice bool, extraContent string) {
if usage == nil {
usage = &dto.Usage{
PromptTokens: relayInfo.PromptTokens,
CompletionTokens: 0,
TotalTokens: relayInfo.PromptTokens,
}
extraContent += " ,(可能是请求出错)"
}
useTimeSeconds := time.Now().Unix() - relayInfo.StartTime.Unix() useTimeSeconds := time.Now().Unix() - relayInfo.StartTime.Unix()
promptTokens := usage.PromptTokens promptTokens := usage.PromptTokens
completionTokens := usage.CompletionTokens completionTokens := usage.CompletionTokens

View File

@ -475,6 +475,9 @@ const LogsTable = () => {
}; };
const handleEyeClick = async () => { const handleEyeClick = async () => {
if (loadingStat) {
return;
}
setLoadingStat(true); setLoadingStat(true);
if (isAdminUser) { if (isAdminUser) {
await getLogStat(); await getLogStat();
@ -596,6 +599,7 @@ const LogsTable = () => {
.catch((reason) => { .catch((reason) => {
showError(reason); showError(reason);
}); });
handleEyeClick();
}, []); }, []);
const searchLogs = async () => { const searchLogs = async () => {
@ -622,19 +626,17 @@ const LogsTable = () => {
<Layout> <Layout>
<Header> <Header>
<Spin spinning={loadingStat}> <Spin spinning={loadingStat}>
<h3> <Space>
使用明细总消耗额度 <Tag color='green' size='large' style={{ padding: 15 }}>
<span 总消耗额度: {renderQuota(stat.quota)}
onClick={handleEyeClick} </Tag>
style={{ <Tag color='blue' size='large' style={{ padding: 15 }}>
cursor: 'pointer', RPM: {stat.rpm}
color: 'gray', </Tag>
}} <Tag color='purple' size='large' style={{ padding: 15 }}>
> TPM: {stat.tpm}
{showStat ? renderQuota(stat.quota) : '点击查看'} </Tag>
</span> </Space>
</h3>
</Spin> </Spin>
</Header> </Header>
<Form layout='horizontal' style={{ marginTop: 10 }}> <Form layout='horizontal' style={{ marginTop: 10 }}>
@ -700,7 +702,6 @@ const LogsTable = () => {
/> />
</> </>
)} )}
<Form.Section>
<Button <Button
label='查询' label='查询'
type='primary' type='primary'
@ -708,9 +709,12 @@ const LogsTable = () => {
className='btn-margin-right' className='btn-margin-right'
onClick={refresh} onClick={refresh}
loading={loading} loading={loading}
style={{ marginTop: 24 }}
> >
查询 查询
</Button> </Button>
<Form.Section>
</Form.Section> </Form.Section>
</> </>
</Form> </Form>
@ -736,6 +740,7 @@ const LogsTable = () => {
onChange={(value) => { onChange={(value) => {
setLogType(parseInt(value)); setLogType(parseInt(value));
loadLogs(0, pageSize, parseInt(value)); loadLogs(0, pageSize, parseInt(value));
handleEyeClick();
}} }}
> >
<Select.Option value='0'>全部</Select.Option> <Select.Option value='0'>全部</Select.Option>