import { NextResponse } from "next/server"; import { auth } from "@/app/(auth)/auth"; import { createCanvasImageTask, enqueueCanvasImageTask, } from "@/lib/canvas/image-task-queue"; import { getPointsSystemConfig } from "@/lib/db/queries"; import { prepareFeaturePointsCharge } from "@/lib/points/feature-charge"; import { getImageToolCreditCost } from "@/lib/points/config"; import type { CanvasLayoutReplaceTaskRequest } from "@/lib/canvas/layout-replace-task"; export const maxDuration = 1200; function normalizeHttpUrl(value: unknown) { const url = String(value || "").trim(); return /^https?:\/\//i.test(url) ? url : ""; } function normalizeUuid(value: unknown) { const uuid = String(value || "").trim(); return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(uuid) ? uuid : undefined; } export async function POST(request: Request) { try { const session = await auth(); if (!session?.user?.id) { return NextResponse.json( { success: false, error: "未登录" }, { status: 401 }, ); } const body = await request.json().catch(() => ({})); const sourceImageUrl = normalizeHttpUrl(body?.sourceImageUrl); const referenceImageUrl = normalizeHttpUrl(body?.referenceImageUrl); if (!sourceImageUrl) { return NextResponse.json( { success: false, error: "缺少当前产品图片" }, { status: 400 }, ); } if (!referenceImageUrl) { return NextResponse.json( { success: false, error: "缺少排版参考图" }, { status: 400 }, ); } const pointsConfig = await getPointsSystemConfig(); const pointsCharge = await prepareFeaturePointsCharge({ userId: session.user.id, unitCost: getImageToolCreditCost(pointsConfig, "repaint"), reason: "image_repaint", modelId: "canvas-layout-replace", note: "排版替换消耗积分", pointsConfig, }); if (!pointsCharge.ok) { return NextResponse.json(pointsCharge.payload, { status: pointsCharge.status, }); } const taskRequest: CanvasLayoutReplaceTaskRequest = { taskKind: "canvas-layout-replace", sourceImageUrl, referenceImageUrl, supplementalPrompt: typeof body?.supplementalPrompt === "string" ? body.supplementalPrompt : undefined, model: typeof body?.model === "string" ? body.model : undefined, imageSize: typeof body?.imageSize === "string" && body.imageSize.trim() ? body.imageSize.trim() : "2K", sourceNodeId: typeof body?.sourceNodeId === "string" ? body.sourceNodeId : undefined, agentProjectId: normalizeUuid(body?.agentProjectId), referenceLabel: typeof body?.referenceLabel === "string" ? body.referenceLabel : undefined, debugMeta: body?.debugMeta && typeof body.debugMeta === "object" && !Array.isArray(body.debugMeta) ? body.debugMeta : undefined, }; const task = await createCanvasImageTask({ userId: session.user.id, request: taskRequest as unknown as Record, }); await enqueueCanvasImageTask(task.id); if (pointsCharge.chargeable) { try { await pointsCharge.consume({ note: `排版替换消耗积分(${task.id})`, }); } catch (pointsError) { console.error("[Points] Failed to consume canvas layout replace points:", pointsError); } } return NextResponse.json({ success: true, taskId: task.id, status: task.status, }); } catch (error) { console.error("[Canvas Layout Replace] Error:", error); return NextResponse.json( { success: false, error: error instanceof Error ? error.message : "排版替换提交失败", }, { status: 500 }, ); } }