109 lines
3.2 KiB
TypeScript
109 lines
3.2 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { auth } from "@/app/(auth)/auth";
|
|
import { getTripoProviderConfig } from "@/lib/tripo/server";
|
|
import { TripoApiError, tripoRequest } from "@/lib/tripo/client";
|
|
|
|
export const runtime = "nodejs";
|
|
export const maxDuration = 60;
|
|
|
|
const ALLOWED_IMAGE_TYPES = new Set(["image/png", "image/jpeg", "image/webp"]);
|
|
const MAX_UPLOAD_SIZE = 10 * 1024 * 1024;
|
|
|
|
function extractImageToken(data: unknown): string | null {
|
|
if (!data) return null;
|
|
if (typeof data === "string") return data.trim() || null;
|
|
if (typeof data !== "object") return null;
|
|
const record = data as Record<string, unknown>;
|
|
const tokenCandidates = [record.image_token, record.file_token, record.token];
|
|
for (const candidate of tokenCandidates) {
|
|
if (typeof candidate === "string" && candidate.trim()) {
|
|
return candidate.trim();
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export async function POST(request: Request) {
|
|
try {
|
|
const session = await auth();
|
|
if (!session?.user?.id) {
|
|
return NextResponse.json({ success: false, error: "未登录" }, { status: 401 });
|
|
}
|
|
|
|
const formData = await request.formData();
|
|
const file = formData.get("file");
|
|
if (!(file instanceof File)) {
|
|
return NextResponse.json({ success: false, error: "请上传图片文件" }, { status: 400 });
|
|
}
|
|
|
|
if (!ALLOWED_IMAGE_TYPES.has(file.type)) {
|
|
return NextResponse.json(
|
|
{ success: false, error: "仅支持 PNG/JPEG/WEBP 图片" },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
if (file.size <= 0 || file.size > MAX_UPLOAD_SIZE) {
|
|
return NextResponse.json(
|
|
{ success: false, error: "图片大小需在 1B~10MB 之间" },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
const config = await getTripoProviderConfig();
|
|
|
|
const uploadPaths = ["/upload/sts", "/upload"];
|
|
let lastError: unknown = null;
|
|
|
|
for (const path of uploadPaths) {
|
|
try {
|
|
const submitData = new FormData();
|
|
submitData.set("file", file, file.name || "upload.png");
|
|
const result = await tripoRequest<Record<string, unknown>>(config, {
|
|
method: "POST",
|
|
path,
|
|
formData: submitData,
|
|
});
|
|
const imageToken = extractImageToken(result.data);
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: {
|
|
imageToken,
|
|
file: result.data,
|
|
},
|
|
traceId: result.traceId,
|
|
});
|
|
} catch (error) {
|
|
lastError = error;
|
|
if (error instanceof TripoApiError && error.httpStatus === 404) {
|
|
continue;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
throw lastError instanceof Error ? lastError : new Error("图片上传失败");
|
|
} catch (error) {
|
|
if (error instanceof TripoApiError) {
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: error.message,
|
|
code: error.code,
|
|
suggestion: error.suggestion,
|
|
traceId: error.traceId,
|
|
},
|
|
{ status: error.httpStatus || 502 }
|
|
);
|
|
}
|
|
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: error instanceof Error ? error.message : "图片上传失败",
|
|
},
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|