first-update
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getUploadFileInfoById, delUploadFileInfoById } from '@/lib/db/upload-files';
|
||||
import { getProject } from '@/lib/db/projects';
|
||||
import { getProjectChunks, getProjectTocByName } from '@/lib/file/text-splitter';
|
||||
import { batchSaveTags } from '@/lib/db/tags';
|
||||
import { handleDomainTree } from '@/lib/util/domain-tree';
|
||||
import path from 'path';
|
||||
import { getProjectRoot } from '@/lib/db/base';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
/**
|
||||
* 批量删除文件
|
||||
* 复用单个文件删除的完整逻辑,包括领域树修订
|
||||
*/
|
||||
export async function POST(request, { params }) {
|
||||
try {
|
||||
const { projectId } = params;
|
||||
const body = await request.json();
|
||||
|
||||
if (!projectId) {
|
||||
return NextResponse.json({ error: 'Project ID is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
const { fileIds, domainTreeAction = 'keep', model, language = '中文' } = body;
|
||||
|
||||
if (!fileIds || !Array.isArray(fileIds) || fileIds.length === 0) {
|
||||
return NextResponse.json({ error: 'File IDs array is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
console.log('开始处理批量删除文件请求');
|
||||
console.log('项目ID:', projectId);
|
||||
console.log('请求的文件IDs:', fileIds);
|
||||
console.log('领域树操作:', domainTreeAction);
|
||||
|
||||
// 获取项目信息
|
||||
const project = await getProject(projectId);
|
||||
if (!project) {
|
||||
return NextResponse.json({ error: 'The project does not exist' }, { status: 404 });
|
||||
}
|
||||
|
||||
// 验证文件并删除
|
||||
const results = [];
|
||||
const deletedTocs = [];
|
||||
let deletedCount = 0;
|
||||
let failedCount = 0;
|
||||
let totalStats = {
|
||||
deletedChunks: 0,
|
||||
deletedQuestions: 0,
|
||||
deletedDatasets: 0
|
||||
};
|
||||
|
||||
for (const fileId of fileIds) {
|
||||
try {
|
||||
console.log(`正在验证文件: ${fileId}`);
|
||||
const fileInfo = await getUploadFileInfoById(fileId);
|
||||
|
||||
if (!fileInfo) {
|
||||
console.log(`文件不存在: ${fileId}`);
|
||||
results.push({
|
||||
fileId,
|
||||
success: false,
|
||||
error: 'File not found'
|
||||
});
|
||||
failedCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileInfo.projectId !== projectId) {
|
||||
console.log(`文件属于其他项目: ${fileInfo.projectId} != ${projectId}`);
|
||||
results.push({
|
||||
fileId,
|
||||
success: false,
|
||||
error: 'File belongs to another project'
|
||||
});
|
||||
failedCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 删除文件及其相关的文本块、问题和数据集
|
||||
console.log(`删除文件: ${fileInfo.fileName}`);
|
||||
const { stats, fileName } = await delUploadFileInfoById(fileId);
|
||||
|
||||
// 累计统计信息
|
||||
totalStats.deletedChunks += stats.deletedChunks || 0;
|
||||
totalStats.deletedQuestions += stats.deletedQuestions || 0;
|
||||
totalStats.deletedDatasets += stats.deletedDatasets || 0;
|
||||
|
||||
// 获取并保存删除的 TOC 信息
|
||||
const deleteToc = await getProjectTocByName(projectId, fileName);
|
||||
if (deleteToc) {
|
||||
deletedTocs.push(deleteToc);
|
||||
}
|
||||
|
||||
// 删除 TOC 文件
|
||||
try {
|
||||
const projectRoot = await getProjectRoot();
|
||||
const projectPath = path.join(projectRoot, projectId);
|
||||
const tocDir = path.join(projectPath, 'toc');
|
||||
const baseName = path.basename(fileInfo.fileName, path.extname(fileInfo.fileName));
|
||||
const tocPath = path.join(tocDir, `${baseName}-toc.json`);
|
||||
await fs.unlink(tocPath);
|
||||
console.log(`成功删除 TOC 文件: ${tocPath}`);
|
||||
} catch (error) {
|
||||
console.error(`删除 TOC 文件失败:`, String(error));
|
||||
}
|
||||
|
||||
results.push({
|
||||
fileId,
|
||||
fileName: fileInfo.fileName,
|
||||
success: true,
|
||||
stats
|
||||
});
|
||||
deletedCount++;
|
||||
|
||||
console.log(`成功删除文件: ${fileInfo.fileName}`);
|
||||
} catch (error) {
|
||||
console.error(`删除文件 ${fileId} 时出错:`, error);
|
||||
results.push({
|
||||
fileId,
|
||||
success: false,
|
||||
error: error.message
|
||||
});
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`批量删除完成: 成功${deletedCount}个, 失败${failedCount}个`);
|
||||
|
||||
// 如果选择了保持领域树不变,直接返回删除结果
|
||||
if (domainTreeAction === 'keep') {
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
deletedCount,
|
||||
failedCount,
|
||||
total: fileIds.length,
|
||||
results,
|
||||
stats: totalStats,
|
||||
domainTreeAction: 'keep',
|
||||
message: `Successfully deleted ${deletedCount} files, ${failedCount} failed`
|
||||
});
|
||||
}
|
||||
|
||||
// 处理领域树更新
|
||||
try {
|
||||
// 获取项目的所有文件
|
||||
const { chunks, toc } = await getProjectChunks(projectId);
|
||||
|
||||
// 如果不存在文本块,说明项目已经没有文件了
|
||||
if (!chunks || chunks.length === 0) {
|
||||
// 清空领域树
|
||||
await batchSaveTags(projectId, []);
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
deletedCount,
|
||||
failedCount,
|
||||
total: fileIds.length,
|
||||
results,
|
||||
stats: totalStats,
|
||||
domainTreeAction,
|
||||
message: `Successfully deleted ${deletedCount} files, domain tree cleared`,
|
||||
domainTreeCleared: true
|
||||
});
|
||||
}
|
||||
|
||||
// 调用领域树处理模块
|
||||
await handleDomainTree({
|
||||
projectId,
|
||||
action: domainTreeAction,
|
||||
allToc: toc,
|
||||
model: model,
|
||||
language,
|
||||
deleteToc: deletedTocs.length > 0 ? deletedTocs : undefined,
|
||||
project
|
||||
});
|
||||
|
||||
console.log('领域树更新成功');
|
||||
} catch (error) {
|
||||
console.error('Error updating domain tree after batch deletion:', String(error));
|
||||
// 即使领域树更新失败,也不影响文件删除的结果
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
deletedCount,
|
||||
failedCount,
|
||||
total: fileIds.length,
|
||||
results,
|
||||
stats: totalStats,
|
||||
domainTreeAction,
|
||||
message: `Successfully deleted ${deletedCount} files, ${failedCount} failed`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error batch deleting files:', String(error));
|
||||
return NextResponse.json({ error: String(error) || 'Failed to batch delete files' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user