import { SEEDANCE_25_MODEL } from "@/lib/video-settings"; export type VideoInputEngine = "seedance" | "minimax" | "bailian"; export type VideoInputMode = "reference" | "frames"; export type VideoMaterialKind = "image" | "video" | "audio"; export const BAILIAN_27_VIDEO_MODEL = "wan2.7-i2v-2026-04-25"; export const BAILIAN_30_VIDEO_MODEL = "wan3.0-video"; export const BAILIAN_VIDEO_MODELS = [ { id: BAILIAN_27_VIDEO_MODEL, label: "Wan 2.7 · 首尾帧" }, { id: BAILIAN_30_VIDEO_MODEL, label: "Wan 3.0 · 多图参考" } ] as const; export type VideoInputSelection = { engine: VideoInputEngine; model: string; inputMode: VideoInputMode; }; export function videoInputHint(selection: VideoInputSelection): string { if (selection.engine === "seedance") { return selection.model === SEEDANCE_25_MODEL ? "多素材参考:最多 30 张图片、10 段视频、10 段音频,总计 50 个。可在提示词中用 @图片1 等编号指定用途。" : "多素材参考:最多 9 张图片、3 段视频、3 段音频;音频需要搭配图片或视频。可用 @图片1 等编号指定用途。"; } if (selection.engine === "minimax") { return selection.inputMode === "frames" ? "首帧模式:可不上传图片,或上传 1 张图片固定视频开头;有首帧时比例跟随图片。若想用多张图共同指导内容,请切换到「多图参考」。" : "多图参考:最多 9 张图片。图片用于指导人物、服装或场景,不会被固定为视频首帧;可在提示词中引用 @图片1 等编号。"; } if (selection.model === BAILIAN_27_VIDEO_MODEL) { return "Wan 2.7 首尾帧:上传 1 张图片作为首帧,或按顺序上传 2 张作为首帧和尾帧。多图参考请切换到 Wan 3.0。"; } return selection.inputMode === "frames" ? "首尾帧:上传 1 张首帧图,或按顺序上传 2 张首尾帧图。若想让更多图片共同指导内容,请切换到「多图参考」。" : "多图参考:可只输入文字,或上传最多 10 张图片指导人物、服装和场景;参考图不会固定为首尾帧,可在提示词中引用 @图片1 等编号。"; } export function videoMaterialError(selection: VideoInputSelection, materials: readonly { type: VideoMaterialKind }[]): string | null { const imageCount = materials.filter((item) => item.type === "image").length; const videoCount = materials.filter((item) => item.type === "video").length; const audioCount = materials.filter((item) => item.type === "audio").length; if (selection.engine === "seedance") { const is25 = selection.model === SEEDANCE_25_MODEL; const maxImages = is25 ? 30 : 9; const maxVideo = is25 ? 10 : 3; const maxAudio = is25 ? 10 : 3; if (imageCount > maxImages || videoCount > maxVideo || audioCount > maxAudio || is25 && materials.length > 50) { return `${is25 ? "Seedance 2.5" : "Seedance 2.0"} 最多支持 ${maxImages} 张图片、${maxVideo} 段视频、${maxAudio} 段音频${is25 ? ",总计 50 个素材" : ""};请移除超出的素材。`; } if (!is25 && audioCount > 0 && imageCount + videoCount === 0) { return "Seedance 2.0 的音频不能单独生成视频;请添加至少 1 张图片或 1 段视频,或切换到 Seedance 2.5。"; } return null; } if (selection.engine === "minimax") { if (videoCount || audioCount) return "MiniMax H3 当前只接受图片素材;请移除视频和音频,或切换到 Seedance。"; if (selection.inputMode === "frames" && imageCount > 1) { return "MiniMax H3 首帧模式最多只能上传 1 张图;请切换到「多图参考」或移除多余图片。"; } if (selection.inputMode === "reference" && imageCount > 9) { return "MiniMax H3 多图参考最多支持 9 张图片;请移除多余图片。"; } return null; } if (videoCount || audioCount) return "百炼当前只接受图片素材;请移除视频和音频,或切换到 Seedance。"; if (selection.model === BAILIAN_27_VIDEO_MODEL || selection.inputMode === "frames") { if (!imageCount) return "首尾帧模式需要至少 1 张图片作为首帧;请上传图片,或切换到 Wan 3.0 多图参考。"; if (imageCount > 2) return "首尾帧模式最多支持 2 张图片;请切换到 Wan 3.0 多图参考,或移除多余图片。"; return null; } if (imageCount > 10) return "Wan 3.0 多图参考最多支持 10 张图片;请移除多余图片。"; return null; } export function videoImageFileError(selection: VideoInputSelection, file: Pick): string | null { if (selection.engine === "seedance" || selection.engine === "bailian" && selection.model === BAILIAN_27_VIDEO_MODEL) return null; const format = file.name.split(".").pop()?.toLowerCase() || file.type.split("/").pop()?.toLowerCase() || ""; const isMinimax = selection.engine === "minimax"; const formats = isMinimax ? ["jpg", "jpeg", "png", "webp", "heic", "heif"] : ["jpg", "jpeg", "png", "bmp", "webp"]; const maxBytes = (isMinimax ? 30 : 20) * 1024 * 1024; const modelLabel = isMinimax ? "MiniMax H3" : "Wan 3.0"; if (!formats.includes(format)) { return `${modelLabel} 不支持「${file.name}」的格式;请转换为 ${isMinimax ? "JPG、PNG、WEBP、HEIC 或 HEIF" : "JPG、PNG、BMP 或 WEBP"} 后上传。`; } if (file.size > maxBytes) return `${modelLabel} 的单张图片不能超过 ${isMinimax ? 30 : 20} MB;请压缩「${file.name}」后重试。`; return null; }