first-update
This commit is contained in:
400
easy-dataset-main/components/text-split/ChunkListHeader.js
Normal file
400
easy-dataset-main/components/text-split/ChunkListHeader.js
Normal file
@@ -0,0 +1,400 @@
|
||||
'use client';
|
||||
|
||||
import { Box, Typography, Checkbox, Button, Select, MenuItem, Tooltip, Menu, IconButton, Badge } from '@mui/material';
|
||||
import QuizIcon from '@mui/icons-material/Quiz';
|
||||
import DownloadIcon from '@mui/icons-material/Download';
|
||||
import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh';
|
||||
import CleaningServicesIcon from '@mui/icons-material/CleaningServices';
|
||||
import AssessmentIcon from '@mui/icons-material/Assessment';
|
||||
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import FilterListIcon from '@mui/icons-material/FilterList';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import axios from 'axios';
|
||||
import { toast } from 'sonner';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useState } from 'react';
|
||||
import ChunkFilterDialog from './ChunkFilterDialog';
|
||||
|
||||
export default function ChunkListHeader({
|
||||
projectId,
|
||||
totalChunks,
|
||||
selectedChunks,
|
||||
onSelectAll,
|
||||
onBatchGenerateQuestions,
|
||||
onBatchEditChunks,
|
||||
onBatchDeleteChunks,
|
||||
questionFilter,
|
||||
setQuestionFilter,
|
||||
chunks = [], // 添加chunks参数,用于导出文本块
|
||||
selectedModel = {},
|
||||
onFilterChange = null,
|
||||
activeFilterCount = 0
|
||||
}) {
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
// 添加更多菜单的状态和锚点
|
||||
const [moreMenuAnchorEl, setMoreMenuAnchorEl] = useState(null);
|
||||
const isMoreMenuOpen = Boolean(moreMenuAnchorEl);
|
||||
|
||||
// 添加筛选对话框状态
|
||||
const [filterDialogOpen, setFilterDialogOpen] = useState(false);
|
||||
|
||||
// 自动任务菜单状态
|
||||
const [autoTasksMenuAnchorEl, setAutoTasksMenuAnchorEl] = useState(null);
|
||||
const isAutoTasksMenuOpen = Boolean(autoTasksMenuAnchorEl);
|
||||
|
||||
const handleAutoTasksClick = event => {
|
||||
setAutoTasksMenuAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleAutoTasksClose = () => {
|
||||
setAutoTasksMenuAnchorEl(null);
|
||||
};
|
||||
|
||||
// 打开更多菜单
|
||||
const handleMoreMenuClick = event => {
|
||||
setMoreMenuAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
// 关闭更多菜单
|
||||
const handleMoreMenuClose = () => {
|
||||
setMoreMenuAnchorEl(null);
|
||||
};
|
||||
|
||||
// 处理批量编辑,关闭菜单并调用原有函数
|
||||
const handleBatchEdit = () => {
|
||||
handleMoreMenuClose();
|
||||
onBatchEditChunks();
|
||||
};
|
||||
|
||||
// 处理批量删除,关闭菜单并调用原有函数
|
||||
const handleBatchDelete = () => {
|
||||
handleMoreMenuClose();
|
||||
onBatchDeleteChunks();
|
||||
};
|
||||
|
||||
// 处理导出文本块,关闭菜单并调用原有函数
|
||||
const handleExport = () => {
|
||||
handleMoreMenuClose();
|
||||
handleExportChunks();
|
||||
};
|
||||
|
||||
// 创建自动提取问题任务
|
||||
const handleCreateAutoQuestionTask = async () => {
|
||||
if (!projectId || !selectedModel?.id) {
|
||||
toast.error(t('textSplit.selectModelFirst', { defaultValue: '请先选择模型' }));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用创建任务接口
|
||||
const response = await axios.post(`/api/projects/${projectId}/tasks`, {
|
||||
taskType: 'question-generation',
|
||||
modelInfo: selectedModel,
|
||||
language: i18n.language,
|
||||
detail: '批量生成问题任务'
|
||||
});
|
||||
|
||||
if (response.data?.code === 0) {
|
||||
toast.success(t('tasks.createSuccess', { defaultValue: '后台任务已创建,系统将自动处理未生成问题的文本块' }));
|
||||
} else {
|
||||
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + response.data?.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('创建自动提取问题任务失败:', error);
|
||||
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
// 创建自动数据清洗任务
|
||||
const handleCreateAutoDataCleaningTask = async () => {
|
||||
if (!projectId || !selectedModel?.id) {
|
||||
toast.error(t('textSplit.selectModelFirst', { defaultValue: '请先选择模型' }));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用创建任务接口
|
||||
const response = await axios.post(`/api/projects/${projectId}/tasks`, {
|
||||
taskType: 'data-cleaning',
|
||||
modelInfo: selectedModel,
|
||||
language: i18n.language,
|
||||
detail: '批量数据清洗任务'
|
||||
});
|
||||
|
||||
if (response.data?.code === 0) {
|
||||
toast.success(
|
||||
t('tasks.createSuccess', { defaultValue: '后台任务已创建,系统将自动处理所有文本块进行数据清洗' })
|
||||
);
|
||||
} else {
|
||||
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + response.data?.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('创建自动数据清洗任务失败:', error);
|
||||
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
// 创建自动生成评估数据集任务
|
||||
const handleCreateAutoEvalGenerationTask = async () => {
|
||||
if (!projectId || !selectedModel?.id) {
|
||||
toast.error(t('textSplit.selectModelFirst', { defaultValue: '请先选择模型' }));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用创建任务接口
|
||||
const response = await axios.post(`/api/projects/${projectId}/tasks`, {
|
||||
taskType: 'eval-generation',
|
||||
modelInfo: selectedModel,
|
||||
language: i18n.language,
|
||||
detail: '批量生成评估数据集任务'
|
||||
});
|
||||
|
||||
if (response.data?.code === 0) {
|
||||
toast.success(
|
||||
t('tasks.createSuccess', {
|
||||
defaultValue: '后台任务已创建,系统将自动为所有未生成评估题目的文本块生成评估数据集'
|
||||
})
|
||||
);
|
||||
} else {
|
||||
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + response.data?.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('创建自动生成评估数据集任务失败:', error);
|
||||
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
// 导出文本块为JSON文件的函数
|
||||
const handleExportChunks = () => {
|
||||
if (!chunks || chunks.length === 0) return;
|
||||
|
||||
// 创建要导出的数据对象
|
||||
const exportData = chunks.map(chunk => ({
|
||||
name: chunk.name,
|
||||
projectId: chunk.projectId,
|
||||
fileName: chunk.fileName,
|
||||
content: chunk.content,
|
||||
summary: chunk.summary,
|
||||
size: chunk.size
|
||||
}));
|
||||
|
||||
// 将数据转换为JSON字符串
|
||||
const jsonString = JSON.stringify(exportData, null, 2);
|
||||
|
||||
// 创建Blob对象
|
||||
const blob = new Blob([jsonString], { type: 'application/json' });
|
||||
|
||||
// 创建下载链接
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `text-chunks-export-${new Date().toISOString().split('T')[0]}.json`;
|
||||
|
||||
// 触发下载
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
// 清理
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: { xs: 'column', md: 'row' },
|
||||
justifyContent: 'space-between',
|
||||
alignItems: { xs: 'flex-start', md: 'center' },
|
||||
gap: 2,
|
||||
mb: 3
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Checkbox
|
||||
checked={selectedChunks.length === totalChunks}
|
||||
indeterminate={selectedChunks.length > 0 && selectedChunks.length < totalChunks}
|
||||
onChange={onSelectAll}
|
||||
/>
|
||||
<Typography variant="body1">{t('textSplit.selectedCount', { count: selectedChunks.length })}</Typography>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: { xs: 'column', sm: 'row' },
|
||||
alignItems: { xs: 'flex-start', sm: 'center' },
|
||||
flexWrap: 'wrap',
|
||||
gap: 1.5,
|
||||
width: { xs: '100%', md: 'auto' }
|
||||
}}
|
||||
>
|
||||
{/* 更多筛选按钮 */}
|
||||
<Tooltip title={t('datasets.moreFilters', { defaultValue: '更多筛选' })}>
|
||||
<Badge badgeContent={activeFilterCount} color="error" overlap="circular">
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<FilterListIcon />}
|
||||
onClick={() => setFilterDialogOpen(true)}
|
||||
size="small"
|
||||
sx={{ borderRadius: 1 }}
|
||||
>
|
||||
{t('datasets.moreFilters', { defaultValue: '更多筛选' })}
|
||||
</Button>
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
gap: 1.5,
|
||||
mt: { xs: 1, sm: 0 },
|
||||
width: { xs: '100%', sm: 'auto' }
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<QuizIcon />}
|
||||
disabled={selectedChunks.length === 0}
|
||||
onClick={onBatchGenerateQuestions}
|
||||
size="medium"
|
||||
sx={{ minWidth: { xs: '48%', sm: 'auto' } }}
|
||||
>
|
||||
{t('textSplit.batchGenerateQuestions')}
|
||||
</Button>
|
||||
|
||||
{/* 自动任务下拉菜单 */}
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
startIcon={<AutoFixHighIcon />}
|
||||
endIcon={<KeyboardArrowDownIcon />}
|
||||
onClick={handleAutoTasksClick}
|
||||
disabled={!projectId || !selectedModel?.id}
|
||||
size="medium"
|
||||
sx={{ minWidth: { xs: '48%', sm: 'auto' } }}
|
||||
>
|
||||
{t('textSplit.autoTasks', { defaultValue: '自动任务' })}
|
||||
</Button>
|
||||
|
||||
<Menu
|
||||
anchorEl={autoTasksMenuAnchorEl}
|
||||
open={isAutoTasksMenuOpen}
|
||||
onClose={handleAutoTasksClose}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'right'
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'right'
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
title={t('textSplit.autoGenerateQuestionsTip', {
|
||||
defaultValue: '创建后台批量处理任务:自动查询待生成问题的文本块并提取问题'
|
||||
})}
|
||||
placement="left"
|
||||
>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
handleCreateAutoQuestionTask();
|
||||
handleAutoTasksClose();
|
||||
}}
|
||||
>
|
||||
<QuizIcon fontSize="small" sx={{ mr: 1, color: 'secondary.main' }} />
|
||||
{t('textSplit.autoGenerateQuestions')}
|
||||
</MenuItem>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip
|
||||
title={t('textSplit.autoEvalGenerationTip', {
|
||||
defaultValue: '创建后台批量处理任务:自动为所有未生成评估题目的文本块生成评估数据集'
|
||||
})}
|
||||
placement="left"
|
||||
>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
handleCreateAutoEvalGenerationTask();
|
||||
handleAutoTasksClose();
|
||||
}}
|
||||
>
|
||||
<AssessmentIcon fontSize="small" sx={{ mr: 1, color: 'secondary.main' }} />
|
||||
{t('textSplit.autoEvalGeneration', { defaultValue: '自动生成评估集' })}
|
||||
</MenuItem>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip
|
||||
title={t('textSplit.autoDataCleaningTip', {
|
||||
defaultValue: '创建后台批量处理任务:自动对所有文本块进行数据清洗'
|
||||
})}
|
||||
placement="left"
|
||||
>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
handleCreateAutoDataCleaningTask();
|
||||
handleAutoTasksClose();
|
||||
}}
|
||||
>
|
||||
<CleaningServicesIcon fontSize="small" sx={{ mr: 1, color: 'success.main' }} />
|
||||
{t('textSplit.autoDataCleaning', { defaultValue: '自动数据清洗' })}
|
||||
</MenuItem>
|
||||
</Tooltip>
|
||||
</Menu>
|
||||
|
||||
{/* 更多菜单按钮 */}
|
||||
<Tooltip title={t('common.more', { defaultValue: '更多操作' })}>
|
||||
<IconButton
|
||||
onClick={handleMoreMenuClick}
|
||||
color="primary"
|
||||
size="medium"
|
||||
sx={{
|
||||
border: '1px solid',
|
||||
borderColor: 'divider'
|
||||
}}
|
||||
>
|
||||
<MoreVertIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
{/* 更多操作下拉菜单 */}
|
||||
<Menu
|
||||
anchorEl={moreMenuAnchorEl}
|
||||
open={isMoreMenuOpen}
|
||||
onClose={handleMoreMenuClose}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'right'
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'right'
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={handleBatchEdit} disabled={selectedChunks.length === 0}>
|
||||
<EditIcon fontSize="small" sx={{ mr: 1 }} />
|
||||
{t('batchEdit.batchEdit', { defaultValue: '批量编辑' })}
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleBatchDelete} disabled={selectedChunks.length === 0}>
|
||||
<DeleteIcon fontSize="small" sx={{ mr: 1, color: 'error.main' }} />
|
||||
{t('textSplit.batchDeleteChunks', { defaultValue: '批量删除' })}
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleExport} disabled={chunks.length === 0}>
|
||||
<DownloadIcon fontSize="small" sx={{ mr: 1 }} />
|
||||
{t('textSplit.exportChunks', { defaultValue: '导出文本块' })}
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* 筛选对话框 */}
|
||||
<ChunkFilterDialog open={filterDialogOpen} onClose={() => setFilterDialogOpen(false)} onApply={onFilterChange} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user