mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-03-30 02:44:40 +00:00
feat: 图像倍率,音频倍率和音频补全倍率配置
This commit is contained in:
@@ -112,6 +112,33 @@ func UpdateOption(c *gin.Context) {
|
||||
})
|
||||
return
|
||||
}
|
||||
case "ImageRatio":
|
||||
err = ratio_setting.UpdateImageRatioByJSONString(option.Value)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": false,
|
||||
"message": "图片倍率设置失败: " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
case "AudioRatio":
|
||||
err = ratio_setting.UpdateAudioRatioByJSONString(option.Value)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": false,
|
||||
"message": "音频倍率设置失败: " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
case "AudioCompletionRatio":
|
||||
err = ratio_setting.UpdateAudioCompletionRatioByJSONString(option.Value)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": false,
|
||||
"message": "音频补全倍率设置失败: " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
case "ModelRequestRateLimitGroup":
|
||||
err = setting.CheckModelRequestRateLimitGroup(option.Value)
|
||||
if err != nil {
|
||||
|
||||
@@ -111,6 +111,9 @@ func InitOptionMap() {
|
||||
common.OptionMap["GroupGroupRatio"] = ratio_setting.GroupGroupRatio2JSONString()
|
||||
common.OptionMap["UserUsableGroups"] = setting.UserUsableGroups2JSONString()
|
||||
common.OptionMap["CompletionRatio"] = ratio_setting.CompletionRatio2JSONString()
|
||||
common.OptionMap["ImageRatio"] = ratio_setting.ImageRatio2JSONString()
|
||||
common.OptionMap["AudioRatio"] = ratio_setting.AudioRatio2JSONString()
|
||||
common.OptionMap["AudioCompletionRatio"] = ratio_setting.AudioCompletionRatio2JSONString()
|
||||
common.OptionMap["TopUpLink"] = common.TopUpLink
|
||||
//common.OptionMap["ChatLink"] = common.ChatLink
|
||||
//common.OptionMap["ChatLink2"] = common.ChatLink2
|
||||
@@ -396,6 +399,12 @@ func updateOptionMap(key string, value string) (err error) {
|
||||
err = ratio_setting.UpdateModelPriceByJSONString(value)
|
||||
case "CacheRatio":
|
||||
err = ratio_setting.UpdateCacheRatioByJSONString(value)
|
||||
case "ImageRatio":
|
||||
err = ratio_setting.UpdateImageRatioByJSONString(value)
|
||||
case "AudioRatio":
|
||||
err = ratio_setting.UpdateAudioRatioByJSONString(value)
|
||||
case "AudioCompletionRatio":
|
||||
err = ratio_setting.UpdateAudioCompletionRatioByJSONString(value)
|
||||
case "TopUpLink":
|
||||
common.TopUpLink = value
|
||||
//case "ChatLink":
|
||||
|
||||
@@ -52,6 +52,8 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
|
||||
var cacheRatio float64
|
||||
var imageRatio float64
|
||||
var cacheCreationRatio float64
|
||||
var audioRatio float64
|
||||
var audioCompletionRatio float64
|
||||
if !usePrice {
|
||||
preConsumedTokens := common.Max(promptTokens, common.PreConsumedQuota)
|
||||
if meta.MaxTokens != 0 {
|
||||
@@ -73,6 +75,8 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
|
||||
cacheRatio, _ = ratio_setting.GetCacheRatio(info.OriginModelName)
|
||||
cacheCreationRatio, _ = ratio_setting.GetCreateCacheRatio(info.OriginModelName)
|
||||
imageRatio, _ = ratio_setting.GetImageRatio(info.OriginModelName)
|
||||
audioRatio = ratio_setting.GetAudioRatio(info.OriginModelName)
|
||||
audioCompletionRatio = ratio_setting.GetAudioCompletionRatio(info.OriginModelName)
|
||||
ratio := modelRatio * groupRatioInfo.GroupRatio
|
||||
preConsumedQuota = int(float64(preConsumedTokens) * ratio)
|
||||
} else {
|
||||
@@ -90,6 +94,8 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
|
||||
UsePrice: usePrice,
|
||||
CacheRatio: cacheRatio,
|
||||
ImageRatio: imageRatio,
|
||||
AudioRatio: audioRatio,
|
||||
AudioCompletionRatio: audioCompletionRatio,
|
||||
CacheCreationRatio: cacheCreationRatio,
|
||||
ShouldPreConsumedQuota: preConsumedQuota,
|
||||
}
|
||||
|
||||
@@ -278,6 +278,18 @@ var defaultModelPrice = map[string]float64{
|
||||
"mj_upload": 0.05,
|
||||
}
|
||||
|
||||
var defaultAudioRatio = map[string]float64{
|
||||
"gpt-4o-audio-preview": 16,
|
||||
"gpt-4o-mini-audio-preview": 66.67,
|
||||
"gpt-4o-realtime-preview": 8,
|
||||
"gpt-4o-mini-realtime-preview": 16.67,
|
||||
}
|
||||
|
||||
var defaultAudioCompletionRatio = map[string]float64{
|
||||
"gpt-4o-realtime": 2,
|
||||
"gpt-4o-mini-realtime": 2,
|
||||
}
|
||||
|
||||
var (
|
||||
modelPriceMap map[string]float64 = nil
|
||||
modelPriceMapMutex = sync.RWMutex{}
|
||||
@@ -326,6 +338,15 @@ func InitRatioSettings() {
|
||||
imageRatioMap = defaultImageRatio
|
||||
imageRatioMapMutex.Unlock()
|
||||
|
||||
// initialize audioRatioMap
|
||||
audioRatioMapMutex.Lock()
|
||||
audioRatioMap = defaultAudioRatio
|
||||
audioRatioMapMutex.Unlock()
|
||||
|
||||
// initialize audioCompletionRatioMap
|
||||
audioCompletionRatioMapMutex.Lock()
|
||||
audioCompletionRatioMap = defaultAudioCompletionRatio
|
||||
audioCompletionRatioMapMutex.Unlock()
|
||||
}
|
||||
|
||||
func GetModelPriceMap() map[string]float64 {
|
||||
@@ -417,6 +438,18 @@ func GetDefaultModelRatioMap() map[string]float64 {
|
||||
return defaultModelRatio
|
||||
}
|
||||
|
||||
func GetDefaultImageRatioMap() map[string]float64 {
|
||||
return defaultImageRatio
|
||||
}
|
||||
|
||||
func GetDefaultAudioRatioMap() map[string]float64 {
|
||||
return defaultAudioRatio
|
||||
}
|
||||
|
||||
func GetDefaultAudioCompletionRatioMap() map[string]float64 {
|
||||
return defaultAudioCompletionRatio
|
||||
}
|
||||
|
||||
func GetCompletionRatioMap() map[string]float64 {
|
||||
CompletionRatioMutex.RLock()
|
||||
defer CompletionRatioMutex.RUnlock()
|
||||
@@ -584,32 +617,20 @@ func getHardcodedCompletionModelRatio(name string) (float64, bool) {
|
||||
}
|
||||
|
||||
func GetAudioRatio(name string) float64 {
|
||||
if strings.Contains(name, "-realtime") {
|
||||
if strings.HasSuffix(name, "gpt-4o-realtime-preview") {
|
||||
return 8
|
||||
} else if strings.Contains(name, "gpt-4o-mini-realtime-preview") {
|
||||
return 10 / 0.6
|
||||
} else {
|
||||
return 20
|
||||
}
|
||||
}
|
||||
if strings.Contains(name, "-audio") {
|
||||
if strings.HasPrefix(name, "gpt-4o-audio-preview") {
|
||||
return 40 / 2.5
|
||||
} else if strings.HasPrefix(name, "gpt-4o-mini-audio-preview") {
|
||||
return 10 / 0.15
|
||||
} else {
|
||||
return 40
|
||||
}
|
||||
audioRatioMapMutex.RLock()
|
||||
defer audioRatioMapMutex.RUnlock()
|
||||
if ratio, ok := audioRatioMap[name]; ok {
|
||||
return ratio
|
||||
}
|
||||
return 20
|
||||
}
|
||||
|
||||
func GetAudioCompletionRatio(name string) float64 {
|
||||
if strings.HasPrefix(name, "gpt-4o-realtime") {
|
||||
return 2
|
||||
} else if strings.HasPrefix(name, "gpt-4o-mini-realtime") {
|
||||
return 2
|
||||
audioCompletionRatioMapMutex.RLock()
|
||||
defer audioCompletionRatioMapMutex.RUnlock()
|
||||
if ratio, ok := audioCompletionRatioMap[name]; ok {
|
||||
|
||||
return ratio
|
||||
}
|
||||
return 2
|
||||
}
|
||||
@@ -630,6 +651,14 @@ var defaultImageRatio = map[string]float64{
|
||||
}
|
||||
var imageRatioMap map[string]float64
|
||||
var imageRatioMapMutex sync.RWMutex
|
||||
var (
|
||||
audioRatioMap map[string]float64 = nil
|
||||
audioRatioMapMutex = sync.RWMutex{}
|
||||
)
|
||||
var (
|
||||
audioCompletionRatioMap map[string]float64 = nil
|
||||
audioCompletionRatioMapMutex = sync.RWMutex{}
|
||||
)
|
||||
|
||||
func ImageRatio2JSONString() string {
|
||||
imageRatioMapMutex.RLock()
|
||||
@@ -658,6 +687,68 @@ func GetImageRatio(name string) (float64, bool) {
|
||||
return ratio, true
|
||||
}
|
||||
|
||||
func AudioRatio2JSONString() string {
|
||||
audioRatioMapMutex.RLock()
|
||||
defer audioRatioMapMutex.RUnlock()
|
||||
jsonBytes, err := common.Marshal(audioRatioMap)
|
||||
if err != nil {
|
||||
common.SysError("error marshalling audio ratio: " + err.Error())
|
||||
}
|
||||
return string(jsonBytes)
|
||||
}
|
||||
|
||||
func UpdateAudioRatioByJSONString(jsonStr string) error {
|
||||
audioRatioMapMutex.Lock()
|
||||
defer audioRatioMapMutex.Unlock()
|
||||
audioRatioMap = make(map[string]float64)
|
||||
err := common.Unmarshal([]byte(jsonStr), &audioRatioMap)
|
||||
if err == nil {
|
||||
InvalidateExposedDataCache()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func GetAudioRatioCopy() map[string]float64 {
|
||||
audioRatioMapMutex.RLock()
|
||||
defer audioRatioMapMutex.RUnlock()
|
||||
copyMap := make(map[string]float64, len(audioRatioMap))
|
||||
for k, v := range audioRatioMap {
|
||||
copyMap[k] = v
|
||||
}
|
||||
return copyMap
|
||||
}
|
||||
|
||||
func AudioCompletionRatio2JSONString() string {
|
||||
audioCompletionRatioMapMutex.RLock()
|
||||
defer audioCompletionRatioMapMutex.RUnlock()
|
||||
jsonBytes, err := common.Marshal(audioCompletionRatioMap)
|
||||
if err != nil {
|
||||
common.SysError("error marshalling audio completion ratio: " + err.Error())
|
||||
}
|
||||
return string(jsonBytes)
|
||||
}
|
||||
|
||||
func UpdateAudioCompletionRatioByJSONString(jsonStr string) error {
|
||||
audioCompletionRatioMapMutex.Lock()
|
||||
defer audioCompletionRatioMapMutex.Unlock()
|
||||
audioCompletionRatioMap = make(map[string]float64)
|
||||
err := common.Unmarshal([]byte(jsonStr), &audioCompletionRatioMap)
|
||||
if err == nil {
|
||||
InvalidateExposedDataCache()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func GetAudioCompletionRatioCopy() map[string]float64 {
|
||||
audioCompletionRatioMapMutex.RLock()
|
||||
defer audioCompletionRatioMapMutex.RUnlock()
|
||||
copyMap := make(map[string]float64, len(audioCompletionRatioMap))
|
||||
for k, v := range audioCompletionRatioMap {
|
||||
copyMap[k] = v
|
||||
}
|
||||
return copyMap
|
||||
}
|
||||
|
||||
func GetModelRatioCopy() map[string]float64 {
|
||||
modelRatioMapMutex.RLock()
|
||||
defer modelRatioMapMutex.RUnlock()
|
||||
|
||||
@@ -15,6 +15,8 @@ type PriceData struct {
|
||||
CacheRatio float64
|
||||
CacheCreationRatio float64
|
||||
ImageRatio float64
|
||||
AudioRatio float64
|
||||
AudioCompletionRatio float64
|
||||
UsePrice bool
|
||||
ShouldPreConsumedQuota int
|
||||
GroupRatioInfo GroupRatioInfo
|
||||
@@ -27,5 +29,5 @@ type PerCallPriceData struct {
|
||||
}
|
||||
|
||||
func (p PriceData) ToSetting() string {
|
||||
return fmt.Sprintf("ModelPrice: %f, ModelRatio: %f, CompletionRatio: %f, CacheRatio: %f, GroupRatio: %f, UsePrice: %t, CacheCreationRatio: %f, ShouldPreConsumedQuota: %d, ImageRatio: %f", p.ModelPrice, p.ModelRatio, p.CompletionRatio, p.CacheRatio, p.GroupRatioInfo.GroupRatio, p.UsePrice, p.CacheCreationRatio, p.ShouldPreConsumedQuota, p.ImageRatio)
|
||||
return fmt.Sprintf("ModelPrice: %f, ModelRatio: %f, CompletionRatio: %f, CacheRatio: %f, GroupRatio: %f, UsePrice: %t, CacheCreationRatio: %f, ShouldPreConsumedQuota: %d, ImageRatio: %f, AudioRatio: %f, AudioCompletionRatio: %f", p.ModelPrice, p.ModelRatio, p.CompletionRatio, p.CacheRatio, p.GroupRatioInfo.GroupRatio, p.UsePrice, p.CacheCreationRatio, p.ShouldPreConsumedQuota, p.ImageRatio, p.AudioRatio, p.AudioCompletionRatio)
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ const RatioSetting = () => {
|
||||
CompletionRatio: '',
|
||||
GroupRatio: '',
|
||||
GroupGroupRatio: '',
|
||||
ImageRatio: '',
|
||||
AudioRatio: '',
|
||||
AudioCompletionRatio: '',
|
||||
AutoGroups: '',
|
||||
DefaultUseAutoGroup: false,
|
||||
ExposeRatioEnabled: false,
|
||||
@@ -61,7 +64,10 @@ const RatioSetting = () => {
|
||||
item.key === 'UserUsableGroups' ||
|
||||
item.key === 'CompletionRatio' ||
|
||||
item.key === 'ModelPrice' ||
|
||||
item.key === 'CacheRatio'
|
||||
item.key === 'CacheRatio' ||
|
||||
item.key === 'ImageRatio' ||
|
||||
item.key === 'AudioRatio' ||
|
||||
item.key === 'AudioCompletionRatio'
|
||||
) {
|
||||
try {
|
||||
item.value = JSON.stringify(JSON.parse(item.value), null, 2);
|
||||
|
||||
@@ -2017,5 +2017,15 @@
|
||||
"查看密钥": "View key",
|
||||
"查看渠道密钥": "View channel key",
|
||||
"渠道密钥信息": "Channel key information",
|
||||
"密钥获取成功": "Key acquisition successful"
|
||||
"密钥获取成功": "Key acquisition successful",
|
||||
"模型补全倍率(仅对自定义模型有效)": "Model completion ratio (only effective for custom models)",
|
||||
"图片倍率": "Image ratio",
|
||||
"音频倍率": "Audio ratio",
|
||||
"音频补全倍率": "Audio completion ratio",
|
||||
"图片输入相关的倍率设置,键为模型名称,值为倍率": "Image input related ratio settings, key is model name, value is ratio",
|
||||
"音频输入相关的倍率设置,键为模型名称,值为倍率": "Audio input related ratio settings, key is model name, value is ratio",
|
||||
"音频输出补全相关的倍率设置,键为模型名称,值为倍率": "Audio output completion related ratio settings, key is model name, value is ratio",
|
||||
"为一个 JSON 文本,键为模型名称,值为倍率,例如:{\"gpt-image-1\": 2}": "A JSON text with model name as key and ratio as value, e.g.: {\"gpt-image-1\": 2}",
|
||||
"为一个 JSON 文本,键为模型名称,值为倍率,例如:{\"gpt-4o-audio-preview\": 16}": "A JSON text with model name as key and ratio as value, e.g.: {\"gpt-4o-audio-preview\": 16}",
|
||||
"为一个 JSON 文本,键为模型名称,值为倍率,例如:{\"gpt-4o-realtime\": 2}": "A JSON text with model name as key and ratio as value, e.g.: {\"gpt-4o-realtime\": 2}"
|
||||
}
|
||||
|
||||
@@ -44,6 +44,9 @@ export default function ModelRatioSettings(props) {
|
||||
ModelRatio: '',
|
||||
CacheRatio: '',
|
||||
CompletionRatio: '',
|
||||
ImageRatio: '',
|
||||
AudioRatio: '',
|
||||
AudioCompletionRatio: '',
|
||||
ExposeRatioEnabled: false,
|
||||
});
|
||||
const refForm = useRef();
|
||||
@@ -219,6 +222,72 @@ export default function ModelRatioSettings(props) {
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} sm={16}>
|
||||
<Form.TextArea
|
||||
label={t('图片倍率')}
|
||||
extraText={t('图片输入相关的倍率设置,键为模型名称,值为倍率')}
|
||||
placeholder={t('为一个 JSON 文本,键为模型名称,值为倍率,例如:{"gpt-image-1": 2}')}
|
||||
field={'ImageRatio'}
|
||||
autosize={{ minRows: 6, maxRows: 12 }}
|
||||
trigger='blur'
|
||||
stopValidateWithError
|
||||
rules={[
|
||||
{
|
||||
validator: (rule, value) => verifyJSON(value),
|
||||
message: '不是合法的 JSON 字符串',
|
||||
},
|
||||
]}
|
||||
onChange={(value) =>
|
||||
setInputs({ ...inputs, ImageRatio: value })
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} sm={16}>
|
||||
<Form.TextArea
|
||||
label={t('音频倍率')}
|
||||
extraText={t('音频输入相关的倍率设置,键为模型名称,值为倍率')}
|
||||
placeholder={t('为一个 JSON 文本,键为模型名称,值为倍率,例如:{"gpt-4o-audio-preview": 16}')}
|
||||
field={'AudioRatio'}
|
||||
autosize={{ minRows: 6, maxRows: 12 }}
|
||||
trigger='blur'
|
||||
stopValidateWithError
|
||||
rules={[
|
||||
{
|
||||
validator: (rule, value) => verifyJSON(value),
|
||||
message: '不是合法的 JSON 字符串',
|
||||
},
|
||||
]}
|
||||
onChange={(value) =>
|
||||
setInputs({ ...inputs, AudioRatio: value })
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} sm={16}>
|
||||
<Form.TextArea
|
||||
label={t('音频补全倍率')}
|
||||
extraText={t('音频输出补全相关的倍率设置,键为模型名称,值为倍率')}
|
||||
placeholder={t('为一个 JSON 文本,键为模型名称,值为倍率,例如:{"gpt-4o-realtime": 2}')}
|
||||
field={'AudioCompletionRatio'}
|
||||
autosize={{ minRows: 6, maxRows: 12 }}
|
||||
trigger='blur'
|
||||
stopValidateWithError
|
||||
rules={[
|
||||
{
|
||||
validator: (rule, value) => verifyJSON(value),
|
||||
message: '不是合法的 JSON 字符串',
|
||||
},
|
||||
]}
|
||||
onChange={(value) =>
|
||||
setInputs({ ...inputs, AudioCompletionRatio: value })
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={16}>
|
||||
<Col span={16}>
|
||||
<Form.Switch
|
||||
|
||||
Reference in New Issue
Block a user