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
Unverified
Commit
eb99ab1b
authored
Sep 05, 2026
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(billing): add built-in expression pricing for gpt-6-astra
parent
d5803532
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
178 additions
and
11 deletions
+178
-11
controller/option.go
+17
-6
relay/channel/openai/constant.go
+1
-0
setting/billing_setting/builtin_billing.go
+11
-0
setting/billing_setting/builtin_billing_test.go
+111
-0
setting/billing_setting/tiered_billing.go
+38
-5
No files found.
controller/option.go
View file @
eb99ab1b
...
@@ -3,6 +3,7 @@ package controller
...
@@ -3,6 +3,7 @@ package controller
import
(
import
(
"fmt"
"fmt"
"net/http"
"net/http"
"slices"
"sort"
"sort"
"strconv"
"strconv"
"strings"
"strings"
...
@@ -85,7 +86,7 @@ func GetOptions(c *gin.Context) {
...
@@ -85,7 +86,7 @@ func GetOptions(c *gin.Context) {
optionValues
:=
make
(
map
[
string
]
string
)
optionValues
:=
make
(
map
[
string
]
string
)
common
.
OptionMapRWMutex
.
Lock
()
common
.
OptionMapRWMutex
.
Lock
()
for
k
,
v
:=
range
common
.
OptionMap
{
for
k
,
v
:=
range
common
.
OptionMap
{
if
k
==
"theme.frontend"
{
if
k
==
"theme.frontend"
||
k
==
"billing_setting.billing_mode"
||
k
==
"billing_setting.billing_expr"
{
continue
continue
}
}
value
:=
common
.
Interface2String
(
v
)
value
:=
common
.
Interface2String
(
v
)
...
@@ -101,14 +102,24 @@ func GetOptions(c *gin.Context) {
...
@@ -101,14 +102,24 @@ func GetOptions(c *gin.Context) {
Key
:
k
,
Key
:
k
,
Value
:
value
,
Value
:
value
,
})
})
for
_
,
optionKey
:=
range
completionRatioMetaOptionKeys
{
if
slices
.
Contains
(
completionRatioMetaOptionKeys
,
k
)
{
if
optionKey
==
k
{
optionValues
[
k
]
=
value
optionValues
[
k
]
=
value
break
}
}
}
}
}
common
.
OptionMapRWMutex
.
Unlock
()
common
.
OptionMapRWMutex
.
Unlock
()
// Display the same effective expressions used by pricing and settlement,
// including built-in defaults absent from persisted administrator options.
for
key
,
values
:=
range
map
[
string
]
map
[
string
]
string
{
"billing_setting.billing_mode"
:
billing_setting
.
GetBillingModeCopy
(),
"billing_setting.billing_expr"
:
billing_setting
.
GetBillingExprCopy
(),
}
{
encoded
,
err
:=
common
.
Marshal
(
values
)
if
err
!=
nil
{
c
.
JSON
(
http
.
StatusInternalServerError
,
gin
.
H
{
"success"
:
false
,
"message"
:
err
.
Error
()})
return
}
options
=
append
(
options
,
&
model
.
Option
{
Key
:
key
,
Value
:
string
(
encoded
)})
}
options
=
append
(
options
,
&
model
.
Option
{
options
=
append
(
options
,
&
model
.
Option
{
Key
:
"CompletionRatioMeta"
,
Key
:
"CompletionRatioMeta"
,
Value
:
buildCompletionRatioMetaValue
(
optionValues
),
Value
:
buildCompletionRatioMetaValue
(
optionValues
),
...
...
relay/channel/openai/constant.go
View file @
eb99ab1b
package
openai
package
openai
var
ModelList
=
[]
string
{
var
ModelList
=
[]
string
{
"gpt-6-astra"
,
"gpt-3.5-turbo"
,
"gpt-3.5-turbo-0613"
,
"gpt-3.5-turbo-1106"
,
"gpt-3.5-turbo-0125"
,
"gpt-3.5-turbo"
,
"gpt-3.5-turbo-0613"
,
"gpt-3.5-turbo-1106"
,
"gpt-3.5-turbo-0125"
,
"gpt-3.5-turbo-16k"
,
"gpt-3.5-turbo-16k-0613"
,
"gpt-3.5-turbo-16k"
,
"gpt-3.5-turbo-16k-0613"
,
"gpt-3.5-turbo-instruct"
,
"gpt-3.5-turbo-instruct-0914"
,
"gpt-3.5-turbo-instruct"
,
"gpt-3.5-turbo-instruct-0914"
,
...
...
setting/billing_setting/builtin_billing.go
0 → 100644
View file @
eb99ab1b
package
billing_setting
// Built-in token prices use actual USD per million tokens. Keep new model
// defaults here instead of splitting them across the legacy ratio tables.
var
builtinBillingExpr
=
map
[
string
]
string
{
// https://developers.openai.com/api/docs/models/gpt-6-astra
// Standard pricing; the long-context rates apply to the whole request.
// Do not infer service-tier discounts from incoming request parameters:
// channels filter service_tier by default, so it may not reach the upstream.
"gpt-6-astra"
:
`len <= 272000 ? tier("standard", p * 10 + c * 50 + cr * 1 + cc * 12.5) : tier("long_context", p * 20 + c * 75 + cr * 2 + cc * 25)`
,
}
setting/billing_setting/builtin_billing_test.go
0 → 100644
View file @
eb99ab1b
package
billing_setting_test
import
(
"net/http/httptest"
"testing"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/controller"
"github.com/QuantumNous/new-api/model"
"github.com/QuantumNous/new-api/pkg/billingexpr"
"github.com/QuantumNous/new-api/relaykit/dto"
"github.com/QuantumNous/new-api/service"
"github.com/QuantumNous/new-api/setting/billing_setting"
"github.com/QuantumNous/new-api/setting/config"
"github.com/QuantumNous/new-api/setting/ratio_setting"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func
TestGPT6AstraBuiltinBilling
(
t
*
testing
.
T
)
{
settings
:=
config
.
GlobalConfig
.
Get
(
"billing_setting"
)
.
(
*
billing_setting
.
BillingSetting
)
saved
:=
*
settings
savedRatios
,
savedPrices
:=
ratio_setting
.
ModelRatio2JSONString
(),
ratio_setting
.
ModelPrice2JSONString
()
savedOptions
:=
common
.
OptionMap
t
.
Cleanup
(
func
()
{
*
settings
,
common
.
OptionMap
=
saved
,
savedOptions
require
.
NoError
(
t
,
ratio_setting
.
UpdateModelRatioByJSONString
(
savedRatios
))
require
.
NoError
(
t
,
ratio_setting
.
UpdateModelPriceByJSONString
(
savedPrices
))
})
common
.
OptionMap
=
map
[
string
]
string
{
"billing_setting.billing_mode"
:
`{}`
,
"billing_setting.billing_expr"
:
`{}`
}
require
.
NoError
(
t
,
config
.
GlobalConfig
.
LoadFromDB
(
common
.
OptionMap
))
require
.
NoError
(
t
,
ratio_setting
.
UpdateModelRatioByJSONString
(
`{}`
))
require
.
NoError
(
t
,
ratio_setting
.
UpdateModelPriceByJSONString
(
`{}`
))
assert
.
Equal
(
t
,
billing_setting
.
BillingModeTieredExpr
,
billing_setting
.
GetBillingMode
(
"gpt-6-astra"
))
expression
,
ok
:=
billing_setting
.
GetBillingExpr
(
"gpt-6-astra"
)
require
.
True
(
t
,
ok
)
for
_
,
tc
:=
range
[]
struct
{
name
string
input
,
output
,
cached
,
written
int
request
string
quota
int
}{
{
"standard"
,
1000
,
100
,
0
,
0
,
`{}`
,
7500
},
{
"client flex cannot discount standard pricing"
,
1000
,
100
,
0
,
0
,
`{"service_tier":"flex"}`
,
7500
},
{
"cache at context boundary"
,
272000
,
1000
,
200000
,
20000
,
`{}`
,
510000
},
{
"whole request above boundary"
,
272001
,
1000
,
200000
,
20000
,
`{}`
,
1007510
},
}
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
usage
:=
&
dto
.
Usage
{
PromptTokens
:
tc
.
input
,
CompletionTokens
:
tc
.
output
,
PromptTokensDetails
:
dto
.
InputTokenDetails
{
CachedTokens
:
tc
.
cached
,
CacheWriteTokens
:
tc
.
written
},
}
params
:=
service
.
BuildTieredTokenParams
(
usage
,
false
,
billingexpr
.
UsedVars
(
expression
))
result
,
err
:=
billingexpr
.
ComputeTieredQuotaWithRequest
(
&
billingexpr
.
BillingSnapshot
{
ExprString
:
expression
,
GroupRatio
:
1
,
QuotaPerUnit
:
500000
,
},
params
,
billingexpr
.
RequestInput
{
Body
:
[]
byte
(
tc
.
request
)})
require
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
tc
.
quota
,
result
.
ActualQuotaAfterGroup
)
})
}
t
.
Run
(
"admin options expose defaults without persisting them"
,
func
(
t
*
testing
.
T
)
{
recorder
:=
httptest
.
NewRecorder
()
ctx
,
_
:=
gin
.
CreateTestContext
(
recorder
)
controller
.
GetOptions
(
ctx
)
var
response
struct
{
Success
bool
Data
[]
model
.
Option
}
require
.
NoError
(
t
,
common
.
Unmarshal
(
recorder
.
Body
.
Bytes
(),
&
response
))
require
.
True
(
t
,
response
.
Success
)
found
:=
map
[
string
]
string
{}
for
_
,
option
:=
range
response
.
Data
{
if
_
,
ok
:=
common
.
OptionMap
[
option
.
Key
];
ok
{
assert
.
NotContains
(
t
,
found
,
option
.
Key
)
var
values
map
[
string
]
string
require
.
NoError
(
t
,
common
.
UnmarshalJsonStr
(
option
.
Value
,
&
values
))
found
[
option
.
Key
]
=
values
[
"gpt-6-astra"
]
assert
.
Equal
(
t
,
`{}`
,
common
.
OptionMap
[
option
.
Key
])
}
}
assert
.
Equal
(
t
,
map
[
string
]
string
{
"billing_setting.billing_mode"
:
"tiered_expr"
,
"billing_setting.billing_expr"
:
expression
},
found
)
})
for
_
,
tc
:=
range
[]
struct
{
name
,
mode
,
expr
,
ratios
,
prices
,
wantMode
string
}{
{
"custom expression overrides legacy price"
,
"tiered_expr"
,
"p * 7"
,
`{"gpt-6-astra":8}`
,
`{}`
,
"tiered_expr"
},
{
"explicit ratio mode"
,
"ratio"
,
""
,
`{}`
,
`{}`
,
"ratio"
},
{
"existing free token price"
,
""
,
""
,
`{"gpt-6-astra":0}`
,
`{}`
,
"ratio"
},
{
"existing per-call price"
,
""
,
""
,
`{}`
,
`{"gpt-6-astra":0.1}`
,
"ratio"
},
}
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
*
settings
=
billing_setting
.
BillingSetting
{
BillingMode
:
map
[
string
]
string
{},
BillingExpr
:
map
[
string
]
string
{}}
if
tc
.
mode
!=
""
{
settings
.
BillingMode
[
"gpt-6-astra"
]
=
tc
.
mode
}
if
tc
.
expr
!=
""
{
settings
.
BillingExpr
[
"gpt-6-astra"
]
=
tc
.
expr
}
require
.
NoError
(
t
,
ratio_setting
.
UpdateModelRatioByJSONString
(
tc
.
ratios
))
require
.
NoError
(
t
,
ratio_setting
.
UpdateModelPriceByJSONString
(
tc
.
prices
))
assert
.
Equal
(
t
,
tc
.
wantMode
,
billing_setting
.
GetBillingMode
(
"gpt-6-astra"
))
actual
,
ok
:=
billing_setting
.
GetBillingExpr
(
"gpt-6-astra"
)
assert
.
Equal
(
t
,
tc
.
expr
,
actual
)
assert
.
Equal
(
t
,
tc
.
expr
!=
""
,
ok
)
})
}
}
setting/billing_setting/tiered_billing.go
View file @
eb99ab1b
...
@@ -6,11 +6,12 @@ import (
...
@@ -6,11 +6,12 @@ import (
"sort"
"sort"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/relaykit/dto"
"github.com/QuantumNous/new-api/pkg/billingexpr"
"github.com/QuantumNous/new-api/pkg/billingexpr"
"github.com/QuantumNous/new-api/pkg/jsplugin"
"github.com/QuantumNous/new-api/pkg/jsplugin"
relaycommon
"github.com/QuantumNous/new-api/relay/common"
relaycommon
"github.com/QuantumNous/new-api/relay/common"
"github.com/QuantumNous/new-api/relaykit/dto"
"github.com/QuantumNous/new-api/setting/config"
"github.com/QuantumNous/new-api/setting/config"
"github.com/QuantumNous/new-api/setting/ratio_setting"
"github.com/samber/lo"
"github.com/samber/lo"
)
)
...
@@ -46,20 +47,52 @@ func GetBillingMode(model string) string {
...
@@ -46,20 +47,52 @@ func GetBillingMode(model string) string {
if
mode
,
ok
:=
billingSetting
.
BillingMode
[
model
];
ok
{
if
mode
,
ok
:=
billingSetting
.
BillingMode
[
model
];
ok
{
return
mode
return
mode
}
}
if
_
,
ok
:=
builtinBillingExpr
[
model
];
ok
{
// Existing administrator-configured legacy prices take precedence over
// a newly introduced built-in expression unless a mode was explicit.
if
ratio_setting
.
HasConfiguredModelRatio
(
model
)
{
return
BillingModeRatio
}
if
_
,
configured
:=
ratio_setting
.
GetModelPrice
(
model
,
false
);
configured
{
return
BillingModeRatio
}
return
BillingModeTieredExpr
}
return
BillingModeRatio
return
BillingModeRatio
}
}
func
GetBillingExpr
(
model
string
)
(
string
,
bool
)
{
func
GetBillingExpr
(
model
string
)
(
string
,
bool
)
{
expr
,
ok
:=
billingSetting
.
BillingExpr
[
model
]
if
expr
,
ok
:=
billingSetting
.
BillingExpr
[
model
];
ok
{
return
expr
,
ok
return
expr
,
true
}
if
GetBillingMode
(
model
)
==
BillingModeTieredExpr
{
expr
,
ok
:=
builtinBillingExpr
[
model
]
return
expr
,
ok
}
return
""
,
false
}
}
func
GetBillingModeCopy
()
map
[
string
]
string
{
func
GetBillingModeCopy
()
map
[
string
]
string
{
return
lo
.
Assign
(
billingSetting
.
BillingMode
)
modes
:=
lo
.
Assign
(
billingSetting
.
BillingMode
)
for
model
:=
range
builtinBillingExpr
{
if
_
,
configured
:=
modes
[
model
];
!
configured
&&
GetBillingMode
(
model
)
==
BillingModeTieredExpr
{
modes
[
model
]
=
BillingModeTieredExpr
}
}
return
modes
}
}
func
GetBillingExprCopy
()
map
[
string
]
string
{
func
GetBillingExprCopy
()
map
[
string
]
string
{
return
lo
.
Assign
(
billingSetting
.
BillingExpr
)
expressions
:=
lo
.
Assign
(
billingSetting
.
BillingExpr
)
for
model
:=
range
builtinBillingExpr
{
if
_
,
configured
:=
expressions
[
model
];
configured
{
continue
}
if
expression
,
ok
:=
GetBillingExpr
(
model
);
ok
{
expressions
[
model
]
=
expression
}
}
return
expressions
}
}
func
GetPricingSyncData
(
base
map
[
string
]
any
)
map
[
string
]
any
{
func
GetPricingSyncData
(
base
map
[
string
]
any
)
map
[
string
]
any
{
...
...
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