import { NextResponse } from "next/server"; import { z } from "zod"; import { auth } from "@/app/(auth)/auth"; import { createCanvasImageTask, enqueueCanvasImageTask, getCanvasImageTaskForUser, } from "@/lib/canvas/image-task-queue"; import { type CanvasGenerateImageRequest } from "@/lib/canvas/generate-image"; import { getModelGenerationCreditCost } from "@/lib/ai/image-model-pricing"; import { prepareFeaturePointsCharge } from "@/lib/points/feature-charge"; import { findStyleProImageModelByRef, getStyleProImageModelEntries, } from "@/lib/style-pro/model-options"; import { getAiModelFrontendAvailability } from "@/lib/ai/model-frontend-availability"; const requestSchema = z.object({ prompt: z.string().min(1).max(5000), referenceImage: z.string().min(1).max(200000), selectedModelId: z.string().min(1).max(128), imageSize: z.string().min(1).max(16).optional(), promptExtend: z.boolean().optional(), aspectRatio: z.string().min(1).max(16).optional(), title: z.string().max(128).optional(), }); export const dynamic = "force-dynamic"; export const maxDuration = 120; 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 = requestSchema.parse(await request.json()); const imageModelEntries = await getStyleProImageModelEntries({ includeHidden: true, }); const selectedModel = findStyleProImageModelByRef( imageModelEntries, body.selectedModelId ); if (!selectedModel) { return NextResponse.json( { success: false, error: "所选 AI洗图 生图模型不可用" }, { status: 400 } ); } const availability = getAiModelFrontendAvailability(selectedModel.model); if (availability.selectable === false) { return NextResponse.json( { success: false, error: availability.disabledReason || "所选 AI洗图 生图模型当前不可用", }, { status: 400 } ); } const imageSize = body.imageSize?.trim() || "2K"; const unitCost = getModelGenerationCreditCost(selectedModel.model as any, "image", { imageSize, }); const pointsCharge = await prepareFeaturePointsCharge({ userId: session.user.id, unitCost, reason: "ai_wash_generation", modelId: selectedModel.model.id, note: `AI洗图消耗积分(${body.title || selectedModel.model.displayName})`, }); if (!pointsCharge.ok) { return NextResponse.json(pointsCharge.payload, { status: pointsCharge.status, }); } const payload: CanvasGenerateImageRequest = { prompt: body.prompt.trim(), model: selectedModel.model.id, referenceImage: body.referenceImage.trim(), imageSize, imageCount: 1, promptExtend: body.promptExtend === true, aspectRatio: body.aspectRatio?.trim() || "auto", ownerKey: session.user.id, debugLabel: "ai-wash", debugMeta: { selectedModelId: selectedModel.model.id, selectedModelName: selectedModel.model.displayName, title: body.title || "", }, }; const task = await createCanvasImageTask({ userId: session.user.id, request: payload as unknown as Record, }); await enqueueCanvasImageTask(task.id); const currentTask = await getCanvasImageTaskForUser({ taskId: task.id, userId: session.user.id, }); if (pointsCharge.chargeable) { try { await pointsCharge.consume({ note: `AI洗图消耗积分(${body.title || selectedModel.model.displayName} / ${task.id})`, }); } catch (pointsError) { console.error("[AI Wash] Failed to consume points:", pointsError); } } return NextResponse.json({ success: true, taskId: task.id, status: currentTask?.status || task.status, queueStatus: currentTask?.queueStatus, unitCost, modelId: selectedModel.model.id, modelName: selectedModel.model.displayName, }); } catch (error) { console.error("[AI Wash Generate] Failed:", error); if (error instanceof z.ZodError) { return NextResponse.json( { success: false, error: error.issues[0]?.message || "请求参数错误" }, { status: 400 } ); } return NextResponse.json( { success: false, error: error instanceof Error ? error.message : "AI洗图失败" }, { status: 500 } ); } }