-
-
Notifications
You must be signed in to change notification settings - Fork 928
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Enhance Operation Settings with Group and Model Ratio Management
- Added new components for GroupRatioSettings and ModelRatioSettings to manage group and model ratios. - Integrated tabs in OperationSetting to switch between model and visual ratio settings. - Updated translations for new settings and improved existing ones in the English locale file. - Refactored ModelSettingsVisualEditor to support dynamic pricing and ratio configurations. This update improves the user interface for managing operational settings, enhancing usability and localization support.
- Loading branch information
1 parent
6ca6865
commit a4c43bb
Showing
5 changed files
with
400 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import React, { useEffect, useState, useRef } from 'react'; | ||
import { Button, Col, Form, Row, Spin } from '@douyinfe/semi-ui'; | ||
import { | ||
compareObjects, | ||
API, | ||
showError, | ||
showSuccess, | ||
showWarning, | ||
verifyJSON, | ||
} from '../../../helpers'; | ||
import { useTranslation } from 'react-i18next'; | ||
|
||
export default function GroupRatioSettings(props) { | ||
const { t } = useTranslation(); | ||
const [loading, setLoading] = useState(false); | ||
const [inputs, setInputs] = useState({ | ||
GroupRatio: '', | ||
UserUsableGroups: '' | ||
}); | ||
const refForm = useRef(); | ||
const [inputsRow, setInputsRow] = useState(inputs); | ||
|
||
async function onSubmit() { | ||
try { | ||
await refForm.current.validate().then(() => { | ||
const updateArray = compareObjects(inputs, inputsRow); | ||
if (!updateArray.length) return showWarning(t('你似乎并没有修改什么')); | ||
|
||
const requestQueue = updateArray.map((item) => { | ||
const value = typeof inputs[item.key] === 'boolean' | ||
? String(inputs[item.key]) | ||
: inputs[item.key]; | ||
return API.put('/api/option/', { key: item.key, value }); | ||
}); | ||
|
||
setLoading(true); | ||
Promise.all(requestQueue) | ||
.then((res) => { | ||
if (res.includes(undefined)) { | ||
return showError(requestQueue.length > 1 ? t('部分保存失败,请重试') : t('保存失败')); | ||
} | ||
|
||
for (let i = 0; i < res.length; i++) { | ||
if (!res[i].data.success) { | ||
return showError(res[i].data.message); | ||
} | ||
} | ||
|
||
showSuccess(t('保存成功')); | ||
props.refresh(); | ||
}) | ||
.catch(error => { | ||
console.error('Unexpected error:', error); | ||
showError(t('保存失败,请重试')); | ||
}) | ||
.finally(() => { | ||
setLoading(false); | ||
}); | ||
}).catch(() => { | ||
showError(t('请检查输入')); | ||
}); | ||
} catch (error) { | ||
showError(t('请检查输入')); | ||
console.error(error); | ||
} | ||
} | ||
|
||
useEffect(() => { | ||
const currentInputs = {}; | ||
for (let key in props.options) { | ||
if (Object.keys(inputs).includes(key)) { | ||
currentInputs[key] = props.options[key]; | ||
} | ||
} | ||
setInputs(currentInputs); | ||
setInputsRow(structuredClone(currentInputs)); | ||
refForm.current.setValues(currentInputs); | ||
}, [props.options]); | ||
|
||
return ( | ||
<Spin spinning={loading}> | ||
<Form | ||
values={inputs} | ||
getFormApi={(formAPI) => (refForm.current = formAPI)} | ||
style={{ marginBottom: 15 }} | ||
> | ||
<Form.Section text={t('分组设置')}> | ||
<Row gutter={16}> | ||
<Col span={16}> | ||
<Form.TextArea | ||
label={t('分组倍率')} | ||
placeholder={t('为一个 JSON 文本,键为分组名称,值为倍率')} | ||
field={'GroupRatio'} | ||
autosize={{ minRows: 6, maxRows: 12 }} | ||
trigger='blur' | ||
stopValidateWithError | ||
rules={[ | ||
{ | ||
validator: (rule, value) => verifyJSON(value), | ||
message: t('不是合法的 JSON 字符串') | ||
} | ||
]} | ||
onChange={(value) => setInputs({ ...inputs, GroupRatio: value })} | ||
/> | ||
</Col> | ||
</Row> | ||
<Row gutter={16}> | ||
<Col span={16}> | ||
<Form.TextArea | ||
label={t('用户可选分组')} | ||
placeholder={t('为一个 JSON 文本,键为分组名称,值为分组描述')} | ||
field={'UserUsableGroups'} | ||
autosize={{ minRows: 6, maxRows: 12 }} | ||
trigger='blur' | ||
stopValidateWithError | ||
rules={[ | ||
{ | ||
validator: (rule, value) => verifyJSON(value), | ||
message: t('不是合法的 JSON 字符串') | ||
} | ||
]} | ||
onChange={(value) => setInputs({ ...inputs, UserUsableGroups: value })} | ||
/> | ||
</Col> | ||
</Row> | ||
</Form.Section> | ||
</Form> | ||
<Button onClick={onSubmit}>{t('保存分组倍率设置')}</Button> | ||
</Spin> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
import React, { useEffect, useState, useRef } from 'react'; | ||
import { Button, Col, Form, Popconfirm, Row, Space, Spin } from '@douyinfe/semi-ui'; | ||
import { | ||
compareObjects, | ||
API, | ||
showError, | ||
showSuccess, | ||
showWarning, | ||
verifyJSON, | ||
} from '../../../helpers'; | ||
import { useTranslation } from 'react-i18next'; | ||
|
||
export default function ModelRatioSettings(props) { | ||
const [loading, setLoading] = useState(false); | ||
const [inputs, setInputs] = useState({ | ||
ModelPrice: '', | ||
ModelRatio: '', | ||
CompletionRatio: '', | ||
}); | ||
const refForm = useRef(); | ||
const [inputsRow, setInputsRow] = useState(inputs); | ||
const { t } = useTranslation(); | ||
|
||
async function onSubmit() { | ||
try { | ||
await refForm.current.validate().then(() => { | ||
const updateArray = compareObjects(inputs, inputsRow); | ||
if (!updateArray.length) return showWarning(t('你似乎并没有修改什么')); | ||
|
||
const requestQueue = updateArray.map((item) => { | ||
const value = typeof inputs[item.key] === 'boolean' | ||
? String(inputs[item.key]) | ||
: inputs[item.key]; | ||
return API.put('/api/option/', { key: item.key, value }); | ||
}); | ||
|
||
setLoading(true); | ||
Promise.all(requestQueue) | ||
.then((res) => { | ||
if (res.includes(undefined)) { | ||
return showError(requestQueue.length > 1 ? t('部分保存失败,请重试') : t('保存失败')); | ||
} | ||
|
||
for (let i = 0; i < res.length; i++) { | ||
if (!res[i].data.success) { | ||
return showError(res[i].data.message); | ||
} | ||
} | ||
|
||
showSuccess(t('保存成功')); | ||
props.refresh(); | ||
}) | ||
.catch(error => { | ||
console.error('Unexpected error:', error); | ||
showError(t('保存失败,请重试')); | ||
}) | ||
.finally(() => { | ||
setLoading(false); | ||
}); | ||
}).catch(() => { | ||
showError(t('请检查输入')); | ||
}); | ||
} catch (error) { | ||
showError(t('请检查输入')); | ||
console.error(error); | ||
} | ||
} | ||
|
||
async function resetModelRatio() { | ||
try { | ||
let res = await API.post(`/api/option/rest_model_ratio`); | ||
if (res.data.success) { | ||
showSuccess(res.data.message); | ||
props.refresh(); | ||
} else { | ||
showError(res.data.message); | ||
} | ||
} catch (error) { | ||
showError(error); | ||
} | ||
} | ||
|
||
useEffect(() => { | ||
const currentInputs = {}; | ||
for (let key in props.options) { | ||
if (Object.keys(inputs).includes(key)) { | ||
currentInputs[key] = props.options[key]; | ||
} | ||
} | ||
setInputs(currentInputs); | ||
setInputsRow(structuredClone(currentInputs)); | ||
refForm.current.setValues(currentInputs); | ||
}, [props.options]); | ||
|
||
return ( | ||
<Spin spinning={loading}> | ||
<Form | ||
values={inputs} | ||
getFormApi={(formAPI) => (refForm.current = formAPI)} | ||
style={{ marginBottom: 15 }} | ||
> | ||
<Form.Section> | ||
<Row gutter={16}> | ||
<Col span={16}> | ||
<Form.TextArea | ||
label={t('模型固定价格')} | ||
extraText={t('一次调用消耗多少刀,优先级大于模型倍率')} | ||
placeholder={t('为一个 JSON 文本,键为模型名称,值为一次调用消耗多少刀,比如 "gpt-4-gizmo-*": 0.1,一次消耗0.1刀')} | ||
field={'ModelPrice'} | ||
autosize={{ minRows: 6, maxRows: 12 }} | ||
trigger='blur' | ||
stopValidateWithError | ||
rules={[ | ||
{ | ||
validator: (rule, value) => verifyJSON(value), | ||
message: '不是合法的 JSON 字符串' | ||
} | ||
]} | ||
onChange={(value) => setInputs({ ...inputs, ModelPrice: value })} | ||
/> | ||
</Col> | ||
</Row> | ||
<Row gutter={16}> | ||
<Col span={16}> | ||
<Form.TextArea | ||
label={t('模型倍率')} | ||
placeholder={t('为一个 JSON 文本,键为模型名称,值为倍率')} | ||
field={'ModelRatio'} | ||
autosize={{ minRows: 6, maxRows: 12 }} | ||
trigger='blur' | ||
stopValidateWithError | ||
rules={[ | ||
{ | ||
validator: (rule, value) => verifyJSON(value), | ||
message: '不是合法的 JSON 字符串' | ||
} | ||
]} | ||
onChange={(value) => setInputs({ ...inputs, ModelRatio: value })} | ||
/> | ||
</Col> | ||
</Row> | ||
<Row gutter={16}> | ||
<Col span={16}> | ||
<Form.TextArea | ||
label={t('模型补全倍率(仅对自定义模型有效)')} | ||
extraText={t('仅对自定义模型有效')} | ||
placeholder={t('为一个 JSON 文本,键为模型名称,值为倍率')} | ||
field={'CompletionRatio'} | ||
autosize={{ minRows: 6, maxRows: 12 }} | ||
trigger='blur' | ||
stopValidateWithError | ||
rules={[ | ||
{ | ||
validator: (rule, value) => verifyJSON(value), | ||
message: '不是合法的 JSON 字符串' | ||
} | ||
]} | ||
onChange={(value) => setInputs({ ...inputs, CompletionRatio: value })} | ||
/> | ||
</Col> | ||
</Row> | ||
</Form.Section> | ||
</Form> | ||
<Space> | ||
<Button onClick={onSubmit}>{t('保存模型倍率设置')}</Button> | ||
<Popconfirm | ||
title={t('确定重置模型倍率吗?')} | ||
content={t('此修改将不可逆')} | ||
okType={'danger'} | ||
position={'top'} | ||
onConfirm={resetModelRatio} | ||
> | ||
<Button type={'danger'}>{t('重置模型倍率')}</Button> | ||
</Popconfirm> | ||
</Space> | ||
</Spin> | ||
); | ||
} |
Oops, something went wrong.