213 lines
7.3 KiB
JavaScript
213 lines
7.3 KiB
JavaScript
|
|
'use client';
|
|||
|
|
|
|||
|
|
import { useState, useEffect, useRef } from 'react';
|
|||
|
|
import { useTranslation } from 'react-i18next';
|
|||
|
|
import {
|
|||
|
|
Dialog,
|
|||
|
|
DialogTitle,
|
|||
|
|
DialogContent,
|
|||
|
|
Box,
|
|||
|
|
Typography,
|
|||
|
|
LinearProgress,
|
|||
|
|
Paper,
|
|||
|
|
Divider,
|
|||
|
|
IconButton,
|
|||
|
|
Button
|
|||
|
|
} from '@mui/material';
|
|||
|
|
import CloseIcon from '@mui/icons-material/Close';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 全自动蒸馏进度组件
|
|||
|
|
* @param {Object} props
|
|||
|
|
* @param {boolean} props.open - 对话框是否打开
|
|||
|
|
* @param {Function} props.onClose - 关闭对话框的回调
|
|||
|
|
* @param {Object} props.progress - 进度信息
|
|||
|
|
*/
|
|||
|
|
export default function AutoDistillProgress({ open, onClose, progress = {} }) {
|
|||
|
|
const { t } = useTranslation();
|
|||
|
|
const logContainerRef = useRef(null);
|
|||
|
|
|
|||
|
|
// 自动滚动到底部
|
|||
|
|
useEffect(() => {
|
|||
|
|
if (logContainerRef.current) {
|
|||
|
|
logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;
|
|||
|
|
}
|
|||
|
|
}, [progress.logs]);
|
|||
|
|
|
|||
|
|
const getStageText = () => {
|
|||
|
|
const { stage } = progress;
|
|||
|
|
switch (stage) {
|
|||
|
|
case 'level1':
|
|||
|
|
return t('distill.stageBuildingLevel1');
|
|||
|
|
case 'level2':
|
|||
|
|
return t('distill.stageBuildingLevel2');
|
|||
|
|
case 'level3':
|
|||
|
|
return t('distill.stageBuildingLevel3');
|
|||
|
|
case 'level4':
|
|||
|
|
return t('distill.stageBuildingLevel4');
|
|||
|
|
case 'level5':
|
|||
|
|
return t('distill.stageBuildingLevel5');
|
|||
|
|
case 'questions':
|
|||
|
|
return t('distill.stageBuildingQuestions');
|
|||
|
|
case 'datasets':
|
|||
|
|
return t('distill.stageBuildingDatasets');
|
|||
|
|
case 'multi-turn-datasets':
|
|||
|
|
return t('distill.stageBuildingMultiTurnDatasets', { defaultValue: '生成多轮对话数据集中...' });
|
|||
|
|
case 'completed':
|
|||
|
|
return t('distill.stageCompleted');
|
|||
|
|
default:
|
|||
|
|
return t('distill.stageInitializing');
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const getOverallProgress = () => {
|
|||
|
|
const { tagsBuilt, tagsTotal, questionsBuilt, questionsTotal, datasetsBuilt, datasetsTotal } = progress;
|
|||
|
|
|
|||
|
|
// 整体进度按比例计算:标签构建占30%,问题生成占35%,数据集生成占35%
|
|||
|
|
let tagProgress = tagsTotal ? (tagsBuilt / tagsTotal) * 30 : 0;
|
|||
|
|
let questionProgress = questionsTotal ? (questionsBuilt / questionsTotal) * 35 : 0;
|
|||
|
|
let datasetProgress = datasetsTotal ? (datasetsBuilt / datasetsTotal) * 35 : 0;
|
|||
|
|
|
|||
|
|
return Math.min(100, Math.round(tagProgress + questionProgress + datasetProgress));
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<Dialog
|
|||
|
|
open={open}
|
|||
|
|
onClose={progress.stage === 'completed' || !progress.stage ? onClose : null}
|
|||
|
|
maxWidth="md"
|
|||
|
|
fullWidth
|
|||
|
|
>
|
|||
|
|
<DialogTitle>
|
|||
|
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|||
|
|
{t('distill.autoDistillProgress')}
|
|||
|
|
{(progress.stage === 'completed' || !progress.stage) && (
|
|||
|
|
<IconButton onClick={onClose} aria-label="close">
|
|||
|
|
<CloseIcon />
|
|||
|
|
</IconButton>
|
|||
|
|
)}
|
|||
|
|
</Box>
|
|||
|
|
</DialogTitle>
|
|||
|
|
<DialogContent>
|
|||
|
|
<Box sx={{ py: 1 }}>
|
|||
|
|
{/* 整体进度 */}
|
|||
|
|
<Box sx={{ mb: 4 }}>
|
|||
|
|
<Typography variant="h6" gutterBottom>
|
|||
|
|
{t('distill.overallProgress')}
|
|||
|
|
</Typography>
|
|||
|
|
|
|||
|
|
<Box sx={{ mb: 2 }}>
|
|||
|
|
<LinearProgress variant="determinate" value={getOverallProgress()} sx={{ height: 10, borderRadius: 5 }} />
|
|||
|
|
<Box sx={{ display: 'flex', justifyContent: 'flex-end', mt: 0.5 }}>
|
|||
|
|
<Typography variant="body2" color="text.secondary">
|
|||
|
|
{getOverallProgress()}%
|
|||
|
|
</Typography>
|
|||
|
|
</Box>
|
|||
|
|
</Box>
|
|||
|
|
|
|||
|
|
<Box
|
|||
|
|
sx={{
|
|||
|
|
display: 'grid',
|
|||
|
|
gridTemplateColumns: progress.multiTurnDatasetsTotal > 0 ? 'repeat(4, 1fr)' : 'repeat(3, 1fr)',
|
|||
|
|
gap: 2
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<Paper variant="outlined" sx={{ p: 2 }}>
|
|||
|
|
<Typography variant="body2" color="text.secondary">
|
|||
|
|
{t('distill.tagsProgress')}
|
|||
|
|
</Typography>
|
|||
|
|
<Typography variant="h6">
|
|||
|
|
{progress.tagsBuilt || 0} / {progress.tagsTotal || 0}
|
|||
|
|
</Typography>
|
|||
|
|
</Paper>
|
|||
|
|
|
|||
|
|
<Paper variant="outlined" sx={{ p: 2 }}>
|
|||
|
|
<Typography variant="body2" color="text.secondary">
|
|||
|
|
{t('distill.questionsProgress')}
|
|||
|
|
</Typography>
|
|||
|
|
<Typography variant="h6">
|
|||
|
|
{progress.questionsBuilt || 0} / {progress.questionsTotal || 0}
|
|||
|
|
</Typography>
|
|||
|
|
</Paper>
|
|||
|
|
|
|||
|
|
<Paper variant="outlined" sx={{ p: 2 }}>
|
|||
|
|
<Typography variant="body2" color="text.secondary">
|
|||
|
|
{t('distill.datasetsProgress')}
|
|||
|
|
</Typography>
|
|||
|
|
<Typography variant="h6">
|
|||
|
|
{progress.datasetsBuilt || 0} / {progress.datasetsTotal || 0}
|
|||
|
|
</Typography>
|
|||
|
|
</Paper>
|
|||
|
|
|
|||
|
|
{progress.multiTurnDatasetsTotal > 0 && (
|
|||
|
|
<Paper variant="outlined" sx={{ p: 2 }}>
|
|||
|
|
<Typography variant="body2" color="text.secondary">
|
|||
|
|
{t('distill.multiTurnDatasetsProgress', { defaultValue: '多轮对话进度' })}
|
|||
|
|
</Typography>
|
|||
|
|
<Typography variant="h6">
|
|||
|
|
{progress.multiTurnDatasetsBuilt || 0} / {progress.multiTurnDatasetsTotal || 0}
|
|||
|
|
</Typography>
|
|||
|
|
</Paper>
|
|||
|
|
)}
|
|||
|
|
</Box>
|
|||
|
|
</Box>
|
|||
|
|
|
|||
|
|
{/* 当前阶段 */}
|
|||
|
|
<Box sx={{ mb: 4 }}>
|
|||
|
|
<Typography variant="h6" gutterBottom>
|
|||
|
|
{t('distill.currentStage')}
|
|||
|
|
</Typography>
|
|||
|
|
|
|||
|
|
<Paper variant="outlined" sx={{ p: 2, bgcolor: 'primary.light', color: 'primary.contrastText' }}>
|
|||
|
|
<Typography variant="h6">{getStageText()}</Typography>
|
|||
|
|
</Paper>
|
|||
|
|
</Box>
|
|||
|
|
|
|||
|
|
{/* 实时日志 */}
|
|||
|
|
<Box sx={{ mb: 2 }}>
|
|||
|
|
<Typography variant="h6" gutterBottom>
|
|||
|
|
{t('distill.realTimeLogs')}
|
|||
|
|
</Typography>
|
|||
|
|
|
|||
|
|
<Paper
|
|||
|
|
variant="outlined"
|
|||
|
|
sx={{
|
|||
|
|
p: 2,
|
|||
|
|
maxHeight: 250,
|
|||
|
|
overflow: 'auto',
|
|||
|
|
bgcolor: 'grey.900',
|
|||
|
|
color: 'grey.100',
|
|||
|
|
fontFamily: 'monospace',
|
|||
|
|
fontSize: '0.875rem'
|
|||
|
|
}}
|
|||
|
|
ref={logContainerRef}
|
|||
|
|
>
|
|||
|
|
{progress.logs?.length > 0 ? (
|
|||
|
|
progress.logs.map((log, index) => {
|
|||
|
|
// 检测成功日志,显示为绿色 Successfully
|
|||
|
|
let color = 'inherit';
|
|||
|
|
if (log.includes('成功') || log.includes('完成') || log.includes('Successfully')) {
|
|||
|
|
color = '#4caf50';
|
|||
|
|
}
|
|||
|
|
if (log.includes('失败') || log.toLowerCase().includes('error')) {
|
|||
|
|
color = '#f44336';
|
|||
|
|
}
|
|||
|
|
return (
|
|||
|
|
<Box key={index} sx={{ mb: 0.5, color: color }}>
|
|||
|
|
{log}
|
|||
|
|
</Box>
|
|||
|
|
);
|
|||
|
|
})
|
|||
|
|
) : (
|
|||
|
|
<Typography variant="body2" color="grey.500">
|
|||
|
|
{t('distill.waitingForLogs')}
|
|||
|
|
</Typography>
|
|||
|
|
)}
|
|||
|
|
</Paper>
|
|||
|
|
</Box>
|
|||
|
|
</Box>
|
|||
|
|
</DialogContent>
|
|||
|
|
</Dialog>
|
|||
|
|
);
|
|||
|
|
}
|