mirror of
https://github.com/songquanpeng/one-api.git
synced 2025-11-06 16:53:42 +08:00
Compare commits
5 Commits
v0.3.0-alp
...
v0.3.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8afdc56b11 | ||
|
|
a9ea1d9d10 | ||
|
|
ea8e7c517b | ||
|
|
d1e9b86f05 | ||
|
|
6d1e5cb5dc |
@@ -40,6 +40,9 @@ _✨ All in one 的 OpenAI 接口,整合各种 API 访问方式,开箱即用
|
|||||||
<a href="https://openai.justsong.cn/">在线演示</a>
|
<a href="https://openai.justsong.cn/">在线演示</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
> **Warning**:从 `v0.2` 版本升级到 `v0.3` 版本需要手动迁移数据库,请手动执行[数据库迁移脚本](./bin/migration_v0.2-v0.3.sql)。
|
||||||
|
|
||||||
|
|
||||||
## 功能
|
## 功能
|
||||||
1. 支持多种 API 访问渠道,欢迎 PR 或提 issue 添加更多渠道:
|
1. 支持多种 API 访问渠道,欢迎 PR 或提 issue 添加更多渠道:
|
||||||
+ [x] OpenAI 官方通道
|
+ [x] OpenAI 官方通道
|
||||||
|
|||||||
6
bin/migration_v0.2-v0.3.sql
Normal file
6
bin/migration_v0.2-v0.3.sql
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
UPDATE users
|
||||||
|
SET quota = quota + (
|
||||||
|
SELECT SUM(remain_quota)
|
||||||
|
FROM tokens
|
||||||
|
WHERE tokens.user_id = users.id
|
||||||
|
)
|
||||||
@@ -128,6 +128,13 @@ func relayHelper(c *gin.Context) error {
|
|||||||
model_ = strings.TrimSuffix(model_, "-0314")
|
model_ = strings.TrimSuffix(model_, "-0314")
|
||||||
fullRequestURL = fmt.Sprintf("%s/openai/deployments/%s/%s", baseURL, model_, task)
|
fullRequestURL = fmt.Sprintf("%s/openai/deployments/%s/%s", baseURL, model_, task)
|
||||||
}
|
}
|
||||||
|
preConsumedQuota := 500 // TODO: make this configurable, take ratio into account
|
||||||
|
if consumeQuota {
|
||||||
|
err := model.PreConsumeTokenQuota(tokenId, preConsumedQuota)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
req, err := http.NewRequest(c.Request.Method, fullRequestURL, c.Request.Body)
|
req, err := http.NewRequest(c.Request.Method, fullRequestURL, c.Request.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -179,7 +186,8 @@ func relayHelper(c *gin.Context) error {
|
|||||||
}
|
}
|
||||||
ratio := common.GetModelRatio(textRequest.Model)
|
ratio := common.GetModelRatio(textRequest.Model)
|
||||||
quota = int(float64(quota) * ratio)
|
quota = int(float64(quota) * ratio)
|
||||||
err := model.DecreaseTokenQuota(tokenId, quota)
|
quotaDelta := quota - preConsumedQuota
|
||||||
|
err := model.PostConsumeTokenQuota(tokenId, quotaDelta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.SysError("Error consuming token remain quota: " + err.Error())
|
common.SysError("Error consuming token remain quota: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,7 +160,6 @@ func DeleteToken(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdateToken(c *gin.Context) {
|
func UpdateToken(c *gin.Context) {
|
||||||
isAdmin := c.GetInt("role") >= common.RoleAdminUser
|
|
||||||
userId := c.GetInt("id")
|
userId := c.GetInt("id")
|
||||||
statusOnly := c.Query("status_only")
|
statusOnly := c.Query("status_only")
|
||||||
token := model.Token{}
|
token := model.Token{}
|
||||||
@@ -191,7 +190,7 @@ func UpdateToken(c *gin.Context) {
|
|||||||
if cleanToken.Status == common.TokenStatusExhausted && cleanToken.RemainQuota <= 0 && !cleanToken.UnlimitedQuota {
|
if cleanToken.Status == common.TokenStatusExhausted && cleanToken.RemainQuota <= 0 && !cleanToken.UnlimitedQuota {
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"success": false,
|
"success": false,
|
||||||
"message": "令牌可用次数已用尽,无法启用,请先修改令牌剩余次数,或者设置为无限次数",
|
"message": "令牌可用额度已用尽,无法启用,请先修改令牌剩余额度,或者设置为无限额度",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -202,10 +201,8 @@ func UpdateToken(c *gin.Context) {
|
|||||||
// If you add more fields, please also update token.Update()
|
// If you add more fields, please also update token.Update()
|
||||||
cleanToken.Name = token.Name
|
cleanToken.Name = token.Name
|
||||||
cleanToken.ExpiredTime = token.ExpiredTime
|
cleanToken.ExpiredTime = token.ExpiredTime
|
||||||
if isAdmin {
|
cleanToken.RemainQuota = token.RemainQuota
|
||||||
cleanToken.RemainQuota = token.RemainQuota
|
cleanToken.UnlimitedQuota = token.UnlimitedQuota
|
||||||
cleanToken.UnlimitedQuota = token.UnlimitedQuota
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
err = cleanToken.Update()
|
err = cleanToken.Update()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ func TokenAuth() func(c *gin.Context) {
|
|||||||
c.Set("id", token.UserId)
|
c.Set("id", token.UserId)
|
||||||
c.Set("token_id", token.Id)
|
c.Set("token_id", token.Id)
|
||||||
requestURL := c.Request.URL.String()
|
requestURL := c.Request.URL.String()
|
||||||
consumeQuota := !token.UnlimitedQuota
|
consumeQuota := true
|
||||||
if strings.HasPrefix(requestURL, "/v1/models") {
|
if strings.HasPrefix(requestURL, "/v1/models") {
|
||||||
consumeQuota = false
|
consumeQuota = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,7 +130,23 @@ func DeleteTokenById(id int, userId int) (err error) {
|
|||||||
return token.Delete()
|
return token.Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecreaseTokenQuota(tokenId int, quota int) (err error) {
|
func IncreaseTokenQuota(id int, quota int) (err error) {
|
||||||
|
if quota < 0 {
|
||||||
|
return errors.New("quota 不能为负数!")
|
||||||
|
}
|
||||||
|
err = DB.Model(&Token{}).Where("id = ?", id).Update("remain_quota", gorm.Expr("remain_quota + ?", quota)).Error
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecreaseTokenQuota(id int, quota int) (err error) {
|
||||||
|
if quota < 0 {
|
||||||
|
return errors.New("quota 不能为负数!")
|
||||||
|
}
|
||||||
|
err = DB.Model(&Token{}).Where("id = ?", id).Update("remain_quota", gorm.Expr("remain_quota - ?", quota)).Error
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func PreConsumeTokenQuota(tokenId int, quota int) (err error) {
|
||||||
if quota < 0 {
|
if quota < 0 {
|
||||||
return errors.New("quota 不能为负数!")
|
return errors.New("quota 不能为负数!")
|
||||||
}
|
}
|
||||||
@@ -138,7 +154,7 @@ func DecreaseTokenQuota(tokenId int, quota int) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if token.RemainQuota < quota {
|
if !token.UnlimitedQuota && token.RemainQuota < quota {
|
||||||
return errors.New("令牌额度不足")
|
return errors.New("令牌额度不足")
|
||||||
}
|
}
|
||||||
userQuota, err := GetUserQuota(token.UserId)
|
userQuota, err := GetUserQuota(token.UserId)
|
||||||
@@ -163,17 +179,42 @@ func DecreaseTokenQuota(tokenId int, quota int) (err error) {
|
|||||||
if email != "" {
|
if email != "" {
|
||||||
topUpLink := fmt.Sprintf("%s/topup", common.ServerAddress)
|
topUpLink := fmt.Sprintf("%s/topup", common.ServerAddress)
|
||||||
err = common.SendEmail(prompt, email,
|
err = common.SendEmail(prompt, email,
|
||||||
fmt.Sprintf("%s,剩余额度为 %d,为了不影响您的使用,请及时充值。<br/>充值链接:<a href='%s'>%s</a>", prompt, userQuota-quota, topUpLink, topUpLink))
|
fmt.Sprintf("%s,当前剩余额度为 %d,为了不影响您的使用,请及时充值。<br/>充值链接:<a href='%s'>%s</a>", prompt, userQuota, topUpLink, topUpLink))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.SysError("发送邮件失败:" + err.Error())
|
common.SysError("发送邮件失败:" + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
err = DB.Model(&Token{}).Where("id = ?", tokenId).Update("remain_quota", gorm.Expr("remain_quota - ?", quota)).Error
|
if !token.UnlimitedQuota {
|
||||||
if err != nil {
|
err = DecreaseTokenQuota(tokenId, quota)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err = DecreaseUserQuota(token.UserId, quota)
|
err = DecreaseUserQuota(token.UserId, quota)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PostConsumeTokenQuota(tokenId int, quota int) (err error) {
|
||||||
|
token, err := GetTokenById(tokenId)
|
||||||
|
if quota > 0 {
|
||||||
|
err = DecreaseUserQuota(token.UserId, quota)
|
||||||
|
} else {
|
||||||
|
err = IncreaseUserQuota(token.UserId, -quota)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !token.UnlimitedQuota {
|
||||||
|
if quota > 0 {
|
||||||
|
err = DecreaseTokenQuota(tokenId, quota)
|
||||||
|
} else {
|
||||||
|
err = IncreaseTokenQuota(tokenId, -quota)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ const headerButtons = [
|
|||||||
name: '充值',
|
name: '充值',
|
||||||
to: '/topup',
|
to: '/topup',
|
||||||
icon: 'cart',
|
icon: 'cart',
|
||||||
admin: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '用户',
|
name: '用户',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Button, Form, Header, Segment } from 'semantic-ui-react';
|
import { Button, Form, Header, Message, Segment } from 'semantic-ui-react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { API, showError, showSuccess, timestamp2string } from '../../helpers';
|
import { API, showError, showSuccess, timestamp2string } from '../../helpers';
|
||||||
|
|
||||||
@@ -106,6 +106,7 @@ const EditToken = () => {
|
|||||||
required={!isEdit}
|
required={!isEdit}
|
||||||
/>
|
/>
|
||||||
</Form.Field>
|
</Form.Field>
|
||||||
|
<Message>注意,令牌的额度仅用于限制令牌本身的最大额度使用量,实际的使用受到账户的剩余额度限制。</Message>
|
||||||
<Form.Field>
|
<Form.Field>
|
||||||
<Form.Input
|
<Form.Input
|
||||||
label='额度'
|
label='额度'
|
||||||
|
|||||||
Reference in New Issue
Block a user