import { NextResponse } from "next/server"; import { auth } from "@/app/(auth)/auth"; import { executeDirectVideoGeneration } from "@/lib/ai/tools/generate-video"; import { filterReachableRemoteUrls } from "@/lib/net/url-access"; import type { VideoGenerationMode, VideoRatio, VideoResolution } from "@/types/ai"; export const maxDuration = 300; interface GenerateVideoRequest { prompt?: string; mode?: VideoGenerationMode; images?: string[]; resolution?: VideoResolution; ratio?: VideoRatio; duration?: number; watermark?: boolean; cameraFixed?: boolean; seed?: number; returnLastFrame?: boolean; preferredModelRef?: string; } function inferMode(images: string[]): VideoGenerationMode { if (images.length >= 3) return "reference-images"; if (images.length >= 2) return "first-last-frame"; if (images.length === 1) return "first-frame"; return "text-to-video"; } 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(() => ({}))) as GenerateVideoRequest; const prompt = String(body.prompt || "").trim(); if (!prompt) { return NextResponse.json( { success: false, error: "请输入视频提示词" }, { status: 400 } ); } const inputImages = Array.isArray(body.images) ? body.images.map((item) => String(item || "").trim()).filter(Boolean).slice(0, 4) : []; const { kept: reachableImages, dropped: unreachableImages } = await filterReachableRemoteUrls(inputImages, { timeoutMs: 3000 }); if (inputImages.length > 0 && reachableImages.length === 0) { return NextResponse.json( { success: false, error: "参考图片链接不可访问,请重新上传后再试" }, { status: 400 } ); } const mode = body.mode || inferMode(reachableImages); const result = await executeDirectVideoGeneration({ prompt, mode, images: reachableImages, resolution: body.resolution, ratio: body.ratio, duration: typeof body.duration === "number" && Number.isFinite(body.duration) ? body.duration : undefined, watermark: body.watermark, cameraFixed: body.cameraFixed, seed: typeof body.seed === "number" && Number.isFinite(body.seed) ? body.seed : undefined, returnLastFrame: body.returnLastFrame, preferredModelRef: typeof body.preferredModelRef === "string" ? body.preferredModelRef : undefined, }); if (!result.success || !result.videoUrl) { return NextResponse.json( { success: false, error: "视频生成失败,请稍后重试" }, { status: 502 } ); } return NextResponse.json({ success: true, data: { url: result.videoUrl, metadata: result.metadata || null, modelDisplayName: result.modelDisplayName, modelId: result.modelId, modelRef: result.modelRef, mode, images: reachableImages, droppedImages: unreachableImages, }, }); } catch (error) { console.error("[Canvas Generate Video] Error:", error); return NextResponse.json( { success: false, error: error instanceof Error ? error.message : "生成视频失败", }, { status: 500 } ); } }