style(web): format code

This commit is contained in:
QuentinHsu
2025-04-04 12:00:38 +08:00
parent ad7a64e585
commit 775b1c458b
74 changed files with 6413 additions and 3548 deletions

View File

@@ -1,7 +1,24 @@
// ModelSettingsVisualEditor.js
import React, { useContext, useEffect, useState, useRef } from 'react';
import { Table, Button, Input, Modal, Form, Space, RadioGroup, Radio, Tabs, TabPane } from '@douyinfe/semi-ui';
import { IconDelete, IconPlus, IconSearch, IconSave, IconEdit } from '@douyinfe/semi-icons';
import {
Table,
Button,
Input,
Modal,
Form,
Space,
RadioGroup,
Radio,
Tabs,
TabPane,
} from '@douyinfe/semi-ui';
import {
IconDelete,
IconPlus,
IconSearch,
IconSave,
IconEdit,
} from '@douyinfe/semi-icons';
import { showError, showSuccess } from '../../../helpers';
import { API } from '../../../helpers';
import { useTranslation } from 'react-i18next';
@@ -20,7 +37,7 @@ export default function ModelSettingsVisualEditor(props) {
const [pricingSubMode, setPricingSubMode] = useState('ratio'); // 'ratio' or 'token-price'
const formRef = useRef(null);
const pageSize = 10;
const quotaPerUnit = getQuotaPerUnit()
const quotaPerUnit = getQuotaPerUnit();
useEffect(() => {
try {
@@ -32,14 +49,15 @@ export default function ModelSettingsVisualEditor(props) {
const modelNames = new Set([
...Object.keys(modelPrice),
...Object.keys(modelRatio),
...Object.keys(completionRatio)
...Object.keys(completionRatio),
]);
const modelData = Array.from(modelNames).map(name => ({
const modelData = Array.from(modelNames).map((name) => ({
name,
price: modelPrice[name] === undefined ? '' : modelPrice[name],
ratio: modelRatio[name] === undefined ? '' : modelRatio[name],
completionRatio: completionRatio[name] === undefined ? '' : completionRatio[name]
completionRatio:
completionRatio[name] === undefined ? '' : completionRatio[name],
}));
setModels(modelData);
@@ -56,8 +74,10 @@ export default function ModelSettingsVisualEditor(props) {
};
// 在 return 语句之前,先处理过滤和分页逻辑
const filteredModels = models.filter(model =>
searchText ? model.name.toLowerCase().includes(searchText.toLowerCase()) : true
const filteredModels = models.filter((model) =>
searchText
? model.name.toLowerCase().includes(searchText.toLowerCase())
: true,
);
// 然后基于过滤后的数据计算分页数据
@@ -68,20 +88,24 @@ export default function ModelSettingsVisualEditor(props) {
const output = {
ModelPrice: {},
ModelRatio: {},
CompletionRatio: {}
CompletionRatio: {},
};
let currentConvertModelName = '';
try {
// 数据转换
models.forEach(model => {
models.forEach((model) => {
currentConvertModelName = model.name;
if (model.price !== '') {
// 如果价格不为空,则转换为浮点数,忽略倍率参数
output.ModelPrice[model.name] = parseFloat(model.price)
output.ModelPrice[model.name] = parseFloat(model.price);
} else {
if (model.ratio !== '') output.ModelRatio[model.name] = parseFloat(model.ratio);
if (model.completionRatio !== '') output.CompletionRatio[model.name] = parseFloat(model.completionRatio);
if (model.ratio !== '')
output.ModelRatio[model.name] = parseFloat(model.ratio);
if (model.completionRatio !== '')
output.CompletionRatio[model.name] = parseFloat(
model.completionRatio,
);
}
});
@@ -89,13 +113,13 @@ export default function ModelSettingsVisualEditor(props) {
const finalOutput = {
ModelPrice: JSON.stringify(output.ModelPrice, null, 2),
ModelRatio: JSON.stringify(output.ModelRatio, null, 2),
CompletionRatio: JSON.stringify(output.CompletionRatio, null, 2)
CompletionRatio: JSON.stringify(output.CompletionRatio, null, 2),
};
const requestQueue = Object.entries(finalOutput).map(([key, value]) => {
return API.put('/api/option/', {
key,
value
value,
});
});
@@ -120,7 +144,6 @@ export default function ModelSettingsVisualEditor(props) {
showSuccess('保存成功');
props.refresh();
} catch (error) {
console.error('保存失败:', error);
showError('保存失败,请重试');
@@ -143,9 +166,9 @@ export default function ModelSettingsVisualEditor(props) {
<Input
value={text}
placeholder={t('按量计费')}
onChange={value => updateModel(record.name, 'price', value)}
onChange={(value) => updateModel(record.name, 'price', value)}
/>
)
),
},
{
title: t('模型倍率'),
@@ -156,9 +179,9 @@ export default function ModelSettingsVisualEditor(props) {
value={text}
placeholder={record.price !== '' ? t('模型倍率') : t('默认补全倍率')}
disabled={record.price !== ''}
onChange={value => updateModel(record.name, 'ratio', value)}
onChange={(value) => updateModel(record.name, 'ratio', value)}
/>
)
),
},
{
title: t('补全倍率'),
@@ -169,9 +192,11 @@ export default function ModelSettingsVisualEditor(props) {
value={text}
placeholder={record.price !== '' ? t('补全倍率') : t('默认补全倍率')}
disabled={record.price !== ''}
onChange={value => updateModel(record.name, 'completionRatio', value)}
onChange={(value) =>
updateModel(record.name, 'completionRatio', value)
}
/>
)
),
},
{
title: t('操作'),
@@ -179,19 +204,18 @@ export default function ModelSettingsVisualEditor(props) {
render: (_, record) => (
<Space>
<Button
type="primary"
type='primary'
icon={<IconEdit />}
onClick={() => editModel(record)}
>
</Button>
></Button>
<Button
icon={<IconDelete />}
type="danger"
type='danger'
onClick={() => deleteModel(record.name)}
/>
</Space>
)
}
),
},
];
const updateModel = (name, field, value) => {
@@ -199,103 +223,114 @@ export default function ModelSettingsVisualEditor(props) {
showError('请输入数字');
return;
}
setModels(prev =>
prev.map(model =>
model.name === name
? { ...model, [field]: value }
: model
)
setModels((prev) =>
prev.map((model) =>
model.name === name ? { ...model, [field]: value } : model,
),
);
};
const deleteModel = (name) => {
setModels(prev => prev.filter(model => model.name !== name));
setModels((prev) => prev.filter((model) => model.name !== name));
};
const calculateRatioFromTokenPrice = (tokenPrice) => {
return tokenPrice / 2;
};
const calculateCompletionRatioFromPrices = (modelTokenPrice, completionTokenPrice) => {
const calculateCompletionRatioFromPrices = (
modelTokenPrice,
completionTokenPrice,
) => {
if (!modelTokenPrice || modelTokenPrice === '0') {
showError('模型价格不能为0');
return '';
}
return completionTokenPrice / modelTokenPrice;
};
const handleTokenPriceChange = (value) => {
const handleTokenPriceChange = (value) => {
// Use a temporary variable to hold the new state
let newState = {
...(currentModel || {}),
tokenPrice: value,
ratio: 0
ratio: 0,
};
if (!isNaN(value) && value !== '') {
const tokenPrice = parseFloat(value);
const ratio = calculateRatioFromTokenPrice(tokenPrice);
newState.ratio = ratio;
}
// Set the state with the complete updated object
setCurrentModel(newState);
};
const handleCompletionTokenPriceChange = (value) => {
const handleCompletionTokenPriceChange = (value) => {
// Use a temporary variable to hold the new state
let newState = {
...(currentModel || {}),
completionTokenPrice: value,
completionRatio: 0
completionRatio: 0,
};
if (!isNaN(value) && value !== '' && currentModel?.tokenPrice) {
const completionTokenPrice = parseFloat(value);
const modelTokenPrice = parseFloat(currentModel.tokenPrice);
if (modelTokenPrice > 0) {
const completionRatio = calculateCompletionRatioFromPrices(modelTokenPrice, completionTokenPrice);
const completionRatio = calculateCompletionRatioFromPrices(
modelTokenPrice,
completionTokenPrice,
);
newState.completionRatio = completionRatio;
}
}
// Set the state with the complete updated object
setCurrentModel(newState);
};
const addOrUpdateModel = (values) => {
// Check if we're editing an existing model or adding a new one
const existingModelIndex = models.findIndex(model => model.name === values.name);
const existingModelIndex = models.findIndex(
(model) => model.name === values.name,
);
if (existingModelIndex >= 0) {
// Update existing model
setModels(prev => prev.map((model, index) =>
index === existingModelIndex ? {
name: values.name,
price: values.price || '',
ratio: values.ratio || '',
completionRatio: values.completionRatio || ''
} : model
));
setModels((prev) =>
prev.map((model, index) =>
index === existingModelIndex
? {
name: values.name,
price: values.price || '',
ratio: values.ratio || '',
completionRatio: values.completionRatio || '',
}
: model,
),
);
setVisible(false);
showSuccess(t('更新成功'));
} else {
// Add new model
// Check if model name already exists
if (models.some(model => model.name === values.name)) {
if (models.some((model) => model.name === values.name)) {
showError(t('模型名称已存在'));
return;
}
setModels(prev => [{
name: values.name,
price: values.price || '',
ratio: values.ratio || '',
completionRatio: values.completionRatio || ''
}, ...prev]);
setModels((prev) => [
{
name: values.name,
price: values.price || '',
ratio: values.ratio || '',
completionRatio: values.completionRatio || '',
},
...prev,
]);
setVisible(false);
showSuccess(t('添加成功'));
}
@@ -304,7 +339,7 @@ export default function ModelSettingsVisualEditor(props) {
const calculateTokenPriceFromRatio = (ratio) => {
return ratio * 2;
};
const resetModalState = () => {
setCurrentModel(null);
setPricingMode('per-token');
@@ -312,40 +347,43 @@ export default function ModelSettingsVisualEditor(props) {
};
const editModel = (record) => {
// Determine which pricing mode to use based on the model's current configuration
let initialPricingMode = 'per-token';
let initialPricingSubMode = 'ratio';
if (record.price !== '') {
initialPricingMode = 'per-request';
} else {
initialPricingMode = 'per-token';
// We default to ratio mode, but could set to token-price if needed
}
// Set the pricing modes for the form
setPricingMode(initialPricingMode);
setPricingSubMode(initialPricingSubMode);
// Create a copy of the model data to avoid modifying the original
const modelCopy = { ...record };
// If the model has ratio data and we want to populate token price fields
if (record.ratio) {
modelCopy.tokenPrice = calculateTokenPriceFromRatio(parseFloat(record.ratio)).toString();
modelCopy.tokenPrice = calculateTokenPriceFromRatio(
parseFloat(record.ratio),
).toString();
if (record.completionRatio) {
modelCopy.completionTokenPrice = (parseFloat(modelCopy.tokenPrice) * parseFloat(record.completionRatio)).toString();
modelCopy.completionTokenPrice = (
parseFloat(modelCopy.tokenPrice) * parseFloat(record.completionRatio)
).toString();
}
}
// Set the current model
setCurrentModel(modelCopy);
// Open the modal
setVisible(true);
// Use setTimeout to ensure the form is rendered before setting values
setTimeout(() => {
if (formRef.current) {
@@ -353,7 +391,7 @@ export default function ModelSettingsVisualEditor(props) {
const formValues = {
name: modelCopy.name,
};
if (initialPricingMode === 'per-request') {
formValues.priceInput = modelCopy.price;
} else if (initialPricingMode === 'per-token') {
@@ -362,7 +400,7 @@ export default function ModelSettingsVisualEditor(props) {
formValues.modelTokenPrice = modelCopy.tokenPrice;
formValues.completionTokenPrice = modelCopy.completionTokenPrice;
}
formRef.current.setValues(formValues);
}
}, 0);
@@ -370,23 +408,26 @@ export default function ModelSettingsVisualEditor(props) {
return (
<>
<Space vertical align="start" style={{ width: '100%' }}>
<Space vertical align='start' style={{ width: '100%' }}>
<Space>
<Button icon={<IconPlus />} onClick={() => {
resetModalState();
setVisible(true);
}}>
<Button
icon={<IconPlus />}
onClick={() => {
resetModalState();
setVisible(true);
}}
>
{t('添加模型')}
</Button>
<Button type="primary" icon={<IconSave />} onClick={SubmitData}>
<Button type='primary' icon={<IconSave />} onClick={SubmitData}>
{t('应用更改')}
</Button>
<Input
prefix={<IconSearch />}
placeholder={t('搜索模型名称')}
value={searchText}
onChange={value => {
setSearchText(value)
onChange={(value) => {
setSearchText(value);
setCurrentPage(1);
}}
style={{ width: 200 }}
@@ -399,21 +440,27 @@ export default function ModelSettingsVisualEditor(props) {
currentPage: currentPage,
pageSize: pageSize,
total: filteredModels.length,
onPageChange: page => setCurrentPage(page),
onPageChange: (page) => setCurrentPage(page),
formatPageText: (page) =>
t('第 {{start}} - {{end}} 条,共 {{total}} 条', {
start: page.currentStart,
end: page.currentEnd,
total: filteredModels.length
total: filteredModels.length,
}),
showTotal: true,
showSizeChanger: false
showSizeChanger: false,
}}
/>
</Space>
<Modal
title={currentModel && currentModel.name && models.some(model => model.name === currentModel.name) ? t('编辑模型') : t('添加模型')}
title={
currentModel &&
currentModel.name &&
models.some((model) => model.name === currentModel.name)
? t('编辑模型')
: t('添加模型')
}
visible={visible}
onCancel={() => {
resetModalState();
@@ -423,22 +470,33 @@ export default function ModelSettingsVisualEditor(props) {
if (currentModel) {
// If we're in token price mode, make sure ratio values are properly set
const valuesToSave = { ...currentModel };
if (pricingMode === 'per-token' && pricingSubMode === 'token-price' && currentModel.tokenPrice) {
if (
pricingMode === 'per-token' &&
pricingSubMode === 'token-price' &&
currentModel.tokenPrice
) {
// Calculate and set ratio from token price
const tokenPrice = parseFloat(currentModel.tokenPrice);
valuesToSave.ratio = (tokenPrice / 2).toString();
// Calculate and set completion ratio if both token prices are available
if (currentModel.completionTokenPrice && currentModel.tokenPrice) {
const completionPrice = parseFloat(currentModel.completionTokenPrice);
if (
currentModel.completionTokenPrice &&
currentModel.tokenPrice
) {
const completionPrice = parseFloat(
currentModel.completionTokenPrice,
);
const modelPrice = parseFloat(currentModel.tokenPrice);
if (modelPrice > 0) {
valuesToSave.completionRatio = (completionPrice / modelPrice).toString();
valuesToSave.completionRatio = (
completionPrice / modelPrice
).toString();
}
}
}
// Clear price if we're in per-token mode
if (pricingMode === 'per-token') {
valuesToSave.price = '';
@@ -447,139 +505,175 @@ export default function ModelSettingsVisualEditor(props) {
valuesToSave.ratio = '';
valuesToSave.completionRatio = '';
}
addOrUpdateModel(valuesToSave);
}
}}
>
<Form getFormApi={api => formRef.current = api}>
<Form getFormApi={(api) => (formRef.current = api)}>
<Form.Input
field="name"
field='name'
label={t('模型名称')}
placeholder="strawberry"
placeholder='strawberry'
required
disabled={currentModel && currentModel.name && models.some(model => model.name === currentModel.name)}
onChange={value => setCurrentModel(prev => ({ ...prev, name: value }))}
disabled={
currentModel &&
currentModel.name &&
models.some((model) => model.name === currentModel.name)
}
onChange={(value) =>
setCurrentModel((prev) => ({ ...prev, name: value }))
}
/>
<Form.Section text={t('定价模式')}>
<div style={{ marginBottom: '16px' }}>
<RadioGroup type="button" value={pricingMode} onChange={(e) => {
const newMode = e.target.value;
const oldMode = pricingMode;
setPricingMode(newMode);
// Instead of resetting all values, convert between modes
if (currentModel) {
const updatedModel = { ...currentModel };
// Update formRef with converted values
if (formRef.current) {
const formValues = {
name: updatedModel.name
};
if (newMode === 'per-request') {
formValues.priceInput = updatedModel.price || '';
} else if (newMode === 'per-token') {
formValues.ratioInput = updatedModel.ratio || '';
formValues.completionRatioInput = updatedModel.completionRatio || '';
formValues.modelTokenPrice = updatedModel.tokenPrice || '';
formValues.completionTokenPrice = updatedModel.completionTokenPrice || '';
<RadioGroup
type='button'
value={pricingMode}
onChange={(e) => {
const newMode = e.target.value;
const oldMode = pricingMode;
setPricingMode(newMode);
// Instead of resetting all values, convert between modes
if (currentModel) {
const updatedModel = { ...currentModel };
// Update formRef with converted values
if (formRef.current) {
const formValues = {
name: updatedModel.name,
};
if (newMode === 'per-request') {
formValues.priceInput = updatedModel.price || '';
} else if (newMode === 'per-token') {
formValues.ratioInput = updatedModel.ratio || '';
formValues.completionRatioInput =
updatedModel.completionRatio || '';
formValues.modelTokenPrice =
updatedModel.tokenPrice || '';
formValues.completionTokenPrice =
updatedModel.completionTokenPrice || '';
}
formRef.current.setValues(formValues);
}
formRef.current.setValues(formValues);
// Update the model state
setCurrentModel(updatedModel);
}
// Update the model state
setCurrentModel(updatedModel);
}
}}>
<Radio value="per-token">{t('按量计费')}</Radio>
<Radio value="per-request">{t('按次计费')}</Radio>
}}
>
<Radio value='per-token'>{t('按量计费')}</Radio>
<Radio value='per-request'>{t('按次计费')}</Radio>
</RadioGroup>
</div>
</Form.Section>
{pricingMode === 'per-token' && (
<>
<Form.Section text={t('价格设置方式')}>
<div style={{ marginBottom: '16px' }}>
<RadioGroup type="button" value={pricingSubMode} onChange={(e) => {
const newSubMode = e.target.value;
const oldSubMode = pricingSubMode;
setPricingSubMode(newSubMode);
// Handle conversion between submodes
if (currentModel) {
const updatedModel = { ...currentModel };
// Convert between ratio and token price
if (oldSubMode === 'ratio' && newSubMode === 'token-price') {
if (updatedModel.ratio) {
updatedModel.tokenPrice = calculateTokenPriceFromRatio(parseFloat(updatedModel.ratio)).toString();
if (updatedModel.completionRatio) {
updatedModel.completionTokenPrice = (parseFloat(updatedModel.tokenPrice) * parseFloat(updatedModel.completionRatio)).toString();
<RadioGroup
type='button'
value={pricingSubMode}
onChange={(e) => {
const newSubMode = e.target.value;
const oldSubMode = pricingSubMode;
setPricingSubMode(newSubMode);
// Handle conversion between submodes
if (currentModel) {
const updatedModel = { ...currentModel };
// Convert between ratio and token price
if (
oldSubMode === 'ratio' &&
newSubMode === 'token-price'
) {
if (updatedModel.ratio) {
updatedModel.tokenPrice =
calculateTokenPriceFromRatio(
parseFloat(updatedModel.ratio),
).toString();
if (updatedModel.completionRatio) {
updatedModel.completionTokenPrice = (
parseFloat(updatedModel.tokenPrice) *
parseFloat(updatedModel.completionRatio)
).toString();
}
}
} else if (
oldSubMode === 'token-price' &&
newSubMode === 'ratio'
) {
// Ratio values should already be calculated by the handlers
}
} else if (oldSubMode === 'token-price' && newSubMode === 'ratio') {
// Ratio values should already be calculated by the handlers
}
// Update the form values
if (formRef.current) {
const formValues = {};
if (newSubMode === 'ratio') {
formValues.ratioInput = updatedModel.ratio || '';
formValues.completionRatioInput = updatedModel.completionRatio || '';
} else if (newSubMode === 'token-price') {
formValues.modelTokenPrice = updatedModel.tokenPrice || '';
formValues.completionTokenPrice = updatedModel.completionTokenPrice || '';
// Update the form values
if (formRef.current) {
const formValues = {};
if (newSubMode === 'ratio') {
formValues.ratioInput = updatedModel.ratio || '';
formValues.completionRatioInput =
updatedModel.completionRatio || '';
} else if (newSubMode === 'token-price') {
formValues.modelTokenPrice =
updatedModel.tokenPrice || '';
formValues.completionTokenPrice =
updatedModel.completionTokenPrice || '';
}
formRef.current.setValues(formValues);
}
formRef.current.setValues(formValues);
setCurrentModel(updatedModel);
}
setCurrentModel(updatedModel);
}
}}>
<Radio value="ratio">{t('按倍率设置')}</Radio>
<Radio value="token-price">{t('按价格设置')}</Radio>
}}
>
<Radio value='ratio'>{t('按倍率设置')}</Radio>
<Radio value='token-price'>{t('按价格设置')}</Radio>
</RadioGroup>
</div>
</Form.Section>
{pricingSubMode === 'ratio' && (
<>
<Form.Input
field="ratioInput"
field='ratioInput'
label={t('模型倍率')}
placeholder={t('输入模型倍率')}
onChange={value => setCurrentModel(prev => ({
...prev || {},
ratio: value
}))}
onChange={(value) =>
setCurrentModel((prev) => ({
...(prev || {}),
ratio: value,
}))
}
initValue={currentModel?.ratio || ''}
/>
<Form.Input
field="completionRatioInput"
field='completionRatioInput'
label={t('补全倍率')}
placeholder={t('输入补全倍率')}
onChange={value => setCurrentModel(prev => ({
...prev || {},
completionRatio: value
}))}
onChange={(value) =>
setCurrentModel((prev) => ({
...(prev || {}),
completionRatio: value,
}))
}
initValue={currentModel?.completionRatio || ''}
/>
</>
)}
{pricingSubMode === 'token-price' && (
<>
<Form.Input
field="modelTokenPrice"
field='modelTokenPrice'
label={t('输入价格')}
onChange={(value) => {
handleTokenPriceChange(value);
@@ -588,7 +682,7 @@ export default function ModelSettingsVisualEditor(props) {
suffix={t('$/1M tokens')}
/>
<Form.Input
field="completionTokenPrice"
field='completionTokenPrice'
label={t('输出价格')}
onChange={(value) => {
handleCompletionTokenPriceChange(value);
@@ -600,16 +694,18 @@ export default function ModelSettingsVisualEditor(props) {
)}
</>
)}
{pricingMode === 'per-request' && (
<Form.Input
field="priceInput"
field='priceInput'
label={t('固定价格(每次)')}
placeholder={t('输入每次价格')}
onChange={value => setCurrentModel(prev => ({
...prev || {},
price: value
}))}
onChange={(value) =>
setCurrentModel((prev) => ({
...(prev || {}),
price: value,
}))
}
initValue={currentModel?.price || ''}
/>
)}