first-update
This commit is contained in:
153
easy-dataset-main/components/settings/BasicSettings.js
Normal file
153
easy-dataset-main/components/settings/BasicSettings.js
Normal file
@@ -0,0 +1,153 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Typography, Box, Button, TextField, Grid, Card, CardContent, Alert, Snackbar } from '@mui/material';
|
||||
import SaveIcon from '@mui/icons-material/Save';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function BasicSettings({ projectId }) {
|
||||
const { t } = useTranslation();
|
||||
const [projectInfo, setProjectInfo] = useState({
|
||||
id: '',
|
||||
name: '',
|
||||
description: ''
|
||||
});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [success, setSuccess] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchProjectInfo() {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await fetch(`/api/projects/${projectId}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(t('projects.fetchFailed'));
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
setProjectInfo(data);
|
||||
} catch (error) {
|
||||
console.error('获取项目信息出错:', error);
|
||||
setError(error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
fetchProjectInfo();
|
||||
}, [projectId, t]);
|
||||
|
||||
// 处理项目信息变更
|
||||
const handleProjectInfoChange = e => {
|
||||
const { name, value } = e.target;
|
||||
setProjectInfo(prev => ({
|
||||
...prev,
|
||||
[name]: value
|
||||
}));
|
||||
};
|
||||
|
||||
// 保存项目信息
|
||||
const handleSaveProjectInfo = async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/projects/${projectId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: projectInfo.name,
|
||||
description: projectInfo.description
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(t('projects.saveFailed'));
|
||||
}
|
||||
|
||||
setSuccess(true);
|
||||
} catch (error) {
|
||||
console.error('保存项目信息出错:', error);
|
||||
setError(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCloseSnackbar = () => {
|
||||
setSuccess(false);
|
||||
setError(null);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <Typography>{t('common.loading')}</Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
{t('settings.basicInfo')}
|
||||
</Typography>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('projects.id')}
|
||||
value={projectInfo.id}
|
||||
disabled
|
||||
helperText={t('settings.idNotEditable')}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('projects.name')}
|
||||
name="name"
|
||||
value={projectInfo.name}
|
||||
onChange={handleProjectInfoChange}
|
||||
required
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('projects.description')}
|
||||
name="description"
|
||||
value={projectInfo.description}
|
||||
onChange={handleProjectInfoChange}
|
||||
multiline
|
||||
rows={3}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Button variant="contained" startIcon={<SaveIcon />} onClick={handleSaveProjectInfo}>
|
||||
{t('settings.saveBasicInfo')}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
|
||||
<Snackbar
|
||||
open={success}
|
||||
autoHideDuration={2000}
|
||||
onClose={handleCloseSnackbar}
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
|
||||
>
|
||||
<Alert onClose={handleCloseSnackbar} severity="success" sx={{ width: '100%' }}>
|
||||
{t('settings.saveSuccess')}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
|
||||
<Snackbar
|
||||
open={!!error}
|
||||
autoHideDuration={2000}
|
||||
onClose={handleCloseSnackbar}
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
|
||||
>
|
||||
<Alert onClose={handleCloseSnackbar} severity="error" sx={{ width: '100%' }}>
|
||||
{error}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
1056
easy-dataset-main/components/settings/ModelSettings.js
Normal file
1056
easy-dataset-main/components/settings/ModelSettings.js
Normal file
File diff suppressed because it is too large
Load Diff
709
easy-dataset-main/components/settings/TaskSettings.js
Normal file
709
easy-dataset-main/components/settings/TaskSettings.js
Normal file
@@ -0,0 +1,709 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import {
|
||||
Typography,
|
||||
Box,
|
||||
Button,
|
||||
TextField,
|
||||
Grid,
|
||||
Card,
|
||||
CardContent,
|
||||
Slider,
|
||||
InputAdornment,
|
||||
Alert,
|
||||
Snackbar,
|
||||
FormControl,
|
||||
Select,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Chip,
|
||||
FormHelperText
|
||||
} from '@mui/material';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import SaveIcon from '@mui/icons-material/Save';
|
||||
import useTaskSettings from '@/hooks/useTaskSettings';
|
||||
|
||||
export default function TaskSettings({ projectId }) {
|
||||
const { t } = useTranslation();
|
||||
const { taskSettings, setTaskSettings, loading, error, success, setSuccess } = useTaskSettings(projectId);
|
||||
|
||||
// 确保 multiTurnRounds 有正确的初始值
|
||||
useEffect(() => {
|
||||
if (
|
||||
!loading &&
|
||||
taskSettings &&
|
||||
(taskSettings.multiTurnRounds === undefined || taskSettings.multiTurnRounds === null)
|
||||
) {
|
||||
setTaskSettings(prev => ({
|
||||
...prev,
|
||||
multiTurnRounds: 3 // 默认值
|
||||
}));
|
||||
}
|
||||
}, [loading, taskSettings, setTaskSettings]);
|
||||
|
||||
// 处理设置变更
|
||||
const handleSettingChange = e => {
|
||||
const { name, value } = e.target;
|
||||
setTaskSettings(prev => ({
|
||||
...prev,
|
||||
[name]: value
|
||||
}));
|
||||
};
|
||||
|
||||
// 处理滑块变更
|
||||
const handleSliderChange = name => (event, newValue) => {
|
||||
setTaskSettings(prev => ({
|
||||
...prev,
|
||||
[name]: newValue
|
||||
}));
|
||||
};
|
||||
|
||||
// 保存任务配置
|
||||
const handleSaveTaskSettings = async () => {
|
||||
try {
|
||||
// 确保数组类型的数据被正确处理
|
||||
const settingsToSave = { ...taskSettings };
|
||||
|
||||
// 确保递归分块的分隔符数组存在
|
||||
if (settingsToSave.splitType === 'recursive' && settingsToSave.separatorsInput) {
|
||||
if (!settingsToSave.separators || !Array.isArray(settingsToSave.separators)) {
|
||||
settingsToSave.separators = settingsToSave.separatorsInput.split(',').map(item => item.trim());
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Saving settings:', settingsToSave);
|
||||
|
||||
const response = await fetch(`/api/projects/${projectId}/tasks`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(settingsToSave)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(t('settings.saveTasksFailed'));
|
||||
}
|
||||
|
||||
setSuccess(true);
|
||||
} catch (error) {
|
||||
console.error('保存任务配置出错:', error);
|
||||
//setError(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCloseSnackbar = () => {
|
||||
setSuccess(false);
|
||||
//setError(null);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <Typography>{t('common.loading')}</Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box sx={{ position: 'relative', pb: 8 }}>
|
||||
{' '}
|
||||
{/* 添加底部填充,为固定按钮留出空间 */}
|
||||
<Card style={{ marginBottom: 20 }}>
|
||||
<CardContent>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
{t('settings.textSplitSettings')}
|
||||
</Typography>
|
||||
<Box sx={{ px: 2, py: 1 }}>
|
||||
{/* 分块策略选择 */}
|
||||
<FormControl fullWidth sx={{ mb: 3 }}>
|
||||
<InputLabel id="split-type-label">{t('settings.splitType')}</InputLabel>
|
||||
<Select
|
||||
labelId="split-type-label"
|
||||
value={taskSettings.splitType || 'recursive'}
|
||||
label={t('settings.splitType')}
|
||||
name="splitType"
|
||||
onChange={handleSettingChange}
|
||||
>
|
||||
<MenuItem value="markdown">
|
||||
<Box>
|
||||
<Typography variant="subtitle2">{t('settings.splitTypeMarkdown')}</Typography>
|
||||
<Typography variant="caption" sx={{ display: 'block', color: 'text.secondary' }}>
|
||||
{t('settings.splitTypeMarkdownDesc')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem value="recursive">
|
||||
<Box>
|
||||
<Typography variant="subtitle2">{t('settings.splitTypeRecursive')}</Typography>
|
||||
<Typography variant="caption" sx={{ display: 'block', color: 'text.secondary' }}>
|
||||
{t('settings.splitTypeRecursiveDesc')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem value="text">
|
||||
<Box>
|
||||
<Typography variant="subtitle2">{t('settings.splitTypeText')}</Typography>
|
||||
<Typography variant="caption" sx={{ display: 'block', color: 'text.secondary' }}>
|
||||
{t('settings.splitTypeTextDesc')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem value="token">
|
||||
<Box>
|
||||
<Typography variant="subtitle2">{t('settings.splitTypeToken')}</Typography>
|
||||
<Typography variant="caption" sx={{ display: 'block', color: 'text.secondary' }}>
|
||||
{t('settings.splitTypeTokenDesc')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem value="code">
|
||||
<Box>
|
||||
<Typography variant="subtitle2">{t('settings.splitTypeCode')}</Typography>
|
||||
<Typography variant="caption" sx={{ display: 'block', color: 'text.secondary' }}>
|
||||
{t('settings.splitTypeCodeDesc')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
{/* 添加自定义符号分割策略选项 */}
|
||||
<MenuItem value="custom">
|
||||
<Box>
|
||||
<Typography variant="subtitle2">{t('settings.splitTypeCustom')}</Typography>
|
||||
<Typography variant="caption" sx={{ display: 'block', color: 'text.secondary' }}>
|
||||
{t('settings.splitTypeCustomDesc')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
{/* Markdown模式设置 */}
|
||||
{(!taskSettings.splitType || taskSettings.splitType === 'markdown') && (
|
||||
<>
|
||||
<Typography id="text-split-min-length-slider" gutterBottom>
|
||||
{t('settings.minLength')}: {taskSettings.textSplitMinLength}
|
||||
</Typography>
|
||||
<Slider
|
||||
value={taskSettings.textSplitMinLength || 2000}
|
||||
onChange={handleSliderChange('textSplitMinLength')}
|
||||
aria-labelledby="text-split-min-length-slider"
|
||||
valueLabelDisplay="auto"
|
||||
step={100}
|
||||
marks
|
||||
min={100}
|
||||
max={5000}
|
||||
/>
|
||||
|
||||
<Typography id="text-split-max-length-slider" gutterBottom sx={{ mt: 3 }}>
|
||||
{t('settings.maxLength')}: {taskSettings.textSplitMaxLength}
|
||||
</Typography>
|
||||
<Slider
|
||||
value={taskSettings.textSplitMaxLength || 3000}
|
||||
onChange={handleSliderChange('textSplitMaxLength')}
|
||||
aria-labelledby="text-split-max-length-slider"
|
||||
valueLabelDisplay="auto"
|
||||
step={100}
|
||||
marks
|
||||
min={2000}
|
||||
max={20000}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* 通用 LangChain 参数设置 */}
|
||||
{taskSettings.splitType && taskSettings.splitType !== 'markdown' && (
|
||||
<>
|
||||
<Typography id="chunk-size-slider" gutterBottom>
|
||||
{t('settings.chunkSize')}: {taskSettings.chunkSize || 3000}
|
||||
</Typography>
|
||||
<Slider
|
||||
value={taskSettings.chunkSize || 3000}
|
||||
onChange={handleSliderChange('chunkSize')}
|
||||
aria-labelledby="chunk-size-slider"
|
||||
valueLabelDisplay="auto"
|
||||
step={100}
|
||||
marks
|
||||
min={500}
|
||||
max={20000}
|
||||
/>
|
||||
|
||||
<Typography id="chunk-overlap-slider" gutterBottom sx={{ mt: 3 }}>
|
||||
{t('settings.chunkOverlap')}: {taskSettings.chunkOverlap || 200}
|
||||
</Typography>
|
||||
<Slider
|
||||
value={taskSettings.chunkOverlap || 200}
|
||||
onChange={handleSliderChange('chunkOverlap')}
|
||||
aria-labelledby="chunk-overlap-slider"
|
||||
valueLabelDisplay="auto"
|
||||
step={50}
|
||||
marks
|
||||
min={0}
|
||||
max={1000}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Text 分块器特殊设置 */}
|
||||
{taskSettings.splitType === 'text' && (
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.separator')}
|
||||
name="separator"
|
||||
value={taskSettings.separator || '\\n\\n'}
|
||||
onChange={handleSettingChange}
|
||||
helperText={t('settings.separatorHelper')}
|
||||
sx={{ mt: 3 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 自定义符号分块器特殊设置 */}
|
||||
{taskSettings.splitType === 'custom' && (
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.customSeparator')}
|
||||
name="customSeparator"
|
||||
value={taskSettings.customSeparator || '---'}
|
||||
onChange={handleSettingChange}
|
||||
helperText={t('settings.customSeparatorHelper')}
|
||||
sx={{ mt: 3 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Code 分块器特殊设置 */}
|
||||
{taskSettings.splitType === 'code' && (
|
||||
<FormControl fullWidth sx={{ mt: 3 }}>
|
||||
<InputLabel id="code-language-label">{t('settings.codeLanguage')}</InputLabel>
|
||||
<Select
|
||||
labelId="code-language-label"
|
||||
value={taskSettings.splitLanguage || 'js'}
|
||||
label={t('settings.codeLanguage')}
|
||||
name="splitLanguage"
|
||||
onChange={handleSettingChange}
|
||||
>
|
||||
<MenuItem value="js">JavaScript</MenuItem>
|
||||
<MenuItem value="python">Python</MenuItem>
|
||||
<MenuItem value="java">Java</MenuItem>
|
||||
<MenuItem value="go">Go</MenuItem>
|
||||
<MenuItem value="ruby">Ruby</MenuItem>
|
||||
<MenuItem value="cpp">C++</MenuItem>
|
||||
<MenuItem value="c">C</MenuItem>
|
||||
<MenuItem value="csharp">C#</MenuItem>
|
||||
<MenuItem value="php">PHP</MenuItem>
|
||||
<MenuItem value="rust">Rust</MenuItem>
|
||||
<MenuItem value="typescript">TypeScript</MenuItem>
|
||||
<MenuItem value="swift">Swift</MenuItem>
|
||||
<MenuItem value="kotlin">Kotlin</MenuItem>
|
||||
<MenuItem value="scala">Scala</MenuItem>
|
||||
</Select>
|
||||
<FormHelperText>{t('settings.codeLanguageHelper')}</FormHelperText>
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
{/* Recursive 分块器特殊设置 */}
|
||||
{taskSettings.splitType === 'recursive' && (
|
||||
<Box sx={{ mt: 3 }}>
|
||||
<Typography gutterBottom>{t('settings.separators')}</Typography>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.separatorsInput')}
|
||||
name="separatorsInput"
|
||||
value={taskSettings.separatorsInput || '|,##,>,-'}
|
||||
onChange={e => {
|
||||
const value = e.target.value;
|
||||
// 同时更新输入框值和分隔符数组
|
||||
setTaskSettings(prev => ({
|
||||
...prev,
|
||||
separatorsInput: value,
|
||||
separators: value.split(',').map(item => item.trim())
|
||||
}));
|
||||
}}
|
||||
helperText={t('settings.separatorsHelper')}
|
||||
/>
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1, mt: 1 }}>
|
||||
{(taskSettings.separators || ['|', '##', '>', '-']).map((sep, index) => (
|
||||
<Chip key={index} label={sep} variant="outlined" />
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 3 }}>
|
||||
{t('settings.textSplitDescription')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card style={{ marginBottom: 20 }}>
|
||||
<CardContent>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
{t('settings.questionGenSettings')}
|
||||
</Typography>
|
||||
<Box sx={{ px: 2, py: 1 }}>
|
||||
<Typography id="question-generation-length-slider" gutterBottom>
|
||||
{t('settings.questionGenLength', { length: taskSettings.questionGenerationLength })}
|
||||
</Typography>
|
||||
<Slider
|
||||
value={taskSettings.questionGenerationLength}
|
||||
onChange={handleSliderChange('questionGenerationLength')}
|
||||
aria-labelledby="question-generation-length-slider"
|
||||
valueLabelDisplay="auto"
|
||||
step={10}
|
||||
marks
|
||||
min={10}
|
||||
max={1000}
|
||||
/>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 1 }}>
|
||||
{t('settings.questionGenDescription')}
|
||||
</Typography>
|
||||
|
||||
<Typography id="question-mark-removing-probability-slider" gutterBottom sx={{ mt: 3 }}>
|
||||
{t('settings.questionMaskRemovingProbability', {
|
||||
probability: taskSettings.questionMaskRemovingProbability
|
||||
})}
|
||||
</Typography>
|
||||
<Slider
|
||||
value={taskSettings.questionMaskRemovingProbability}
|
||||
onChange={handleSliderChange('questionMaskRemovingProbability')}
|
||||
aria-labelledby="question-generation-length-slider"
|
||||
valueLabelDisplay="auto"
|
||||
step={5}
|
||||
marks
|
||||
min={0}
|
||||
max={100}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
style={{ marginTop: 20 }}
|
||||
fullWidth
|
||||
label={t('settings.concurrencyLimit')}
|
||||
name="concurrencyLimit"
|
||||
value={taskSettings.concurrencyLimit}
|
||||
onChange={handleSettingChange}
|
||||
type="number"
|
||||
helperText={t('settings.concurrencyLimitHelper')}
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card style={{ marginBottom: 20 }}>
|
||||
<CardContent>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
{t('settings.pdfSettings')}
|
||||
</Typography>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.minerUToken')}
|
||||
name="minerUToken"
|
||||
value={taskSettings.minerUToken}
|
||||
onChange={handleSettingChange}
|
||||
type="password"
|
||||
helperText={t('settings.minerUHelper')}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.minerULocalUrl')}
|
||||
name="minerULocalUrl"
|
||||
value={taskSettings.minerULocalUrl}
|
||||
onChange={handleSettingChange}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.visionConcurrencyLimit')}
|
||||
name="visionConcurrencyLimit"
|
||||
value={taskSettings.visionConcurrencyLimit ? taskSettings.visionConcurrencyLimit : 5}
|
||||
onChange={handleSettingChange}
|
||||
type="number"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{/* 多轮对话数据集设置 */}
|
||||
<Card style={{ marginBottom: 20 }}>
|
||||
<CardContent>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
{t('settings.multiTurnSettings')}
|
||||
</Typography>
|
||||
<Box sx={{ px: 2, py: 1 }}>
|
||||
{/* 系统提示词 */}
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.multiTurnSystemPrompt')}
|
||||
name="multiTurnSystemPrompt"
|
||||
value={taskSettings.multiTurnSystemPrompt || ''}
|
||||
onChange={handleSettingChange}
|
||||
multiline
|
||||
rows={3}
|
||||
helperText={t('settings.multiTurnSystemPromptHelper')}
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
{/* 对话场景 */}
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.multiTurnScenario')}
|
||||
name="multiTurnScenario"
|
||||
value={taskSettings.multiTurnScenario || ''}
|
||||
onChange={handleSettingChange}
|
||||
helperText={t('settings.multiTurnScenarioHelper')}
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
{/* 对话轮数 */}
|
||||
<Typography id="multi-turn-rounds-slider" gutterBottom sx={{ mt: 2 }}>
|
||||
{t('settings.multiTurnRounds', { rounds: taskSettings.multiTurnRounds || 3 })}
|
||||
</Typography>
|
||||
<Slider
|
||||
value={taskSettings.multiTurnRounds || 3}
|
||||
onChange={handleSliderChange('multiTurnRounds')}
|
||||
aria-labelledby="multi-turn-rounds-slider"
|
||||
valueLabelDisplay="auto"
|
||||
step={1}
|
||||
marks
|
||||
min={2}
|
||||
max={8}
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
{/* 角色A设定 */}
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.multiTurnRoleA')}
|
||||
name="multiTurnRoleA"
|
||||
value={taskSettings.multiTurnRoleA || ''}
|
||||
onChange={handleSettingChange}
|
||||
multiline
|
||||
rows={2}
|
||||
helperText={t('settings.multiTurnRoleAHelper')}
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
{/* 角色B设定 */}
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.multiTurnRoleB')}
|
||||
name="multiTurnRoleB"
|
||||
value={taskSettings.multiTurnRoleB || ''}
|
||||
onChange={handleSettingChange}
|
||||
multiline
|
||||
rows={2}
|
||||
helperText={t('settings.multiTurnRoleBHelper')}
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 1 }}>
|
||||
{t('settings.multiTurnDescription')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{/* 测试集生成设置 */}
|
||||
<Card style={{ marginBottom: 20 }}>
|
||||
<CardContent>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
{t('settings.evalQuestionSettings')}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||
{t('settings.evalQuestionSettingsDescription')}
|
||||
</Typography>
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} sm={6} md={2.4}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.evalTrueFalseRatio')}
|
||||
type="number"
|
||||
value={taskSettings.evalQuestionTypeRatios?.true_false || 0}
|
||||
onChange={e => {
|
||||
const value = Math.max(0, parseInt(e.target.value) || 0);
|
||||
setTaskSettings(prev => ({
|
||||
...prev,
|
||||
evalQuestionTypeRatios: {
|
||||
...prev.evalQuestionTypeRatios,
|
||||
true_false: value
|
||||
}
|
||||
}));
|
||||
}}
|
||||
InputProps={{ inputProps: { min: 0 } }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* 单选题 */}
|
||||
<Grid item xs={12} sm={6} md={2.4}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.evalSingleChoiceRatio')}
|
||||
type="number"
|
||||
value={taskSettings.evalQuestionTypeRatios?.single_choice || 0}
|
||||
onChange={e => {
|
||||
const value = Math.max(0, parseInt(e.target.value) || 0);
|
||||
setTaskSettings(prev => ({
|
||||
...prev,
|
||||
evalQuestionTypeRatios: {
|
||||
...prev.evalQuestionTypeRatios,
|
||||
single_choice: value
|
||||
}
|
||||
}));
|
||||
}}
|
||||
InputProps={{ inputProps: { min: 0 } }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* 多选题 */}
|
||||
<Grid item xs={12} sm={6} md={2.4}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.evalMultipleChoiceRatio')}
|
||||
type="number"
|
||||
value={taskSettings.evalQuestionTypeRatios?.multiple_choice || 0}
|
||||
onChange={e => {
|
||||
const value = Math.max(0, parseInt(e.target.value) || 0);
|
||||
setTaskSettings(prev => ({
|
||||
...prev,
|
||||
evalQuestionTypeRatios: {
|
||||
...prev.evalQuestionTypeRatios,
|
||||
multiple_choice: value
|
||||
}
|
||||
}));
|
||||
}}
|
||||
InputProps={{ inputProps: { min: 0 } }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* 固定短答案 */}
|
||||
<Grid item xs={12} sm={6} md={2.4}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.evalShortAnswerRatio')}
|
||||
type="number"
|
||||
value={taskSettings.evalQuestionTypeRatios?.short_answer || 0}
|
||||
onChange={e => {
|
||||
const value = Math.max(0, parseInt(e.target.value) || 0);
|
||||
setTaskSettings(prev => ({
|
||||
...prev,
|
||||
evalQuestionTypeRatios: {
|
||||
...prev.evalQuestionTypeRatios,
|
||||
short_answer: value
|
||||
}
|
||||
}));
|
||||
}}
|
||||
InputProps={{ inputProps: { min: 0 } }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* 开放式回答 */}
|
||||
<Grid item xs={12} sm={6} md={2.4}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.evalOpenEndedRatio')}
|
||||
type="number"
|
||||
value={taskSettings.evalQuestionTypeRatios?.open_ended || 0}
|
||||
onChange={e => {
|
||||
const value = Math.max(0, parseInt(e.target.value) || 0);
|
||||
setTaskSettings(prev => ({
|
||||
...prev,
|
||||
evalQuestionTypeRatios: {
|
||||
...prev.evalQuestionTypeRatios,
|
||||
open_ended: value
|
||||
}
|
||||
}));
|
||||
}}
|
||||
InputProps={{ inputProps: { min: 0 } }}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 2 }}>
|
||||
{t('settings.evalQuestionRatioHelper')}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card style={{ marginBottom: 20 }}>
|
||||
<CardContent>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
{t('settings.huggingfaceSettings')}
|
||||
</Typography>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('settings.huggingfaceToken')}
|
||||
name="huggingfaceToken"
|
||||
value={taskSettings.huggingfaceToken || ''}
|
||||
onChange={handleSettingChange}
|
||||
type="password"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Snackbar
|
||||
open={success}
|
||||
autoHideDuration={2000}
|
||||
onClose={handleCloseSnackbar}
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
|
||||
>
|
||||
<Alert onClose={handleCloseSnackbar} severity="success" sx={{ width: '100%' }}>
|
||||
{t('settings.saveSuccess')}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
<Snackbar
|
||||
open={!!error}
|
||||
autoHideDuration={2000}
|
||||
onClose={handleCloseSnackbar}
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
|
||||
>
|
||||
<Alert onClose={handleCloseSnackbar} severity="error" sx={{ width: '100%' }}>
|
||||
{error}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
{/* 吸底保存按钮 */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
padding: '8px',
|
||||
backgroundColor: 'background.paper',
|
||||
borderTop: '1px solid',
|
||||
borderColor: 'divider',
|
||||
zIndex: 1100,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
boxShadow: 3
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size="medium"
|
||||
startIcon={<SaveIcon />}
|
||||
onClick={handleSaveTaskSettings}
|
||||
>
|
||||
{t('settings.saveTaskConfig')}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user