Files
YG-Datasets/easy-dataset-main/components/text-split/ChunkListHeader.js

401 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'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>
);
}