Parcourir la source

feat: able to display token billing stat via billing api (close #186)

JustSong il y a 2 ans
Parent
commit
7edc2b5376

+ 2 - 1
common/constants.go

@@ -18,7 +18,8 @@ var Logo = ""
 var TopUpLink = ""
 var TopUpLink = ""
 var ChatLink = ""
 var ChatLink = ""
 var QuotaPerUnit = 500 * 1000.0 // $0.002 / 1K tokens
 var QuotaPerUnit = 500 * 1000.0 // $0.002 / 1K tokens
-var DisplayInCurrencyEnabled = false
+var DisplayInCurrencyEnabled = true
+var DisplayTokenStatEnabled = true
 
 
 var UsingSQLite = false
 var UsingSQLite = false
 
 

+ 22 - 4
controller/billing.go

@@ -7,8 +7,17 @@ import (
 )
 )
 
 
 func GetSubscription(c *gin.Context) {
 func GetSubscription(c *gin.Context) {
-	userId := c.GetInt("id")
-	quota, err := model.GetUserQuota(userId)
+	var quota int
+	var err error
+	var token *model.Token
+	if common.DisplayTokenStatEnabled {
+		tokenId := c.GetInt("token_id")
+		token, err = model.GetTokenById(tokenId)
+		quota = token.RemainQuota
+	} else {
+		userId := c.GetInt("id")
+		quota, err = model.GetUserQuota(userId)
+	}
 	if err != nil {
 	if err != nil {
 		openAIError := OpenAIError{
 		openAIError := OpenAIError{
 			Message: err.Error(),
 			Message: err.Error(),
@@ -35,8 +44,17 @@ func GetSubscription(c *gin.Context) {
 }
 }
 
 
 func GetUsage(c *gin.Context) {
 func GetUsage(c *gin.Context) {
-	userId := c.GetInt("id")
-	quota, err := model.GetUserUsedQuota(userId)
+	var quota int
+	var err error
+	var token *model.Token
+	if common.DisplayTokenStatEnabled {
+		tokenId := c.GetInt("token_id")
+		token, err = model.GetTokenById(tokenId)
+		quota = token.UsedQuota
+	} else {
+		userId := c.GetInt("id")
+		quota, err = model.GetUserUsedQuota(userId)
+	}
 	if err != nil {
 	if err != nil {
 		openAIError := OpenAIError{
 		openAIError := OpenAIError{
 			Message: err.Error(),
 			Message: err.Error(),

+ 1 - 1
controller/option.go

@@ -13,7 +13,7 @@ func GetOptions(c *gin.Context) {
 	var options []*model.Option
 	var options []*model.Option
 	common.OptionMapRWMutex.Lock()
 	common.OptionMapRWMutex.Lock()
 	for k, v := range common.OptionMap {
 	for k, v := range common.OptionMap {
-		if strings.Contains(k, "Token") || strings.Contains(k, "Secret") {
+		if strings.HasSuffix(k, "Token") || strings.HasSuffix(k, "Secret") {
 			continue
 			continue
 		}
 		}
 		options = append(options, &model.Option{
 		options = append(options, &model.Option{

+ 3 - 0
model/option.go

@@ -36,6 +36,7 @@ func InitOptionMap() {
 	common.OptionMap["AutomaticDisableChannelEnabled"] = strconv.FormatBool(common.AutomaticDisableChannelEnabled)
 	common.OptionMap["AutomaticDisableChannelEnabled"] = strconv.FormatBool(common.AutomaticDisableChannelEnabled)
 	common.OptionMap["LogConsumeEnabled"] = strconv.FormatBool(common.LogConsumeEnabled)
 	common.OptionMap["LogConsumeEnabled"] = strconv.FormatBool(common.LogConsumeEnabled)
 	common.OptionMap["DisplayInCurrencyEnabled"] = strconv.FormatBool(common.DisplayInCurrencyEnabled)
 	common.OptionMap["DisplayInCurrencyEnabled"] = strconv.FormatBool(common.DisplayInCurrencyEnabled)
+	common.OptionMap["DisplayTokenStatEnabled"] = strconv.FormatBool(common.DisplayTokenStatEnabled)
 	common.OptionMap["ChannelDisableThreshold"] = strconv.FormatFloat(common.ChannelDisableThreshold, 'f', -1, 64)
 	common.OptionMap["ChannelDisableThreshold"] = strconv.FormatFloat(common.ChannelDisableThreshold, 'f', -1, 64)
 	common.OptionMap["SMTPServer"] = ""
 	common.OptionMap["SMTPServer"] = ""
 	common.OptionMap["SMTPFrom"] = ""
 	common.OptionMap["SMTPFrom"] = ""
@@ -144,6 +145,8 @@ func updateOptionMap(key string, value string) (err error) {
 			common.LogConsumeEnabled = boolValue
 			common.LogConsumeEnabled = boolValue
 		case "DisplayInCurrencyEnabled":
 		case "DisplayInCurrencyEnabled":
 			common.DisplayInCurrencyEnabled = boolValue
 			common.DisplayInCurrencyEnabled = boolValue
+		case "DisplayTokenStatEnabled":
+			common.DisplayTokenStatEnabled = boolValue
 		}
 		}
 	}
 	}
 	switch key {
 	switch key {

+ 13 - 2
model/token.go

@@ -18,6 +18,7 @@ type Token struct {
 	ExpiredTime    int64  `json:"expired_time" gorm:"bigint;default:-1"` // -1 means never expired
 	ExpiredTime    int64  `json:"expired_time" gorm:"bigint;default:-1"` // -1 means never expired
 	RemainQuota    int    `json:"remain_quota" gorm:"default:0"`
 	RemainQuota    int    `json:"remain_quota" gorm:"default:0"`
 	UnlimitedQuota bool   `json:"unlimited_quota" gorm:"default:false"`
 	UnlimitedQuota bool   `json:"unlimited_quota" gorm:"default:false"`
+	UsedQuota      int    `json:"used_quota" gorm:"default:0"` // used quota
 }
 }
 
 
 func GetAllUserTokens(userId int, startIdx int, num int) ([]*Token, error) {
 func GetAllUserTokens(userId int, startIdx int, num int) ([]*Token, error) {
@@ -130,7 +131,12 @@ func IncreaseTokenQuota(id int, quota int) (err error) {
 	if quota < 0 {
 	if quota < 0 {
 		return errors.New("quota 不能为负数!")
 		return errors.New("quota 不能为负数!")
 	}
 	}
-	err = DB.Model(&Token{}).Where("id = ?", id).Update("remain_quota", gorm.Expr("remain_quota + ?", quota)).Error
+	err = DB.Model(&Token{}).Where("id = ?", id).Updates(
+		map[string]interface{}{
+			"remain_quota": gorm.Expr("remain_quota + ?", quota),
+			"used_quota":   gorm.Expr("used_quota - ?", quota),
+		},
+	).Error
 	return err
 	return err
 }
 }
 
 
@@ -138,7 +144,12 @@ func DecreaseTokenQuota(id int, quota int) (err error) {
 	if quota < 0 {
 	if quota < 0 {
 		return errors.New("quota 不能为负数!")
 		return errors.New("quota 不能为负数!")
 	}
 	}
-	err = DB.Model(&Token{}).Where("id = ?", id).Update("remain_quota", gorm.Expr("remain_quota - ?", quota)).Error
+	err = DB.Model(&Token{}).Where("id = ?", id).Updates(
+		map[string]interface{}{
+			"remain_quota": gorm.Expr("remain_quota - ?", quota),
+			"used_quota":   gorm.Expr("used_quota + ?", quota),
+		},
+	).Error
 	return err
 	return err
 }
 }
 
 

+ 8 - 1
web/src/components/OperationSetting.js

@@ -17,7 +17,8 @@ const OperationSetting = () => {
     AutomaticDisableChannelEnabled: '',
     AutomaticDisableChannelEnabled: '',
     ChannelDisableThreshold: 0,
     ChannelDisableThreshold: 0,
     LogConsumeEnabled: '',
     LogConsumeEnabled: '',
-    DisplayInCurrencyEnabled: ''
+    DisplayInCurrencyEnabled: '',
+    DisplayTokenStatEnabled: ''
   });
   });
   const [originInputs, setOriginInputs] = useState({});
   const [originInputs, setOriginInputs] = useState({});
   let [loading, setLoading] = useState(false);
   let [loading, setLoading] = useState(false);
@@ -177,6 +178,12 @@ const OperationSetting = () => {
               name='DisplayInCurrencyEnabled'
               name='DisplayInCurrencyEnabled'
               onChange={handleInputChange}
               onChange={handleInputChange}
             />
             />
+            <Form.Checkbox
+              checked={inputs.DisplayTokenStatEnabled === 'true'}
+              label='Billing 相关 API 显示令牌额度而非用户额度'
+              name='DisplayTokenStatEnabled'
+              onChange={handleInputChange}
+            />
           </Form.Group>
           </Form.Group>
           <Form.Button onClick={() => {
           <Form.Button onClick={() => {
             submitConfig('general').then();
             submitConfig('general').then();