first-update
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getImageDatasetById, updateImageDataset, deleteImageDataset } from '@/lib/db/imageDatasets';
|
||||
import { getProjectPath } from '@/lib/db/base';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
// 获取单个数据集详情
|
||||
export async function GET(request, { params }) {
|
||||
try {
|
||||
const { projectId, datasetId } = params;
|
||||
|
||||
const dataset = await getImageDatasetById(datasetId);
|
||||
|
||||
if (!dataset || dataset.projectId !== projectId) {
|
||||
return NextResponse.json({ error: 'Dataset not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
// 获取项目路径
|
||||
const projectPath = await getProjectPath(projectId);
|
||||
|
||||
// 读取图片 base64
|
||||
let base64 = null;
|
||||
try {
|
||||
const imagePath = path.join(projectPath, 'images', dataset.imageName);
|
||||
const imageBuffer = await fs.readFile(imagePath);
|
||||
const base64Data = imageBuffer.toString('base64');
|
||||
const ext = path.extname(dataset.imageName).toLowerCase();
|
||||
const mimeType = ext === '.png' ? 'image/png' : ext === '.gif' ? 'image/gif' : 'image/jpeg';
|
||||
base64 = `data:${mimeType};base64,${base64Data}`;
|
||||
} catch (error) {
|
||||
console.error(`Failed to read image ${dataset.imageName}:`, error);
|
||||
}
|
||||
|
||||
// 添加图片 base64
|
||||
const datasetWithImage = {
|
||||
...dataset,
|
||||
base64
|
||||
};
|
||||
|
||||
return NextResponse.json(datasetWithImage);
|
||||
} catch (error) {
|
||||
console.error('Failed to get dataset detail:', error);
|
||||
return NextResponse.json({ error: error.message || 'Failed to get dataset detail' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// 更新数据集
|
||||
export async function PUT(request, { params }) {
|
||||
try {
|
||||
const { projectId, datasetId } = params;
|
||||
const updates = await request.json();
|
||||
|
||||
// 验证数据集存在且属于该项目
|
||||
const dataset = await getImageDatasetById(datasetId);
|
||||
if (!dataset || dataset.projectId !== projectId) {
|
||||
return NextResponse.json({ error: 'Dataset not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
// 更新数据集
|
||||
const updated = await updateImageDataset(datasetId, updates);
|
||||
|
||||
// 获取项目路径
|
||||
const projectPath = await getProjectPath(projectId);
|
||||
|
||||
// 读取图片 base64
|
||||
let base64 = null;
|
||||
try {
|
||||
const imagePath = path.join(projectPath, 'images', updated.imageName);
|
||||
const imageBuffer = await fs.readFile(imagePath);
|
||||
const base64Data = imageBuffer.toString('base64');
|
||||
const ext = path.extname(updated.imageName).toLowerCase();
|
||||
const mimeType = ext === '.png' ? 'image/png' : ext === '.gif' ? 'image/gif' : 'image/jpeg';
|
||||
base64 = `data:${mimeType};base64,${base64Data}`;
|
||||
} catch (error) {
|
||||
console.error(`Failed to read image ${updated.imageName}:`, error);
|
||||
}
|
||||
|
||||
// 添加图片 base64
|
||||
const updatedWithImage = {
|
||||
...updated,
|
||||
base64
|
||||
};
|
||||
|
||||
return NextResponse.json(updatedWithImage);
|
||||
} catch (error) {
|
||||
console.error('Failed to update dataset:', error);
|
||||
return NextResponse.json({ error: error.message || 'Failed to update dataset' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// 删除数据集
|
||||
export async function DELETE(request, { params }) {
|
||||
try {
|
||||
const { projectId, datasetId } = params;
|
||||
|
||||
// 验证数据集存在且属于该项目
|
||||
const dataset = await getImageDatasetById(datasetId);
|
||||
if (!dataset || dataset.projectId !== projectId) {
|
||||
return NextResponse.json({ error: 'Dataset not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
await deleteImageDataset(datasetId);
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Failed to delete dataset:', error);
|
||||
return NextResponse.json({ error: error.message || 'Failed to delete dataset' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getImageDatasetsForExport } from '@/lib/db/imageDatasets';
|
||||
import archiver from 'archiver';
|
||||
import { getProjectPath } from '@/lib/db/base';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
/**
|
||||
* 导出图片文件压缩包
|
||||
*/
|
||||
export async function GET(request, { params }) {
|
||||
try {
|
||||
const { projectId } = params;
|
||||
const { searchParams } = new URL(request.url);
|
||||
const confirmedOnly = searchParams.get('confirmedOnly') === 'true';
|
||||
|
||||
// 验证项目ID
|
||||
if (!projectId) {
|
||||
return NextResponse.json({ error: 'Project ID cannot be empty' }, { status: 400 });
|
||||
}
|
||||
|
||||
// 获取数据集(用于确定需要哪些图片)
|
||||
const datasets = await getImageDatasetsForExport(projectId, confirmedOnly);
|
||||
|
||||
if (!datasets || datasets.length === 0) {
|
||||
return NextResponse.json({ error: 'No data to export' }, { status: 404 });
|
||||
}
|
||||
|
||||
// 获取所有需要的图片名称
|
||||
const imageNames = new Set(datasets.map(d => d.imageName).filter(Boolean));
|
||||
|
||||
if (imageNames.size === 0) {
|
||||
return NextResponse.json({ error: 'No images to export' }, { status: 404 });
|
||||
}
|
||||
|
||||
// 创建压缩包
|
||||
const archive = archiver('zip', {
|
||||
zlib: { level: 9 }
|
||||
});
|
||||
|
||||
// 设置响应头
|
||||
const dateStr = new Date().toISOString().slice(0, 10);
|
||||
const filename = `images-${projectId}-${dateStr}.zip`;
|
||||
|
||||
// 添加图片文件到压缩包
|
||||
const projectPath = await getProjectPath(projectId);
|
||||
const imageDir = path.join(projectPath, 'images');
|
||||
|
||||
if (!fs.existsSync(imageDir)) {
|
||||
return NextResponse.json({ error: 'Image directory not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
let addedCount = 0;
|
||||
for (const imageName of imageNames) {
|
||||
const imagePath = path.join(imageDir, imageName);
|
||||
if (fs.existsSync(imagePath)) {
|
||||
archive.file(imagePath, { name: imageName });
|
||||
addedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (addedCount === 0) {
|
||||
return NextResponse.json({ error: 'No image files found' }, { status: 404 });
|
||||
}
|
||||
|
||||
// 完成压缩
|
||||
archive.finalize();
|
||||
|
||||
// 返回流式响应
|
||||
return new NextResponse(archive, {
|
||||
headers: {
|
||||
'Content-Type': 'application/zip',
|
||||
'Content-Disposition': `attachment; filename="${filename}"`
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to export images:', String(error));
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error.message || 'Failed to export images'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getImageDatasetsForExport } from '@/lib/db/imageDatasets';
|
||||
|
||||
/**
|
||||
* 导出图像数据集
|
||||
*/
|
||||
export async function POST(request, { params }) {
|
||||
try {
|
||||
const { projectId } = params;
|
||||
const body = await request.json();
|
||||
|
||||
// 验证项目ID
|
||||
if (!projectId) {
|
||||
return NextResponse.json({ error: 'Project ID cannot be empty' }, { status: 400 });
|
||||
}
|
||||
|
||||
const confirmedOnly = body.confirmedOnly || false;
|
||||
|
||||
// 获取数据集
|
||||
const datasets = await getImageDatasetsForExport(projectId, confirmedOnly);
|
||||
|
||||
return NextResponse.json(datasets);
|
||||
} catch (error) {
|
||||
console.error('Failed to export image datasets:', String(error));
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: error.message || 'Failed to export image datasets'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getImageDatasetsByProject } from '@/lib/db/imageDatasets';
|
||||
import { getProjectPath } from '@/lib/db/base';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
// 获取图片数据集列表
|
||||
export async function GET(request, { params }) {
|
||||
try {
|
||||
const { projectId } = params;
|
||||
const { searchParams } = new URL(request.url);
|
||||
|
||||
const page = parseInt(searchParams.get('page')) || 1;
|
||||
const pageSize = parseInt(searchParams.get('pageSize')) || 20;
|
||||
const search = searchParams.get('search') || '';
|
||||
const confirmed = searchParams.get('confirmed');
|
||||
const minScore = searchParams.get('minScore');
|
||||
const maxScore = searchParams.get('maxScore');
|
||||
|
||||
// 构建筛选条件
|
||||
const filters = {};
|
||||
if (search) {
|
||||
filters.search = search;
|
||||
}
|
||||
if (confirmed !== null && confirmed !== undefined) {
|
||||
filters.confirmed = confirmed === 'true';
|
||||
}
|
||||
if (minScore) {
|
||||
filters.minScore = parseInt(minScore);
|
||||
}
|
||||
if (maxScore) {
|
||||
filters.maxScore = parseInt(maxScore);
|
||||
}
|
||||
|
||||
const result = await getImageDatasetsByProject(projectId, page, pageSize, filters);
|
||||
|
||||
// 获取项目路径
|
||||
const projectPath = await getProjectPath(projectId);
|
||||
|
||||
// 为每个数据集添加图片 base64
|
||||
const datasetsWithImages = await Promise.all(
|
||||
result.data.map(async dataset => {
|
||||
try {
|
||||
const imagePath = path.join(projectPath, 'images', dataset.imageName);
|
||||
const imageBuffer = await fs.readFile(imagePath);
|
||||
const base64 = imageBuffer.toString('base64');
|
||||
const ext = path.extname(dataset.imageName).toLowerCase();
|
||||
const mimeType = ext === '.png' ? 'image/png' : ext === '.gif' ? 'image/gif' : 'image/jpeg';
|
||||
|
||||
return {
|
||||
...dataset,
|
||||
base64: `data:${mimeType};base64,${base64}`
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Failed to read image ${dataset.imageName}:`, error);
|
||||
return {
|
||||
...dataset,
|
||||
base64: null
|
||||
};
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
return NextResponse.json({
|
||||
data: datasetsWithImages,
|
||||
total: result.total
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to get image datasets:', error);
|
||||
return NextResponse.json({ error: error.message || 'Failed to get image datasets' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getImageDatasetsTagsByProject } from '@/lib/db/imageDatasets';
|
||||
|
||||
// 获取项目中所有已使用的标签
|
||||
export async function GET(request, { params }) {
|
||||
try {
|
||||
const { projectId } = params;
|
||||
|
||||
// 获取项目的所有数据集
|
||||
const datasets = await getImageDatasetsTagsByProject(projectId);
|
||||
|
||||
console.log('datasets', datasets);
|
||||
|
||||
// 提取所有标签
|
||||
const tagsSet = new Set();
|
||||
datasets.forEach(dataset => {
|
||||
if (dataset.tags) {
|
||||
try {
|
||||
const tags = JSON.parse(dataset.tags);
|
||||
if (Array.isArray(tags)) {
|
||||
tags.forEach(tag => tagsSet.add(tag));
|
||||
}
|
||||
} catch (e) {
|
||||
// 忽略解析错误
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 转换为数组并排序
|
||||
const tags = Array.from(tagsSet).sort();
|
||||
|
||||
return NextResponse.json({ tags });
|
||||
} catch (error) {
|
||||
console.error('Failed to get tags:', error);
|
||||
return NextResponse.json({ error: error.message || 'Failed to get tags' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user