Files
YG-Datasets/easy-dataset-main/app/api/projects/[projectId]/files/route.js

244 lines
8.3 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.
import { NextResponse } from 'next/server';
import { getProject } from '@/lib/db/projects';
import path from 'path';
import { getProjectRoot, ensureDir } from '@/lib/db/base';
import { promises as fs } from 'fs';
import {
checkUploadFileInfoByMD5,
createUploadFileInfo,
delUploadFileInfoById,
getUploadFilesPagination
} from '@/lib/db/upload-files';
import { getFileMD5 } from '@/lib/util/file';
import { batchSaveTags } from '@/lib/db/tags';
import { getProjectChunks, getProjectTocByName } from '@/lib/file/text-splitter';
import { handleDomainTree } from '@/lib/util/domain-tree';
// Replace the deprecated config export with the new export syntax
export const dynamic = 'force-dynamic';
// This tells Next.js not to parse the request body automatically
export const bodyParser = false;
// 获取项目文件列表
export async function GET(request, { params }) {
try {
const { projectId } = params;
// 验证项目ID
if (!projectId) {
return NextResponse.json({ error: 'The project ID cannot be empty' }, { status: 400 });
}
const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get('page')) || 1;
const pageSize = parseInt(searchParams.get('pageSize')) || 10; // 每页10个文件支持分页
const fileName = searchParams.get('fileName') || '';
const getAllIds = searchParams.get('getAllIds') === 'true'; // 新增获取所有文件ID的标志
// 如果请求所有文件ID直接返回ID列表
if (getAllIds) {
const allFiles = await getUploadFilesPagination(projectId, 1, 9999, fileName); // 获取所有文件
const allFileIds = allFiles.data?.map(file => String(file.id)) || [];
return NextResponse.json({ allFileIds });
}
// 获取文件列表
const files = await getUploadFilesPagination(projectId, page, pageSize, fileName);
return NextResponse.json(files);
} catch (error) {
console.error('Error obtaining file list:', String(error));
return NextResponse.json({ error: error.message || 'Error obtaining file list' }, { status: 500 });
}
}
// 删除文件
export async function DELETE(request, { params }) {
try {
const { projectId } = params;
const { searchParams } = new URL(request.url);
const fileId = searchParams.get('fileId');
const domainTreeAction = searchParams.get('domainTreeAction') || 'keep';
// 从请求体中获取模型信息和语言环境
const requestData = await request.json();
const model = requestData.model;
const language = requestData.language || 'en';
// 验证项目ID和文件名
if (!projectId) {
return NextResponse.json({ error: 'The project ID cannot be empty' }, { status: 400 });
}
if (!fileId) {
return NextResponse.json({ error: 'The file name cannot be empty' }, { status: 400 });
}
// 获取项目信息
const project = await getProject(projectId);
if (!project) {
return NextResponse.json({ error: 'The project does not exist' }, { status: 404 });
}
// 删除文件及其相关的文本块、问题和数据集
const { stats, fileName, fileInfo } = await delUploadFileInfoById(fileId);
const deleteToc = await getProjectTocByName(projectId, fileName);
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));
// 即使 TOC 文件删除失败,不影响整体结果
}
// 如果选择了保持领域树不变,直接返回删除结果
if (domainTreeAction === 'keep') {
return NextResponse.json({
message: '文件删除成功',
stats: stats,
domainTreeAction: 'keep',
cascadeDelete: true
});
}
// 处理领域树更新
try {
// 获取项目的所有文件
const { chunks, toc } = await getProjectChunks(projectId);
// 如果不存在文本块,说明项目已经没有文件了
if (!chunks || chunks.length === 0) {
// 清空领域树
await batchSaveTags(projectId, []);
return NextResponse.json({
message: '文件删除成功,领域树已清空',
stats: stats,
domainTreeAction,
cascadeDelete: true
});
}
// 调用领域树处理模块
await handleDomainTree({
projectId,
action: domainTreeAction,
allToc: toc,
model,
language,
deleteToc,
project
});
} catch (error) {
console.error('Error updating domain tree after file deletion:', String(error));
// 即使领域树更新失败,也不影响文件删除的结果
}
return NextResponse.json({
message: '文件删除成功',
stats: stats,
domainTreeAction,
cascadeDelete: true
});
} catch (error) {
console.error('Error deleting file:', String(error));
return NextResponse.json({ error: error.message || 'Error deleting file' }, { status: 500 });
}
}
// 上传文件
export async function POST(request, { params }) {
console.log('File upload request processing, parameters:', params);
const { projectId } = params;
// 验证项目ID
if (!projectId) {
console.log('The project ID cannot be empty, returning 400 error');
return NextResponse.json({ error: 'The project ID cannot be empty' }, { status: 400 });
}
// 获取项目信息
const project = await getProject(projectId);
if (!project) {
console.log('The project does not exist, returning 404 error');
return NextResponse.json({ error: 'The project does not exist' }, { status: 404 });
}
console.log('Project information retrieved successfully:', project.name || project.id);
try {
console.log('Try using alternate methods for file upload...');
// 检查请求头中是否包含文件名
const encodedFileName = request.headers.get('x-file-name');
const fileName = encodedFileName ? decodeURIComponent(encodedFileName) : null;
console.log('Get file name from request header:', fileName);
if (!fileName) {
console.log('The request header does not contain a file name');
return NextResponse.json(
{ error: 'The request header does not contain a file name (x-file-name)' },
{ status: 400 }
);
}
// 检查文件类型
if (!fileName.endsWith('.md') && !fileName.endsWith('.pdf')) {
return NextResponse.json({ error: 'Only Markdown files are supported' }, { status: 400 });
}
// 直接从请求体中读取二进制数据
const fileBuffer = Buffer.from(await request.arrayBuffer());
// 保存文件
const projectRoot = await getProjectRoot();
const projectPath = path.join(projectRoot, projectId);
const filesDir = path.join(projectPath, 'files');
await ensureDir(filesDir);
const filePath = path.join(filesDir, fileName);
await fs.writeFile(filePath, fileBuffer);
//获取文件大小
const stats = await fs.stat(filePath);
//获取文件md5
const md5 = await getFileMD5(filePath);
//获取文件扩展名
const ext = path.extname(filePath);
// let res = await checkUploadFileInfoByMD5(projectId, md5);
// if (res) {
// return NextResponse.json({ error: `【${fileName}】该文件已在此项目中存在` }, { status: 400 });
// }
let fileInfo = await createUploadFileInfo({
projectId,
fileName,
size: stats.size,
md5,
fileExt: ext,
path: filesDir
});
console.log('The file upload process is complete, and a successful response is returned');
return NextResponse.json({
message: 'File uploaded successfully',
fileName,
filePath,
fileId: fileInfo.id
});
} catch (error) {
console.error('Error processing file upload:', String(error));
console.error('Error stack:', error.stack);
return NextResponse.json(
{
error: 'File upload failed: ' + (error.message || 'Unknown error')
},
{ status: 500 }
);
}
}