import { getServerSideConfig } from "@/app/config/server"; import type { CreateTaskResponse, GetTaskResponse, GetGenerateTaskResponse, LocalData, } from "../types/zuotang"; import { NextRequest, NextResponse } from "next/server"; import md5 from "spark-md5"; // 类型守卫函数 function isString(value: unknown): value is string { return typeof value === "string"; } // 统一错误响应生成器 function createErrorResponse( message: string, status: number, maxDailyUses?: number, ): NextResponse<CreateTaskResponse> { const response: CreateTaskResponse = { status, message, data: { task_id: "" }, maxDailyUses, }; return NextResponse.json(response, { status, headers: { "Content-Type": "application/json" }, }); } // 处理每日使用限制逻辑 function parseDailyUsage(allowNum: string, configMax: number): number { if (allowNum === "first") return configMax; const parsed = parseInt(allowNum, 10); return Number.isNaN(parsed) ? configMax : parsed; } export async function handle( req: NextRequest, { params }: { params: { path: string[] } }, ) { const config = getServerSideConfig(); const baseUrl = config.bgRemovalUrl; const subPath = params.path.join("/"); const reqUrl = `${baseUrl}/api/tasks/${subPath}`; try { if (req.method === "POST") { const formData = await req.formData(); // 验证访问码 const accessCode = formData.get("accessCode"); if (!isString(accessCode) || !config.codes.has(md5.hash(accessCode))) { return createErrorResponse("无效访问密码!", 401); } // 解析使用限制数据 const localData = formData.get("localData"); if (!isString(localData)) { return createErrorResponse("无效请求参数", 400); } const localDataObj: LocalData = JSON.parse(localData); if (!localDataObj.maxDailyUses) { return createErrorResponse("缺少请求参数", 400); } const maxDailyUses = parseDailyUsage( localDataObj.maxDailyUses, config.maxDailyUses, ); if (maxDailyUses <= 0) { return createErrorResponse("今日次数已用完!", 429, 0); } // 准备API请求 const imageFile = formData.get("image_url"); if (!imageFile) { return createErrorResponse("缺少请求参数", 400); } const headers = new Headers({ "X-API-KEY": config.bgRemovalApiKey }); const newFormData = new FormData(); newFormData.append("image_url", imageFile); if (subPath === "visual/r-background") { newFormData.append("batch_size", "1"); const prompt = formData.get("prompt") as string; const trimmedPrompt = prompt ? prompt.trim() : null; if (!trimmedPrompt) { return createErrorResponse("背景提示词不能为空!", 400); } newFormData.append("prompt", trimmedPrompt); } const response = await fetch(reqUrl, { headers, method: "POST", body: newFormData, }); if (!response.ok) { throw new Error(`API请求失败: ${response.statusText}`); } const responseData: CreateTaskResponse = await response.json(); responseData.maxDailyUses = maxDailyUses - 1; return NextResponse.json(responseData, { status: response.status, headers: { "Content-Type": "application/json" }, }); } else if (req.method === "GET") { const headers = { "X-API-KEY": config.bgRemovalApiKey }; const response = await fetch(reqUrl, { headers }); if (!response.ok) { throw new Error(`API请求失败: ${response.statusText}`); } const isVisualRoute = subPath.includes("visual/r-background"); const responseData = isVisualRoute ? ((await response.json()) as GetTaskResponse) : ((await response.json()) as GetGenerateTaskResponse); return NextResponse.json(responseData, { status: response.status, headers: { "Content-Type": "application/json" }, }); } return createErrorResponse("方法不允许", 405); } catch (error) { console.error("请求处理错误:", error); return createErrorResponse( error instanceof Error ? error.message : "服务器内部错误", 500, ); } }