"use client"; import { useState } from "react"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; import { Badge } from "@/components/ui/badge"; import { Separator } from "@/components/ui/separator"; import { Video, Check, ChevronDown, ChevronUp, Sparkles, Camera, Clock, Settings2, Maximize2, Ratio, } from "lucide-react"; import { cn } from "@/lib/utils"; // 视频生成模式类型 type VideoGenerationMode = | "text-to-video" | "first-frame" | "first-last-frame" | "reference-images"; // 运镜模式类型(与官方一致) type CameraMove = | "none" // 智能运镜 | "static" // 固定镜头 | "hitchcock-push" // 希区柯克推进 | "hitchcock-pull" // 希区柯克拉远 | "mechanical-arm" // 机械臂 | "dynamic-orbit" // 动感环绕 | "center-orbit" // 中心环绕 | "crane" // 起重机 | "super-pull" // 超级拉远 | "ccw-rotate" // 逆时针回旋 | "cw-rotate" // 顺时针回旋 | "handheld" // 手持运镜 | "fast-push-pull"; // 快速推拉 // 视频参数接口 export interface VideoGenerationParams { mode: VideoGenerationMode; resolution: "480p" | "720p" | "1080p"; ratio: "16:9" | "4:3" | "1:1" | "3:4" | "9:16" | "21:9" | "adaptive"; duration: number; watermark: boolean; cameraFixed: boolean; cameraMove?: CameraMove; // 新增:运镜模式 fps?: number; seed?: number; returnLastFrame?: boolean; } interface VideoParamsBarProps { modelName?: string; initialParams?: Partial; onParamsChange?: (params: VideoGenerationParams) => void; inline?: boolean; // 内联模式:只显示参数按钮,不显示外层容器 } const MODE_LABELS: Record = { "text-to-video": "文生视频", "first-last-frame": "首尾帧", "reference-images": "智能多帧", "first-frame": "主体参考", }; const RATIO_OPTIONS = [ { value: "21:9", label: "21:9" }, { value: "16:9", label: "16:9" }, { value: "4:3", label: "4:3" }, { value: "1:1", label: "1:1" }, { value: "3:4", label: "3:4" }, { value: "9:16", label: "9:16" }, ] as const; const RESOLUTION_OPTIONS = [ { value: "480p", label: "480P" }, { value: "720p", label: "720P" }, { value: "1080p", label: "1080P" }, ] as const; // 🎬 运镜模式选项(与官方一致) const CAMERA_MOVE_OPTIONS = [ { value: "none", label: "智能运镜" }, { value: "static", label: "固定镜头" }, { value: "hitchcock-push", label: "希区柯克推进" }, { value: "hitchcock-pull", label: "希区柯克拉远" }, { value: "mechanical-arm", label: "机械臂" }, { value: "dynamic-orbit", label: "动感环绕" }, { value: "center-orbit", label: "中心环绕" }, { value: "crane", label: "起重机" }, { value: "super-pull", label: "超级拉远" }, { value: "ccw-rotate", label: "逆时针回旋" }, { value: "cw-rotate", label: "顺时针回旋" }, { value: "handheld", label: "手持运镜" }, { value: "fast-push-pull", label: "快速推拉" }, ] as const; // 帧率选项 const FPS_OPTIONS = [ { value: 24, label: "24fps" }, { value: 30, label: "30fps" }, { value: 60, label: "60fps" }, ] as const; export function VideoParamsBar({ modelName = "视频 3.0", initialParams, onParamsChange, inline = false, }: VideoParamsBarProps) { const [params, setParams] = useState({ mode: "text-to-video", resolution: "720p", ratio: "16:9", duration: 5, watermark: false, // 默认关闭水印 cameraFixed: false, cameraMove: "none", fps: 24, ...initialParams, }); const [collapsed, setCollapsed] = useState(false); // 获取当前运镜模式的标签 const getCurrentCameraLabel = () => { if (params.cameraMove) { const option = CAMERA_MOVE_OPTIONS.find(opt => opt.value === params.cameraMove); return option ? option.label : "智能运镜"; } return "智能运镜"; }; // 🆕 根据模式获取图片上传配置(根据火山引擎官方文档) const getImageUploadConfig = () => { switch (params.mode) { case "text-to-video": return { min: 0, max: 0, label: "文生视频(无需图片)" }; case "first-last-frame": return { min: 2, max: 2, label: "首尾帧(各 1 张)" }; case "first-frame": return { min: 1, max: 1, label: "首帧模式(1 张)" }; case "reference-images": return { min: 1, max: 4, label: "参考图(1-4 张)" }; default: return { min: 0, max: 0, label: "" }; } }; const imageConfig = getImageUploadConfig(); const updateParam = ( key: K, value: VideoGenerationParams[K] ) => { const newParams = { ...params, [key]: value }; setParams(newParams); onParamsChange?.(newParams); }; // 🆕 内联模式:只返回参数按钮,嵌入工具栏 if (inline) { return (
{/* 模式选择 */} updateParam("mode", "text-to-video")}> 文生视频 updateParam("mode", "first-last-frame")}> 首尾帧 updateParam("mode", "reference-images")}> 智能多帧 updateParam("mode", "first-frame")}> 主体参考 {/* 宽高比 */}
{RATIO_OPTIONS.map((option) => ( ))}
{/* 分辨率 */} {RESOLUTION_OPTIONS.map((option) => ( updateParam("resolution", option.value)}> {option.label} ))} {/* 时长 */} {[5, 10].map((duration) => ( updateParam("duration", duration)}> {duration}s ))} {/* 帧率 */} {FPS_OPTIONS.map((option) => ( updateParam("fps", option.value as VideoGenerationParams["fps"])}> {option.label} ))} {/* 运镜(改为下拉菜单,和其他按钮一致) */} {CAMERA_MOVE_OPTIONS.map((option) => ( { updateParam("cameraMove", option.value); updateParam("cameraFixed", option.value === "static"); }} > {option.label} ))} {/* 高级设置 */} 高级设置
updateParam("returnLastFrame", checked)} />
updateParam("seed", Number(e.target.value) || undefined)} className="h-8 text-xs" />
); } // 非内联模式(独立显示) if (collapsed) { return (
视频参数:{MODE_LABELS[params.mode]} | {params.ratio} | {params.resolution} | {params.duration}s
); } return (
{/* 🆕 图片上传区域(根据模式动态显示) */} {imageConfig.max > 0 && (
{params.mode === "first-last-frame" && (
)} {params.mode === "first-frame" && ( )} {params.mode === "reference-images" && (
{[1, 2, 3, 4].slice(0, imageConfig.max).map((idx) => ( ))}
)}
)} {/* 参数配置栏 - 移除背景色和顶部边框,适应嵌入式布局 */}
{/* 模式选择(无边框,更简洁) */} updateParam("mode", "text-to-video")}> 文生视频 updateParam("mode", "first-last-frame")}> 首尾帧 updateParam("mode", "first-frame")}> 智能多帧 updateParam("mode", "reference-images")}> 主体参考 {/* 宽高比 */}
{RATIO_OPTIONS.map((option) => ( ))}
{/* 分辨率 */} {RESOLUTION_OPTIONS.map((option) => ( updateParam("resolution", option.value)}> {option.label} ))} {/* 时长 */} {[5, 10].map((duration) => ( updateParam("duration", duration)}> {duration}s ))} {/* 帧率 (新增) */} {FPS_OPTIONS.map((option) => ( updateParam("fps", option.value as VideoGenerationParams["fps"])} > {option.label} ))} {/* 运镜(改为下拉菜单,与官方一致) */} {CAMERA_MOVE_OPTIONS.map((option) => ( { updateParam("cameraMove", option.value); updateParam("cameraFixed", option.value === "static"); }} > {option.label} ))}
{/* 高级选项(隐藏水印,默认关闭) */} 高级设置
updateParam("returnLastFrame", checked)} className="scale-75" />
updateParam("seed", Number(e.target.value) || undefined) } className="h-8 text-xs" />
); }