@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
For commercial licensing, please contact support@quantumnous.com
*/
*/
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useRef } from 'react';
import {
import {
Table,
Table,
Button,
Button,
@@ -56,6 +56,7 @@ export default function ModelRatioNotSetEditor(props) {
const [batchRatioValue, setBatchRatioValue] = useState('');
const [batchRatioValue, setBatchRatioValue] = useState('');
const [batchCompletionRatioValue, setBatchCompletionRatioValue] =
const [batchCompletionRatioValue, setBatchCompletionRatioValue] =
useState('');
useState('');
const addFormRef = useRef(null);
const { Text } = Typography;
const { Text } = Typography;
// 定义可选的每页显示条数
// 定义可选的每页显示条数
const pageSizeOptions = [10, 20, 50, 100];
const pageSizeOptions = [10, 20, 50, 100];
@@ -85,6 +86,11 @@ export default function ModelRatioNotSetEditor(props) {
const modelPrice = JSON.parse(props.options.ModelPrice || '{}');
const modelPrice = JSON.parse(props.options.ModelPrice || '{}');
const modelRatio = JSON.parse(props.options.ModelRatio || '{}');
const modelRatio = JSON.parse(props.options.ModelRatio || '{}');
const completionRatio = JSON.parse(props.options.CompletionRatio || '{}');
const completionRatio = JSON.parse(props.options.CompletionRatio || '{}');
const cacheRatio = JSON.parse(props.options.CacheRatio || '{}');
const createCacheRatio = JSON.parse(props.options.CreateCacheRatio || '{}');
const imageRatio = JSON.parse(props.options.ImageRatio || '{}');
const audioRatio = JSON.parse(props.options.AudioRatio || '{}');
const audioCompletionRatio = JSON.parse(props.options.AudioCompletionRatio || '{}');
// 找出所有未设置价格和倍率的模型
// 找出所有未设置价格和倍率的模型
const unsetModels = enabledModels.filter((modelName) => {
const unsetModels = enabledModels.filter((modelName) => {
@@ -101,6 +107,11 @@ export default function ModelRatioNotSetEditor(props) {
price: modelPrice[name] || '',
price: modelPrice[name] || '',
ratio: modelRatio[name] || '',
ratio: modelRatio[name] || '',
completionRatio: completionRatio[name] || '',
completionRatio: completionRatio[name] || '',
cacheRatio: cacheRatio[name] ?? '',
cacheCreationRatio: createCacheRatio[name] ?? '',
imageRatio: imageRatio[name] ?? '',
audioRatio: audioRatio[name] ?? '',
audioCompletionRatio: audioCompletionRatio[name] ?? '',
}));
}));
setModels(modelData);
setModels(modelData);
@@ -142,6 +153,11 @@ export default function ModelRatioNotSetEditor(props) {
ModelPrice: JSON.parse(props.options.ModelPrice || '{}'),
ModelPrice: JSON.parse(props.options.ModelPrice || '{}'),
ModelRatio: JSON.parse(props.options.ModelRatio || '{}'),
ModelRatio: JSON.parse(props.options.ModelRatio || '{}'),
CompletionRatio: JSON.parse(props.options.CompletionRatio || '{}'),
CompletionRatio: JSON.parse(props.options.CompletionRatio || '{}'),
CacheRatio: JSON.parse(props.options.CacheRatio || '{}'),
CreateCacheRatio: JSON.parse(props.options.CreateCacheRatio || '{}'),
ImageRatio: JSON.parse(props.options.ImageRatio || '{}'),
AudioRatio: JSON.parse(props.options.AudioRatio || '{}'),
AudioCompletionRatio: JSON.parse(props.options.AudioCompletionRatio || '{}'),
};
};
try {
try {
@@ -159,6 +175,18 @@ export default function ModelRatioNotSetEditor(props) {
model.completionRatio,
model.completionRatio,
);
);
}
}
// 高级倍率字段(0 是有效值)
if (model.cacheRatio !== '' && model.cacheRatio != null)
output.CacheRatio[model.name] = parseFloat(model.cacheRatio);
if (model.cacheCreationRatio !== '' && model.cacheCreationRatio != null)
output.CreateCacheRatio[model.name] = parseFloat(model.cacheCreationRatio);
if (model.imageRatio !== '' && model.imageRatio != null)
output.ImageRatio[model.name] = parseFloat(model.imageRatio);
if (model.audioRatio !== '' && model.audioRatio != null)
output.AudioRatio[model.name] = parseFloat(model.audioRatio);
if (model.audioCompletionRatio !== '' && model.audioCompletionRatio != null)
output.AudioCompletionRatio[model.name] = parseFloat(model.audioCompletionRatio);
});
});
// 准备API请求数组
// 准备API请求数组
@@ -252,6 +280,75 @@ export default function ModelRatioNotSetEditor(props) {
/>
/>
),
),
},
},
{
title: t('缓存读取倍率'),
dataIndex: 'cacheRatio',
key: 'cacheRatio',
render: (text, record) => (
<Input
value={text}
placeholder={t('全局默认值')}
disabled={record.price !== ''}
onChange={(value) => updateModel(record.name, 'cacheRatio', value)}
/>
),
},
{
title: t('缓存创建倍率(5分钟)'),
dataIndex: 'cacheCreationRatio',
key: 'cacheCreationRatio',
render: (text, record) => (
<Input
value={text}
placeholder={t('全局默认值')}
disabled={record.price !== ''}
onChange={(value) =>
updateModel(record.name, 'cacheCreationRatio', value)
}
/>
),
},
{
title: t('图片倍率'),
dataIndex: 'imageRatio',
key: 'imageRatio',
render: (text, record) => (
<Input
value={text}
placeholder={t('全局默认值')}
disabled={record.price !== ''}
onChange={(value) => updateModel(record.name, 'imageRatio', value)}
/>
),
},
{
title: t('音频输入倍率'),
dataIndex: 'audioRatio',
key: 'audioRatio',
render: (text, record) => (
<Input
value={text}
placeholder={t('全局默认值')}
disabled={record.price !== ''}
onChange={(value) => updateModel(record.name, 'audioRatio', value)}
/>
),
},
{
title: t('音频输出倍率'),
dataIndex: 'audioCompletionRatio',
key: 'audioCompletionRatio',
render: (text, record) => (
<Input
value={text}
placeholder={t('全局默认值')}
disabled={record.price !== ''}
onChange={(value) =>
updateModel(record.name, 'audioCompletionRatio', value)
}
/>
),
},
];
];
const updateModel = (name, field, value) => {
const updateModel = (name, field, value) => {
@@ -272,12 +369,29 @@ export default function ModelRatioNotSetEditor(props) {
showError(t('模型名称已存在'));
showError(t('模型名称已存在'));
return;
return;
}
}
// 从表单读取高级倍率字段
let advancedValues = {};
if (addFormRef.current) {
const formValues = addFormRef.current.getValues();
advancedValues = {
cacheRatio: formValues.cacheRatio != null ? formValues.cacheRatio : '',
cacheCreationRatio: formValues.cacheCreationRatio != null ? formValues.cacheCreationRatio : '',
imageRatio: formValues.imageRatio != null ? formValues.imageRatio : '',
audioRatio: formValues.audioRatio != null ? formValues.audioRatio : '',
audioCompletionRatio: formValues.audioCompletionRatio != null ? formValues.audioCompletionRatio : '',
};
}
setModels((prev) => [
setModels((prev) => [
{
{
name: values.name,
name: values.name,
price: values.price || '',
price: values.price || '',
ratio: values.ratio || '',
ratio: values.ratio || '',
completionRatio: values.completionRatio || '',
completionRatio: values.completionRatio || '',
cacheRatio: advancedValues.cacheRatio ?? '',
cacheCreationRatio: advancedValues.cacheCreationRatio ?? '',
imageRatio: advancedValues.imageRatio ?? '',
audioRatio: advancedValues.audioRatio ?? '',
audioCompletionRatio: advancedValues.audioCompletionRatio ?? '',
},
},
...prev,
...prev,
]);
]);
@@ -457,7 +571,7 @@ export default function ModelRatioNotSetEditor(props) {
currentModel && addModel(currentModel);
currentModel && addModel(currentModel);
}}
}}
>
>
<Form>
<Form getFormApi={(api) => (addFormRef.current = api)} >
<Form.Input
<Form.Input
field='name'
field='name'
label={t('模型名称')}
label={t('模型名称')}
@@ -515,6 +629,43 @@ export default function ModelRatioNotSetEditor(props) {
}))
}))
}
}
/>
/>
<Form.InputNumber
field='cacheRatio'
label={t('缓存读取倍率')}
min={0}
step={0.01}
placeholder={t('全局默认值(1.0)')}
extraText={t('缓存命中时输入价格的倍率。0.5 = 缓存命中的 token 按输入价格的一半计费,留空使用全局默认值 1.0')}
/>
<Form.InputNumber
field='cacheCreationRatio'
label={t('缓存创建倍率(5分钟)')}
min={0}
step={0.01}
placeholder={t('全局默认值(1.25)')}
extraText={t('写入缓存的 token 按此倍率 × 输入价格计费。默认 1.25(5分钟 TTL);超过 1 小时自动按 1.6x 计费,留空使用全局默认值')}
/>
<Form.InputNumber
field='imageRatio'
label={t('图片倍率')}
min={0}
step={0.01}
placeholder={t('全局默认值')}
/>
<Form.InputNumber
field='audioRatio'
label={t('音频输入倍率')}
min={0}
step={0.01}
placeholder={t('全局默认值')}
/>
<Form.InputNumber
field='audioCompletionRatio'
label={t('音频输出倍率')}
min={0}
step={0.01}
placeholder={t('全局默认值')}
/>
</>
</>
)}
)}
</Form>
</Form>