测试视频复刻

This commit is contained in:
Azmat@qq.com
2026-08-27 18:27:08 +08:00
parent b3bf159e08
commit 52c5cdae1d
7 changed files with 299 additions and 106 deletions
-14
View File
@@ -1231,20 +1231,6 @@
.sb-scene-thumb .placeholder .sb-frame-rv .rv-label { display: none; }
.sb-main-img .sb-main-rv { position: absolute; top: 10px; left: 10px; z-index: 4; }
/* 故事板说明层:从已确认脚本直接排版,不把文字烧进给视频模型的关键帧。 */
.sb-director-board { margin: 0 0 14px; background: var(--background-lighter); border: 1px solid var(--border-faint); border-radius: var(--r-md); overflow: hidden; }
.sb-director-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 12px; border-bottom: 1px solid var(--border-faint); background: var(--surface); }
.sb-director-head > div { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.sb-director-head .mono { font-family: var(--font-mono); font-size: 10px; letter-spacing: .05em; color: var(--black-alpha-48); white-space: nowrap; }
.sb-director-head strong { font-size: 12px; font-weight: 500; color: var(--accent-black); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sb-director-beat { display: grid; grid-template-columns: 54px minmax(0, 1fr); border-bottom: 1px solid var(--border-faint); }
.sb-director-beat:last-child { border-bottom: 0; }
.sb-director-time { display: flex; align-items: flex-start; justify-content: center; padding: 11px 6px; background: var(--surface); color: var(--heat); font-family: var(--font-mono); font-size: 11px; font-variant-numeric: tabular-nums; }
.sb-director-copy { min-width: 0; padding: 10px 12px; }
.sb-director-direction { color: var(--accent-black); font-size: 12px; line-height: 1.55; }
.sb-director-narration { margin-top: 5px; color: var(--black-alpha-56); font-size: 11.5px; line-height: 1.55; }
.sb-director-empty { padding: 14px 12px; color: var(--black-alpha-48); font-size: 12px; line-height: 1.6; }
.sb-rerun-note { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px; margin-bottom: 14px; background: rgba(180,83,9,.08); border: 1px solid rgba(180,83,9,.20); border-radius: var(--r-md); color: #7C3A05; line-height: 1.55; }
.sb-rerun-note .warn-ic { width: 22px; height: 22px; border-radius: var(--r-sm); background: rgba(180,83,9,.12); color: #B45309; display: grid; place-items: center; flex: 0 0 22px; }
.sb-rerun-note .warn-ic svg { width: 14px; height: 14px; }
+2 -44
View File
@@ -34,26 +34,6 @@ const KIND_LABEL: Record<string, string> = { product: "商品", person: "角色"
// 脚本来源 → 「来源」brief pill 文案
// 入口收敛为「脚本辅助生成 / 上传脚本」两种。theme 键保留:历史稿的 source 仍可能是旧的「一句话主题」。
const SOURCE_LABEL: Record<string, string> = { ai: "脚本辅助生成", theme: "脚本辅助生成", manual: "上传脚本", video: "上传视频提炼" };
type DirectorBeat = { time: string; direction: string; narration: string };
const DIRECTOR_BEAT_RE = /(?:^|\n)\s*(\d{1,2})\s*[-–—~到至]\s*(\d{1,2})\s*(?:s|秒)?\s*[:]*\s*([^\n]+)/g;
function buildDirectorBeats(visual: string, narration: string, duration: number): DirectorBeat[] {
const matches = [...(visual || "").matchAll(DIRECTOR_BEAT_RE)];
const narrationLines = (narration || "").split(/(?<=[。!?!?])/).map((line) => line.trim()).filter(Boolean);
if (matches.length) {
return matches.slice(0, 5).map((match, index) => ({
time: `${match[1]}${match[2]}s`,
direction: match[3].trim(),
narration: narrationLines[index] || (index === 0 ? narration.trim() : ""),
}));
}
const count = Math.min(3, Math.max(1, narrationLines.length || 1));
const step = duration / count;
return Array.from({ length: count }, (_, index) => ({
time: `${Math.round(index * step)}${Math.round((index + 1) * step)}s`,
direction: visual.trim() || "按本镜脚本完成关键动作与商品露出",
narration: narrationLines[index] || (index === 0 ? narration.trim() : ""),
}));
}
// 旁白配音音色预设(语音合成经典版试用包实测可用,与后端 VOICEOVER_VOICES 对齐)
const VO_VOICES = [
{ key: "BV700_streaming", label: "灿灿 · 活力女声" },
@@ -2070,7 +2050,7 @@ export function PipelinePage(props: {
document.body.style.userSelect = "";
};
}, [gutterDragging]);
const SB_PROMPT_DEFAULT = "统一商品、人物、场景风格,生成干净、可直接指导视频的关键帧;导演分镜说明按脚本自动生成";
const SB_PROMPT_DEFAULT = "统一商品、人物、场景风格,生成完整、可直接指导视频的导演故事板";
// 整张风格提示词:项目级(原 StoryboardVersion.prompt 的去处),重跑时生效
const sbSavedPrompt = (project.metadata as Record<string, unknown> | undefined)?.storyboard_prompt as string | undefined;
const [storyboardPrompt, setStoryboardPrompt] = useState(sbSavedPrompt || SB_PROMPT_DEFAULT);
@@ -3871,13 +3851,6 @@ export function PipelinePage(props: {
const sbViewedIsAdopted = !sbViewedVer || sbViewedVer.is_adopted || sbViewedVer.id === sbActiveShot?.adopted_version;
const mainUrl = sbViewedVer ? (sbViewedVer.asset_url || assetUrl(sbViewedVer.asset)) : shotImg(sbActiveShot);
const mainAid = sbViewedVer?.asset || sbActiveShot?.adopted_asset || "";
const activeScriptShot = sbActiveShot ? shots[sbActiveShot.sort_order] : null;
const directorBeats = buildDirectorBeats(
activeScriptShot?.visual_prompt || "",
activeScriptShot?.narration || "",
activeScriptShot?.duration_seconds || SEGMENT_DURATION_MAX,
);
const directorRange = sceneTimes[sbSelected] || "—";
return (
<section className="stage active" data-stage-pane="3">
<div className="stage-storyboard">
@@ -3949,22 +3922,7 @@ export function PipelinePage(props: {
<span>{sbActiveShot.error_message}</span>
</div>
)}
<div className="muted-2" style={{ fontSize: "12px", lineHeight: 1.55, marginBottom: "10px" }}>稿使</div>
<div className="sb-director-board" aria-label="本场导演故事板">
<div className="sb-director-head">
<div><span className="mono">DIRECTOR BOARD</span><strong> {sbSelected + 1} · {directorRange}</strong></div>
<span className="pill pill-l3 neutral"><span className="dot" />9:16 · </span>
</div>
{directorBeats.length ? directorBeats.map((beat, index) => (
<div className="sb-director-beat" key={`${beat.time}-${index}`}>
<div className="sb-director-time">{beat.time}</div>
<div className="sb-director-copy">
<div className="sb-director-direction">{beat.direction}</div>
{beat.narration && <div className="sb-director-narration">/{beat.narration}</div>}
</div>
</div>
)) : <div className="sb-director-empty"></div>}
</div>
<div className="muted-2" style={{ fontSize: "12px", lineHeight: 1.55, marginBottom: "10px" }}> image-2 ,,</div>
<div className="muted mono" style={{ fontSize: "12px", fontWeight: 500, marginBottom: "6px", letterSpacing: ".04em" }}>(,)</div>
<PromptBox
className="prompt-edit"
+4 -1
View File
@@ -334,7 +334,10 @@ export function VideoReplacePage({
resolution: "720p",
duration: outputDuration,
refs: [
...(videoRef ? [{ type: "video", duration: videoRef.duration || videoMeta.duration }] : []),
// 商品复刻的参考视频只用来提炼分镜稿,不会发给火山,算进估价会让显示积分高于实际扣费。
...(videoRef && replaceMode === "character"
? [{ type: "video", duration: videoRef.duration || videoMeta.duration }]
: []),
...((source === "library"
? Array.from({ length: Math.max(1, libraryImageCount) }, () => ({ type: "image" as const }))
: (tempFiles.length ? tempFiles : tempAssetRefs)