139 lines
4.3 KiB
TypeScript
139 lines
4.3 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
||
import { getServerSession } from 'next-auth';
|
||
import { authOptions } from '@/lib/auth';
|
||
import { prisma } from '@/lib/prisma';
|
||
import {
|
||
createZipFromFiles,
|
||
generatePreviewImages,
|
||
cleanupTempFiles,
|
||
cleanupOnError,
|
||
saveAssets,
|
||
} from '@/lib/task-material-processor';
|
||
|
||
// POST - 完成AI原图上传
|
||
export async function POST(request: NextRequest) {
|
||
let materialId: string | null = null;
|
||
const tempFiles: string[] = []; // 需要清理的临时文件路径
|
||
let zipFilePath: string | null = null;
|
||
const uploadedPreviewUrls: string[] = []; // 新生成的S3预览图URLs
|
||
const uploadIds: string[] = []; // 需要清理的uploadId列表
|
||
|
||
try {
|
||
const session = await getServerSession(authOptions);
|
||
if (!session) {
|
||
return NextResponse.json({ error: '请先登录' }, { status: 401 });
|
||
}
|
||
|
||
const body = await request.json();
|
||
const { materialId: matId, assets } = body;
|
||
|
||
materialId = matId;
|
||
|
||
if (!materialId || !assets) {
|
||
return NextResponse.json(
|
||
{ error: '缺少必填字段' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
if (!assets.main || assets.main.length === 0) {
|
||
return NextResponse.json(
|
||
{ error: '至少需要上传一张原图' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
console.log('[AI Original Complete] Starting, materialId:', materialId);
|
||
console.log('[AI Original Complete] Original images count:', assets.main.length);
|
||
|
||
// 验证素材是否存在且属于当前用户
|
||
const material: any = await prisma.material.findUnique({
|
||
where: { id: materialId },
|
||
});
|
||
|
||
if (!material) {
|
||
return NextResponse.json(
|
||
{ success: false, error: '素材不存在' },
|
||
{ status: 404 }
|
||
);
|
||
}
|
||
|
||
if (material.userId !== (session.user as any).id) {
|
||
return NextResponse.json(
|
||
{ success: false, error: '无权限操作此素材' },
|
||
{ status: 403 }
|
||
);
|
||
}
|
||
|
||
// 步骤1: 从chunk临时目录读取原图文件
|
||
console.log(`[AI Original] Processing ${assets.main.length} original images...`);
|
||
|
||
const { getUploadedFile } = await import('@/lib/upload-sessions');
|
||
const originalFiles: Array<{ path: string; name: string; size: number }> = [];
|
||
|
||
for (const asset of assets.main) {
|
||
try {
|
||
const filePath = await getUploadedFile(asset.uploadId);
|
||
if (filePath) {
|
||
originalFiles.push({
|
||
path: filePath,
|
||
name: asset.fileName,
|
||
size: asset.fileSize,
|
||
});
|
||
tempFiles.push(filePath);
|
||
uploadIds.push(asset.uploadId);
|
||
} else {
|
||
throw new Error(`找不到uploadId对应的文件: ${asset.uploadId}`);
|
||
}
|
||
} catch (error) {
|
||
console.error(`[AI Original] Failed to get file for uploadId ${asset.uploadId}:`, error);
|
||
throw new Error(`获取原图文件失败: ${asset.fileName}`);
|
||
}
|
||
}
|
||
|
||
// 步骤2: 打包原图成zip(保存到本地文件系统)
|
||
console.log(`[AI Original] Creating zip from ${originalFiles.length} original files...`);
|
||
const zipInfo = await createZipFromFiles(
|
||
originalFiles,
|
||
materialId!,
|
||
material.productModel || 'ai-original',
|
||
'任务-AI原图'
|
||
);
|
||
console.log(`[AI Original] Zip created: ${zipInfo.fileName} (${zipInfo.fileSize} bytes)`);
|
||
zipFilePath = zipInfo.filePath;
|
||
|
||
// 步骤3: 生成预览图并上传到S3
|
||
const previewUrls = await generatePreviewImages(
|
||
assets.main.map((a: any) => ({ uploadId: a.uploadId, fileName: a.fileName })),
|
||
'任务-AI原图'
|
||
);
|
||
uploadedPreviewUrls.push(...previewUrls);
|
||
|
||
if (uploadedPreviewUrls.length === 0) {
|
||
throw new Error('生成预览图失败,至少需要一张预览图');
|
||
}
|
||
|
||
// 步骤4: 保存资产记录到数据库
|
||
await saveAssets(materialId!, uploadedPreviewUrls, zipInfo);
|
||
|
||
// 步骤5: 清理临时文件
|
||
await cleanupTempFiles(tempFiles, uploadIds);
|
||
|
||
console.log('[AI Original] Complete success!');
|
||
return NextResponse.json({
|
||
success: true,
|
||
materialId,
|
||
});
|
||
} catch (error: any) {
|
||
console.error('[AI Original Complete Error]', error);
|
||
|
||
// 清理失败时的资源
|
||
await cleanupOnError(uploadedPreviewUrls, zipFilePath, tempFiles, materialId);
|
||
|
||
return NextResponse.json(
|
||
{ error: error.message || '完成上传失败' },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|