测试视频复刻
This commit is contained in:
@@ -23,7 +23,6 @@ import { OverlayPortal, useBodyScrollLock } from "../components/overlays";
|
||||
import { useFileDrop } from "../components/use-file-drop";
|
||||
import {
|
||||
DEFAULT_BILLING_RATES,
|
||||
FC_MODELS,
|
||||
IMAGE_TYPES,
|
||||
MAX_IMAGES,
|
||||
checkRefFile,
|
||||
@@ -38,11 +37,11 @@ const JOB_KEY = "airshelf:video-replace-job";
|
||||
const MODE_KEY = "airshelf:video-replace-mode";
|
||||
const CHARACTER_MARK = "[视频复刻·角色]";
|
||||
const VIDEO_ACCEPT = "video/mp4,video/quicktime";
|
||||
// 复刻(商品 / 角色)统一走 Seedance 2.5,单次能出 30 秒,参考视频也按 30 秒收口。
|
||||
// 复刻固定 Seedance 2.5:参考视频只用来提炼分镜稿,成片最长 30 秒。
|
||||
const REPLACE_SEEDANCE_MODEL = "doubao-seedance-2-5-260628";
|
||||
const PRODUCT_SOURCE_PURPOSE = "video_replace_product";
|
||||
const REF_SECONDS_MAX = { product: 30, character: 30 } as const;
|
||||
const REF_BYTES_MAX = { product: 200 * 1024 * 1024, character: 200 * 1024 * 1024 } as const;
|
||||
// Seedance 2.5 单次出片上限。参考视频更长时不报错,成片按这个截断。
|
||||
const SEEDANCE_MAX_OUTPUT_SECONDS = 30;
|
||||
|
||||
type ProductSource = "library" | "temporary" | "";
|
||||
@@ -54,7 +53,7 @@ const REPLACE_MODE_COPY = {
|
||||
targetLabel: "商品",
|
||||
targetStep: "2. 选择自己的商品",
|
||||
videoEmpty: "系统会先把参考视频拆成分镜稿,再照着它换成你的商品",
|
||||
videoReady: "视频已就绪,将先提炼分镜稿再逐镜复刻",
|
||||
videoReady: "视频已就绪,将先提炼分镜稿再出片",
|
||||
libraryTitle: "从商品库选择",
|
||||
libraryEmpty: "选择已创建的商品",
|
||||
temporaryTitle: "临时上传素材",
|
||||
@@ -62,7 +61,7 @@ const REPLACE_MODE_COPY = {
|
||||
temporaryNoun: "商品图",
|
||||
temporaryFallback: "临时商品素材",
|
||||
generatingTitle: "正在进行商品复刻",
|
||||
generatingCopy: "正在按分镜一镜一镜还原,并换上你的商品",
|
||||
generatingCopy: "正在按分镜稿出片,并换上你的商品",
|
||||
reviewingTitle: "正在审核参考素材",
|
||||
reviewingCopy: "参考图需先通过合规审核,通过后自动开始复刻",
|
||||
digestingTitle: "正在提炼参考视频",
|
||||
@@ -81,7 +80,7 @@ const REPLACE_MODE_COPY = {
|
||||
targetLabel: "角色",
|
||||
targetStep: "2. 选择自己的角色",
|
||||
videoEmpty: "系统会先把参考视频拆成分镜稿,再照着它换成你的角色",
|
||||
videoReady: "视频已就绪,将先提炼分镜稿再逐镜复刻",
|
||||
videoReady: "视频已就绪,将先提炼分镜稿再出片",
|
||||
libraryTitle: "从人物库选择",
|
||||
libraryEmpty: "选择已创建的人物",
|
||||
temporaryTitle: "临时上传角色",
|
||||
@@ -89,7 +88,7 @@ const REPLACE_MODE_COPY = {
|
||||
temporaryNoun: "角色参考图",
|
||||
temporaryFallback: "临时角色素材",
|
||||
generatingTitle: "正在进行角色复刻",
|
||||
generatingCopy: "正在按分镜一镜一镜还原,并换上你的角色",
|
||||
generatingCopy: "正在按分镜稿出片,并换上你的角色",
|
||||
reviewingTitle: "正在审核参考素材",
|
||||
reviewingCopy: "参考图需先通过合规审核,通过后自动开始复刻",
|
||||
digestingTitle: "正在提炼参考视频",
|
||||
@@ -178,7 +177,6 @@ function formatClock(seconds: number) {
|
||||
|
||||
function clampDuration(seconds: number) {
|
||||
const rounded = Math.round(Number(seconds) || SEEDANCE_MAX_OUTPUT_SECONDS);
|
||||
// 60 秒参考视频不是错误:成片取火山能出的最长,分镜稿由模型压缩改编。
|
||||
return Math.min(SEEDANCE_MAX_OUTPUT_SECONDS, Math.max(4, rounded || SEEDANCE_MAX_OUTPUT_SECONDS));
|
||||
}
|
||||
|
||||
@@ -326,7 +324,7 @@ export function VideoReplacePage({
|
||||
[modelConfigs],
|
||||
);
|
||||
const preferredModel = useMemo(
|
||||
() => videoConfigs.find((config) => config.name === FC_MODELS[0].name) || videoConfigs[0],
|
||||
() => videoConfigs.find((config) => config.name === REPLACE_SEEDANCE_MODEL) || videoConfigs[0],
|
||||
[videoConfigs],
|
||||
);
|
||||
|
||||
@@ -359,7 +357,7 @@ export function VideoReplacePage({
|
||||
name: item.label || `${copy.temporaryNoun}${index + 1}`,
|
||||
}));
|
||||
const aspectRatio = ratioFromSize(videoMeta.width, videoMeta.height);
|
||||
const outputDuration = clampDuration(videoMeta.duration || 15);
|
||||
const outputDuration = clampDuration(videoMeta.duration || SEEDANCE_MAX_OUTPUT_SECONDS);
|
||||
const estimated = estimateCost(preferredModel, {
|
||||
ratio: aspectRatio,
|
||||
resolution: "720p",
|
||||
@@ -620,8 +618,7 @@ export function VideoReplacePage({
|
||||
|
||||
const switchReplaceMode = (next: ReplaceMode) => {
|
||||
if (next === replaceMode || generating) return;
|
||||
// 商品复刻能传 60 秒,角色复刻只能 15 秒。带着超长视频切过去会一路走到提交才报错,
|
||||
// 这里直接清掉并说明原因。
|
||||
// 两种模式都按 30 秒收口。带着超长视频切过去会一路走到提交才报错,这里直接清掉。
|
||||
const tooLongForNext = (videoMeta.duration || 0) > REF_SECONDS_MAX[next] + 0.5;
|
||||
if (tooLongForNext) {
|
||||
setVideoFile(null);
|
||||
|
||||
Reference in New Issue
Block a user