feat: able to configure ratio for more models now (close #53)
This commit is contained in:
parent
241ade2fae
commit
d9db16e999
@ -49,11 +49,6 @@ var TurnstileSecretKey = ""
|
|||||||
|
|
||||||
var QuotaForNewUser = 100
|
var QuotaForNewUser = 100
|
||||||
|
|
||||||
// https://platform.openai.com/docs/models/model-endpoint-compatibility
|
|
||||||
var RatioGPT3dot5 float64 = 2
|
|
||||||
var RatioGPT4 float64 = 30
|
|
||||||
var RatioGPT4_32k float64 = 60
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RoleGuestUser = 0
|
RoleGuestUser = 0
|
||||||
RoleCommonUser = 1
|
RoleCommonUser = 1
|
||||||
|
52
common/model-ratio.go
Normal file
52
common/model-ratio.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
|
// https://platform.openai.com/docs/models/model-endpoint-compatibility
|
||||||
|
// https://openai.com/pricing
|
||||||
|
// TODO: when a new api is enabled, check the pricing here
|
||||||
|
var ModelRatio = map[string]float64{
|
||||||
|
"gpt-4": 15,
|
||||||
|
"gpt-4-0314": 15,
|
||||||
|
"gpt-4-32k": 30,
|
||||||
|
"gpt-4-32k-0314": 30,
|
||||||
|
"gpt-3.5-turbo": 1,
|
||||||
|
"gpt-3.5-turbo-0301": 1,
|
||||||
|
"text-ada-001": 0.2,
|
||||||
|
"text-babbage-001": 0.25,
|
||||||
|
"text-curie-001": 1,
|
||||||
|
"text-davinci-002": 10,
|
||||||
|
"text-davinci-003": 10,
|
||||||
|
"text-davinci-edit-001": 10,
|
||||||
|
"code-davinci-edit-001": 10,
|
||||||
|
"whisper-1": 10,
|
||||||
|
"davinci": 10,
|
||||||
|
"curie": 10,
|
||||||
|
"babbage": 10,
|
||||||
|
"ada": 10,
|
||||||
|
"text-embedding-ada-002": 0.25,
|
||||||
|
"text-search-ada-doc-001": 10,
|
||||||
|
"text-moderation-stable": 10,
|
||||||
|
"text-moderation-latest": 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
func ModelRatio2JSONString() string {
|
||||||
|
jsonBytes, err := json.Marshal(ModelRatio)
|
||||||
|
if err != nil {
|
||||||
|
SysError("Error marshalling model ratio: " + err.Error())
|
||||||
|
}
|
||||||
|
return string(jsonBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateModelRatioByJSONString(jsonStr string) error {
|
||||||
|
return json.Unmarshal([]byte(jsonStr), &ModelRatio)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetModelRatio(name string) float64 {
|
||||||
|
ratio, ok := ModelRatio[name]
|
||||||
|
if !ok {
|
||||||
|
SysError("Model ratio not found: " + name)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return ratio
|
||||||
|
}
|
@ -118,24 +118,22 @@ func relayHelper(c *gin.Context) error {
|
|||||||
defer func() {
|
defer func() {
|
||||||
if consumeQuota {
|
if consumeQuota {
|
||||||
quota := 0
|
quota := 0
|
||||||
|
usingGPT4 := strings.HasPrefix(textRequest.Model, "gpt-4")
|
||||||
|
completionRatio := 1
|
||||||
|
if usingGPT4 {
|
||||||
|
completionRatio = 2
|
||||||
|
}
|
||||||
if isStream {
|
if isStream {
|
||||||
var text string
|
var promptText string
|
||||||
for _, message := range textRequest.Messages {
|
for _, message := range textRequest.Messages {
|
||||||
text += fmt.Sprintf("%s: %s\n", message.Role, message.Content)
|
promptText += fmt.Sprintf("%s: %s\n", message.Role, message.Content)
|
||||||
}
|
}
|
||||||
text += fmt.Sprintf("%s: %s\n", "assistant", streamResponseText)
|
completionText := fmt.Sprintf("%s: %s\n", "assistant", streamResponseText)
|
||||||
quota = countToken(text) + 3
|
quota = countToken(promptText) + countToken(completionText)*completionRatio + 3
|
||||||
} else {
|
} else {
|
||||||
quota = textResponse.Usage.TotalTokens
|
quota = textResponse.Usage.PromptTokens + textResponse.Usage.CompletionTokens*completionRatio
|
||||||
}
|
|
||||||
ratio := common.RatioGPT3dot5
|
|
||||||
if strings.HasPrefix(textRequest.Model, "gpt-4-32k") {
|
|
||||||
ratio = common.RatioGPT4_32k
|
|
||||||
} else if strings.HasPrefix(textRequest.Model, "gpt-4") {
|
|
||||||
ratio = common.RatioGPT4
|
|
||||||
} else {
|
|
||||||
ratio = common.RatioGPT3dot5
|
|
||||||
}
|
}
|
||||||
|
ratio := common.GetModelRatio(textRequest.Model)
|
||||||
quota = int(float64(quota) * ratio)
|
quota = int(float64(quota) * ratio)
|
||||||
err := model.DecreaseTokenQuota(tokenId, quota)
|
err := model.DecreaseTokenQuota(tokenId, quota)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -47,9 +47,7 @@ func InitOptionMap() {
|
|||||||
common.OptionMap["TurnstileSiteKey"] = ""
|
common.OptionMap["TurnstileSiteKey"] = ""
|
||||||
common.OptionMap["TurnstileSecretKey"] = ""
|
common.OptionMap["TurnstileSecretKey"] = ""
|
||||||
common.OptionMap["QuotaForNewUser"] = strconv.Itoa(common.QuotaForNewUser)
|
common.OptionMap["QuotaForNewUser"] = strconv.Itoa(common.QuotaForNewUser)
|
||||||
common.OptionMap["RatioGPT3dot5"] = strconv.FormatFloat(common.RatioGPT3dot5, 'f', -1, 64)
|
common.OptionMap["ModelRatio"] = common.ModelRatio2JSONString()
|
||||||
common.OptionMap["RatioGPT4"] = strconv.FormatFloat(common.RatioGPT4, 'f', -1, 64)
|
|
||||||
common.OptionMap["RatioGPT4_32k"] = strconv.FormatFloat(common.RatioGPT4_32k, 'f', -1, 64)
|
|
||||||
common.OptionMap["TopUpLink"] = common.TopUpLink
|
common.OptionMap["TopUpLink"] = common.TopUpLink
|
||||||
common.OptionMapRWMutex.Unlock()
|
common.OptionMapRWMutex.Unlock()
|
||||||
options, _ := AllOption()
|
options, _ := AllOption()
|
||||||
@ -75,7 +73,7 @@ func UpdateOption(key string, value string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateOptionMap(key string, value string) {
|
func updateOptionMap(key string, value string) (err error) {
|
||||||
common.OptionMapRWMutex.Lock()
|
common.OptionMapRWMutex.Lock()
|
||||||
defer common.OptionMapRWMutex.Unlock()
|
defer common.OptionMapRWMutex.Unlock()
|
||||||
common.OptionMap[key] = value
|
common.OptionMap[key] = value
|
||||||
@ -138,13 +136,10 @@ func updateOptionMap(key string, value string) {
|
|||||||
common.TurnstileSecretKey = value
|
common.TurnstileSecretKey = value
|
||||||
case "QuotaForNewUser":
|
case "QuotaForNewUser":
|
||||||
common.QuotaForNewUser, _ = strconv.Atoi(value)
|
common.QuotaForNewUser, _ = strconv.Atoi(value)
|
||||||
case "RatioGPT3dot5":
|
case "ModelRatio":
|
||||||
common.RatioGPT3dot5, _ = strconv.ParseFloat(value, 64)
|
err = common.UpdateModelRatioByJSONString(value)
|
||||||
case "RatioGPT4":
|
|
||||||
common.RatioGPT4, _ = strconv.ParseFloat(value, 64)
|
|
||||||
case "RatioGPT4_32k":
|
|
||||||
common.RatioGPT4_32k, _ = strconv.ParseFloat(value, 64)
|
|
||||||
case "TopUpLink":
|
case "TopUpLink":
|
||||||
common.TopUpLink = value
|
common.TopUpLink = value
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Divider, Form, Grid, Header, Message } from 'semantic-ui-react';
|
import { Divider, Form, Grid, Header, Message } from 'semantic-ui-react';
|
||||||
import { API, removeTrailingSlash, showError } from '../helpers';
|
import { API, removeTrailingSlash, showError, verifyJSON } from '../helpers';
|
||||||
|
|
||||||
const SystemSetting = () => {
|
const SystemSetting = () => {
|
||||||
let [inputs, setInputs] = useState({
|
let [inputs, setInputs] = useState({
|
||||||
@ -25,9 +25,7 @@ const SystemSetting = () => {
|
|||||||
TurnstileSecretKey: '',
|
TurnstileSecretKey: '',
|
||||||
RegisterEnabled: '',
|
RegisterEnabled: '',
|
||||||
QuotaForNewUser: 0,
|
QuotaForNewUser: 0,
|
||||||
RatioGPT3dot5: 2,
|
ModelRatio: '',
|
||||||
RatioGPT4: 30,
|
|
||||||
RatioGPT4_32k: 60,
|
|
||||||
TopUpLink: ''
|
TopUpLink: ''
|
||||||
});
|
});
|
||||||
let originInputs = {};
|
let originInputs = {};
|
||||||
@ -93,7 +91,7 @@ const SystemSetting = () => {
|
|||||||
name === 'TurnstileSiteKey' ||
|
name === 'TurnstileSiteKey' ||
|
||||||
name === 'TurnstileSecretKey' ||
|
name === 'TurnstileSecretKey' ||
|
||||||
name === 'QuotaForNewUser' ||
|
name === 'QuotaForNewUser' ||
|
||||||
name.startsWith('Ratio') ||
|
name === 'ModelRatio' ||
|
||||||
name === 'TopUpLink'
|
name === 'TopUpLink'
|
||||||
) {
|
) {
|
||||||
setInputs((inputs) => ({ ...inputs, [name]: value }));
|
setInputs((inputs) => ({ ...inputs, [name]: value }));
|
||||||
@ -111,19 +109,17 @@ const SystemSetting = () => {
|
|||||||
if (originInputs['QuotaForNewUser'] !== inputs.QuotaForNewUser) {
|
if (originInputs['QuotaForNewUser'] !== inputs.QuotaForNewUser) {
|
||||||
await updateOption('QuotaForNewUser', inputs.QuotaForNewUser);
|
await updateOption('QuotaForNewUser', inputs.QuotaForNewUser);
|
||||||
}
|
}
|
||||||
if (originInputs['RatioGPT3dot5'] !== inputs.RatioGPT3dot5) {
|
if (originInputs['ModelRatio'] !== inputs.ModelRatio) {
|
||||||
await updateOption('RatioGPT3dot5', inputs.RatioGPT3dot5);
|
if (!verifyJSON(inputs.ModelRatio)) {
|
||||||
|
showError('模型倍率不是合法的 JSON 字符串');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (originInputs['RatioGPT4'] !== inputs.RatioGPT4) {
|
await updateOption('ModelRatio', inputs.ModelRatio);
|
||||||
await updateOption('RatioGPT4', inputs.RatioGPT4);
|
|
||||||
}
|
|
||||||
if (originInputs['RatioGPT4_32k'] !== inputs.RatioGPT4_32k) {
|
|
||||||
await updateOption('RatioGPT4_32k', inputs.RatioGPT4_32k);
|
|
||||||
}
|
}
|
||||||
if (originInputs['TopUpLink'] !== inputs.TopUpLink) {
|
if (originInputs['TopUpLink'] !== inputs.TopUpLink) {
|
||||||
await updateOption('TopUpLink', inputs.TopUpLink);
|
await updateOption('TopUpLink', inputs.TopUpLink);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const submitSMTP = async () => {
|
const submitSMTP = async () => {
|
||||||
if (originInputs['SMTPServer'] !== inputs.SMTPServer) {
|
if (originInputs['SMTPServer'] !== inputs.SMTPServer) {
|
||||||
@ -278,39 +274,15 @@ const SystemSetting = () => {
|
|||||||
placeholder='例如发卡网站的购买链接'
|
placeholder='例如发卡网站的购买链接'
|
||||||
/>
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
<Form.Group widths={3}>
|
<Form.Group widths='equal'>
|
||||||
<Form.Input
|
<Form.TextArea
|
||||||
label='GPT-3.5 系列模型倍率'
|
label='模型倍率'
|
||||||
name='RatioGPT3dot5'
|
name='ModelRatio'
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
|
style={{ minHeight: 250, fontFamily: 'JetBrains Mono, Consolas' }}
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
value={inputs.RatioGPT3dot5}
|
value={inputs.ModelRatio}
|
||||||
type='number'
|
placeholder='为一个 JSON 文本,键为模型名称,值为倍率'
|
||||||
step='0.01'
|
|
||||||
min='0'
|
|
||||||
placeholder='例如:2'
|
|
||||||
/>
|
|
||||||
<Form.Input
|
|
||||||
label='GPT-4 系列模型倍率'
|
|
||||||
name='RatioGPT4'
|
|
||||||
onChange={handleInputChange}
|
|
||||||
autoComplete='off'
|
|
||||||
value={inputs.RatioGPT4}
|
|
||||||
type='number'
|
|
||||||
step='0.01'
|
|
||||||
min='0'
|
|
||||||
placeholder='例如:30'
|
|
||||||
/>
|
|
||||||
<Form.Input
|
|
||||||
label='GPT-4 32k 系列模型倍率'
|
|
||||||
name='RatioGPT4_32k'
|
|
||||||
onChange={handleInputChange}
|
|
||||||
autoComplete='off'
|
|
||||||
value={inputs.RatioGPT4_32k}
|
|
||||||
type='number'
|
|
||||||
step='0.01'
|
|
||||||
min='0'
|
|
||||||
placeholder='例如:60'
|
|
||||||
/>
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
<Form.Button onClick={submitOperationConfig}>保存运营设置</Form.Button>
|
<Form.Button onClick={submitOperationConfig}>保存运营设置</Form.Button>
|
||||||
|
@ -153,3 +153,12 @@ export function downloadTextAsFile(text, filename) {
|
|||||||
a.download = filename;
|
a.download = filename;
|
||||||
a.click();
|
a.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const verifyJSON = (str) => {
|
||||||
|
try {
|
||||||
|
JSON.parse(str);
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user