Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
24bdbe11
authored
Jun 23, 2023
by
JustSong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: able to display token billing stat via billing api (close #186)
parent
aaafbe0a
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
49 additions
and
9 deletions
+49
-9
common/constants.go
+2
-1
controller/billing.go
+22
-4
controller/option.go
+1
-1
model/option.go
+3
-0
model/token.go
+13
-2
web/src/components/OperationSetting.js
+8
-1
No files found.
common/constants.go
View file @
24bdbe11
...
@@ -18,7 +18,8 @@ var Logo = ""
...
@@ -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
...
...
controller/billing.go
View file @
24bdbe11
...
@@ -7,8 +7,17 @@ import (
...
@@ -7,8 +7,17 @@ import (
)
)
func
GetSubscription
(
c
*
gin
.
Context
)
{
func
GetSubscription
(
c
*
gin
.
Context
)
{
userId
:=
c
.
GetInt
(
"id"
)
var
quota
int
quota
,
err
:=
model
.
GetUserQuota
(
userId
)
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) {
...
@@ -35,8 +44,17 @@ func GetSubscription(c *gin.Context) {
}
}
func
GetUsage
(
c
*
gin
.
Context
)
{
func
GetUsage
(
c
*
gin
.
Context
)
{
userId
:=
c
.
GetInt
(
"id"
)
var
quota
int
quota
,
err
:=
model
.
GetUserUsedQuota
(
userId
)
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
(),
...
...
controller/option.go
View file @
24bdbe11
...
@@ -13,7 +13,7 @@ func GetOptions(c *gin.Context) {
...
@@ -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
{
...
...
model/option.go
View file @
24bdbe11
...
@@ -36,6 +36,7 @@ func InitOptionMap() {
...
@@ -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) {
...
@@ -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
{
...
...
model/token.go
View file @
24bdbe11
...
@@ -18,6 +18,7 @@ type Token struct {
...
@@ -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) {
...
@@ -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) {
...
@@ -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
}
}
...
...
web/src/components/OperationSetting.js
View file @
24bdbe11
...
@@ -17,7 +17,8 @@ const OperationSetting = () => {
...
@@ -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 = () => {
...
@@ -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
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment