diff --git a/core/backend/apps/ai/services.py b/core/backend/apps/ai/services.py
index eb8eeb3..f36742d 100644
--- a/core/backend/apps/ai/services.py
+++ b/core/backend/apps/ai/services.py
@@ -804,15 +804,29 @@ def _scene_context(project) -> str:
def build_storyboard_frame_prompt(project, version, segment) -> str:
- """单帧故事板提示词:风格锚点 + 本镜画面(回退旁白)+ 版本统一指令。"""
+ """单场故事板提示词:把这一「场」拆成多个分镜,排成一张竖屏【分镜表】。
+ 用户要的结构是「一场 = 一个故事板,内含多个分镜图(不同景别/运镜)」,而非一场一张大图。"""
visual = (segment.visual_prompt or segment.narration or "").strip()
+ dur = segment.duration_seconds or 15
+ sub = max(2, min(4, round(dur / 5))) # 按本场时长估分镜数:15s≈3 格
lines = [
_scene_context(project),
- f"第 {segment.sort_order + 1} 镜画面:{visual}" if visual else f"第 {segment.sort_order + 1} 镜",
+ f"生成一张竖屏【分镜故事板表】:把第 {segment.sort_order + 1} 场(约 {dur} 秒)拆成 {sub} 个分镜,"
+ f"从上到下纵向排成 {sub} 个等宽分格,格与格之间用细线或留白分隔,每格角落标注分镜序号、景别与时长。",
]
+ if visual:
+ lines.append(f"本场画面:{visual}")
+ if segment.narration:
+ lines.append(f"台词/口播:{segment.narration.strip()}")
+ if segment.product_exposure:
+ lines.append(f"商品露出方式:{segment.product_exposure.strip()}")
+ lines.append(
+ "各分镜要体现不同景别与运镜(如 中景固定 → 特写微距 → 全景跟拍),镜头连贯,"
+ "同一人物保持同一张脸、同一商品保持外观与配色一致。"
+ )
if version.prompt:
lines.append(version.prompt.strip())
- lines.append("电商竖屏分镜图,构图清晰,可直接指导视频生成")
+ lines.append("真实清新、生活化的电商带货分镜表,竖屏 9:16,排版工整,画面清晰,可直接指导视频生成。")
return "\n".join(line for line in lines if line)
@@ -906,7 +920,8 @@ def build_storyboard_frame_prompt_refs(project, version, segment, refs: list[dic
)
return (
f"{base}\n参考图对应:{ref_lines}。"
- "请严格保持各参考图中角色的同一张脸、同一商品的外观与配色,按本镜画面重新构图合成为一张电商竖屏分镜图。"
+ "请严格保持各参考图中角色的同一张脸、同一商品的外观与配色,按本场各分镜画面重新构图,"
+ "合成为一张包含多个分镜格的竖屏分镜表(每格一个分镜画面)。"
)
diff --git a/core/frontend/src/pipeline-page.css b/core/frontend/src/pipeline-page.css
index e1246b0..42c0356 100644
--- a/core/frontend/src/pipeline-page.css
+++ b/core/frontend/src/pipeline-page.css
@@ -583,6 +583,14 @@
.tri-missing-pop .pop-tip { font-size: 12px; line-height: 1.5; color: var(--black-alpha-56); }
.tri-missing-pop b { color: var(--heat); }
+ /* ── 底栏「确认故事板」点击气泡:没生成故事板时点确认 → 朝上弹提示(复用 pop 视觉) ── */
+ .sb-confirm-wrap { position: relative; display: inline-flex; }
+ .sb-confirm-pop { position: absolute; bottom: calc(100% + 10px); right: 0; width: 248px; padding: 12px 14px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); box-shadow: 0 12px 32px rgba(0,0,0,.14); display: flex; flex-direction: column; gap: 6px; z-index: 30; animation: sb-confirm-in var(--t-base); }
+ .sb-confirm-pop .pop-h { display: inline-flex; align-items: center; gap: 5px; font-family: var(--font-mono); font-size: 12px; letter-spacing: .04em; color: var(--heat); }
+ .sb-confirm-pop .pop-body { font-size: 12px; line-height: 1.55; color: var(--accent-black); }
+ .sb-confirm-pop b { color: var(--heat); }
+ @keyframes sb-confirm-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
+
/* ── 行39 · 三视图选择弹窗 ── */
.tri-modal { width: min(720px, 100%); }
.tri-modal .tri-modal-tip { font-size: 13px; line-height: 1.55; color: var(--black-alpha-72); padding: 10px 12px; background: var(--heat-12); border: 1px solid var(--heat-20); border-radius: var(--r-md); margin-bottom: 16px; }
diff --git a/core/frontend/src/routes/pipeline.tsx b/core/frontend/src/routes/pipeline.tsx
index 0d5998e..2691a8d 100644
--- a/core/frontend/src/routes/pipeline.tsx
+++ b/core/frontend/src/routes/pipeline.tsx
@@ -667,6 +667,13 @@ export function PipelinePage(props: {
// 让用户一眼看出「这里本该有几张」,出图后逐个填真图。无采用版脚本则为 0(显示「暂无」)。
const sbAdoptedScript = scripts.find((s) => s.is_adopted) || null;
const sbExpectedShots = sbAdoptedScript ? (sbAdoptedScript.segments?.length ?? 0) : 0;
+ // 没生成故事板时点「确认故事板」→ 弹气泡提示先去生成(3.5s 自动收起)
+ const [sbConfirmHint, setSbConfirmHint] = useState(false);
+ useEffect(() => {
+ if (!sbConfirmHint) return;
+ const t = window.setTimeout(() => setSbConfirmHint(false), 3500);
+ return () => window.clearTimeout(t);
+ }, [sbConfirmHint]);
// ── Stage 4:视频片段(adopted_asset 缩略图 + 状态 pill + 时长)──
const segments = [...(project.video_segments ?? [])].sort((a, b) => a.sort_order - b.sort_order);
@@ -2601,7 +2608,7 @@ export function PipelinePage(props: {
: 历史版本)
: 未生成}
-
整张故事板由 image-2 一次性输出,包含画面 + 镜头说明。
+ 每个场一张分镜表 · image-2 把该场拆成多个分镜(不同景别/运镜)画进一张竖屏图。
@@ -2656,12 +2663,19 @@ export function PipelinePage(props: {
[ image-2 整张输出 · {sbFrames.length ? `${sbFrames.length} 场` : sbExpectedShots ? `待生成 ${sbExpectedShots} 场` : "0 场"} · 整张重跑,失败不扣 ]
- {adoptedStoryboard ? (
-
- ) : (
- /* 没有故事板时不再假装「确认故事板」:走真实 skip-storyboard,把项目阶段如实推进到视频 */
-
- )}
+ {/* 不再允许跳过故事板:统一「确认故事板」。没生成故事板时点它 → 弹气泡提示先去生成,不放行 */}
+
+ {sbConfirmHint && (
+
+
+
+ 还没有故事板
+
+
请先点上方 生成故事板,出图后再确认进入视频生成。
+
+ )}
+
+
diff --git a/core/qa/function-audit/output/perf-report.json b/core/qa/function-audit/output/perf-report.json
new file mode 100644
index 0000000..a7c514f
--- /dev/null
+++ b/core/qa/function-audit/output/perf-report.json
@@ -0,0 +1,315 @@
+{
+ "ts": "2026-06-17T10:24:13.586Z",
+ "base": "http://127.0.0.1:5174",
+ "apiChecks": [
+ {
+ "name": "page_size 生效 /api/assets/",
+ "pass": true,
+ "detail": "count=227 返回=200 next=有"
+ },
+ {
+ "name": "page_size 生效 /api/products/",
+ "pass": true,
+ "detail": "count=10 返回=10 next=无"
+ },
+ {
+ "name": "page_size 生效 /api/projects/",
+ "pass": true,
+ "detail": "count=19 返回=19 next=无"
+ },
+ {
+ "name": "延迟 /api/assets/?page_size=200",
+ "pass": false,
+ "soft": true,
+ "detail": "2235ms / 参考 1200ms (HTTP 200)"
+ },
+ {
+ "name": "延迟 /api/products/?page_size=200",
+ "pass": true,
+ "soft": true,
+ "detail": "962ms / 参考 1200ms (HTTP 200)"
+ },
+ {
+ "name": "延迟 /api/projects/?page_size=200",
+ "pass": false,
+ "soft": true,
+ "detail": "2703ms / 参考 1200ms (HTTP 200)"
+ },
+ {
+ "name": "延迟 /api/ops/notifications/?page_size=100",
+ "pass": false,
+ "soft": true,
+ "detail": "1959ms / 参考 1200ms (HTTP 200)"
+ }
+ ],
+ "pageFailed": 0,
+ "results": [
+ {
+ "name": "dashboard",
+ "route": "http://127.0.0.1:5174/dashboard",
+ "unique": 9,
+ "budget": 14,
+ "rawRequests": 11,
+ "waterfall": 0,
+ "duplicates": [],
+ "failed": [],
+ "breakdown": [
+ "GET /api/auth/me/",
+ "GET /api/products/",
+ "GET /api/projects/",
+ "GET /api/billing/summary/",
+ "GET /api/billing/ledgers/?page=1&page_size=10",
+ "GET /api/billing/trend/",
+ "GET /api/auth/team/members/",
+ "GET /api/ai/models/",
+ "GET /api/ai/tasks/",
+ "GET /api/ops/notifications/?page_size=100",
+ "GET /api/assets/summary/"
+ ],
+ "elapsedMs": 6445,
+ "problems": [],
+ "warnings": [],
+ "pass": true
+ },
+ {
+ "name": "products",
+ "route": "http://127.0.0.1:5174/products",
+ "unique": 8,
+ "budget": 6,
+ "rawRequests": 10,
+ "waterfall": 0,
+ "duplicates": [],
+ "failed": [],
+ "breakdown": [
+ "GET /api/auth/me/",
+ "GET /api/products/",
+ "GET /api/projects/",
+ "GET /api/billing/summary/",
+ "GET /api/billing/ledgers/?page=1&page_size=10",
+ "GET /api/billing/trend/",
+ "GET /api/auth/team/members/",
+ "GET /api/ai/models/",
+ "GET /api/ai/tasks/",
+ "GET /api/ops/notifications/?page_size=100"
+ ],
+ "elapsedMs": 3892,
+ "problems": [],
+ "warnings": [
+ "首屏接口数 8 > 预算 6(架构性过量拉取,待决策)"
+ ],
+ "pass": true
+ },
+ {
+ "name": "projects",
+ "route": "http://127.0.0.1:5174/projects",
+ "unique": 8,
+ "budget": 6,
+ "rawRequests": 10,
+ "waterfall": 0,
+ "duplicates": [],
+ "failed": [],
+ "breakdown": [
+ "GET /api/auth/me/",
+ "GET /api/products/",
+ "GET /api/projects/",
+ "GET /api/billing/summary/",
+ "GET /api/billing/ledgers/?page=1&page_size=10",
+ "GET /api/billing/trend/",
+ "GET /api/auth/team/members/",
+ "GET /api/ai/models/",
+ "GET /api/ai/tasks/",
+ "GET /api/ops/notifications/?page_size=100"
+ ],
+ "elapsedMs": 3765,
+ "problems": [],
+ "warnings": [
+ "首屏接口数 8 > 预算 6(架构性过量拉取,待决策)"
+ ],
+ "pass": true
+ },
+ {
+ "name": "library",
+ "route": "http://127.0.0.1:5174/library",
+ "unique": 11,
+ "budget": 8,
+ "rawRequests": 14,
+ "waterfall": 0,
+ "duplicates": [
+ {
+ "key": "GET /api/assets/?ordering=-created_at&page=1&page_size=10&tab=people",
+ "n": 2
+ }
+ ],
+ "failed": [],
+ "breakdown": [
+ "GET /api/assets/?ordering=-created_at&page=1&page_size=10&tab=people ×2",
+ "GET /api/auth/me/",
+ "GET /api/products/",
+ "GET /api/projects/",
+ "GET /api/billing/summary/",
+ "GET /api/billing/ledgers/?page=1&page_size=10",
+ "GET /api/billing/trend/",
+ "GET /api/auth/team/members/",
+ "GET /api/ai/models/",
+ "GET /api/ai/tasks/",
+ "GET /api/ops/notifications/?page_size=100",
+ "GET /api/assets/summary/",
+ "GET /api/assets/facets/?meta_keys=gender,age,role&tab=people"
+ ],
+ "elapsedMs": 6012,
+ "problems": [],
+ "warnings": [
+ "首屏接口数 11 > 预算 8(架构性过量拉取,待决策)"
+ ],
+ "pass": true
+ },
+ {
+ "name": "account",
+ "route": "http://127.0.0.1:5174/account",
+ "unique": 8,
+ "budget": 8,
+ "rawRequests": 11,
+ "waterfall": 0,
+ "duplicates": [
+ {
+ "key": "GET /api/billing/ledgers/?page=1&page_size=10",
+ "n": 2
+ }
+ ],
+ "failed": [],
+ "breakdown": [
+ "GET /api/billing/ledgers/?page=1&page_size=10 ×2",
+ "GET /api/auth/me/",
+ "GET /api/products/",
+ "GET /api/projects/",
+ "GET /api/billing/summary/",
+ "GET /api/billing/trend/",
+ "GET /api/auth/team/members/",
+ "GET /api/ai/models/",
+ "GET /api/ai/tasks/",
+ "GET /api/ops/notifications/?page_size=100"
+ ],
+ "elapsedMs": 5753,
+ "problems": [],
+ "warnings": [],
+ "pass": true
+ },
+ {
+ "name": "team",
+ "route": "http://127.0.0.1:5174/team",
+ "unique": 8,
+ "budget": 4,
+ "rawRequests": 10,
+ "waterfall": 0,
+ "duplicates": [],
+ "failed": [],
+ "breakdown": [
+ "GET /api/auth/me/",
+ "GET /api/products/",
+ "GET /api/projects/",
+ "GET /api/billing/summary/",
+ "GET /api/billing/ledgers/?page=1&page_size=10",
+ "GET /api/billing/trend/",
+ "GET /api/auth/team/members/",
+ "GET /api/ai/models/",
+ "GET /api/ai/tasks/",
+ "GET /api/ops/notifications/?page_size=100"
+ ],
+ "elapsedMs": 3555,
+ "problems": [],
+ "warnings": [
+ "首屏接口数 8 > 预算 4(架构性过量拉取,待决策)"
+ ],
+ "pass": true
+ },
+ {
+ "name": "messages",
+ "route": "http://127.0.0.1:5174/messages",
+ "unique": 8,
+ "budget": 4,
+ "rawRequests": 11,
+ "waterfall": 0,
+ "duplicates": [],
+ "failed": [],
+ "breakdown": [
+ "GET /api/auth/me/",
+ "GET /api/products/",
+ "GET /api/projects/",
+ "GET /api/billing/summary/",
+ "GET /api/billing/ledgers/?page=1&page_size=10",
+ "GET /api/billing/trend/",
+ "GET /api/auth/team/members/",
+ "GET /api/ai/models/",
+ "GET /api/ai/tasks/",
+ "GET /api/ops/notifications/?page_size=100",
+ "GET /api/ops/notifications/?page=1&page_size=10"
+ ],
+ "elapsedMs": 3468,
+ "problems": [],
+ "warnings": [
+ "首屏接口数 8 > 预算 4(架构性过量拉取,待决策)"
+ ],
+ "pass": true
+ },
+ {
+ "name": "productDetail",
+ "route": "http://127.0.0.1:5174/products/045ad8d6-8b15-486b-a4a9-f6968eb1555f",
+ "unique": 9,
+ "budget": 8,
+ "rawRequests": 11,
+ "waterfall": 0,
+ "duplicates": [],
+ "failed": [],
+ "breakdown": [
+ "GET /api/auth/me/",
+ "GET /api/products/",
+ "GET /api/projects/",
+ "GET /api/billing/summary/",
+ "GET /api/billing/ledgers/?page=1&page_size=10",
+ "GET /api/billing/trend/",
+ "GET /api/auth/team/members/",
+ "GET /api/ai/models/",
+ "GET /api/ai/tasks/",
+ "GET /api/ops/notifications/?page_size=100",
+ "GET /api/assets/?page_size=200&product=045ad8d6-8b15-486b-a4a9-f6968eb1555f"
+ ],
+ "elapsedMs": 5956,
+ "problems": [],
+ "warnings": [
+ "首屏接口数 9 > 预算 8(架构性过量拉取,待决策)"
+ ],
+ "pass": true
+ },
+ {
+ "name": "pipeline",
+ "route": "http://127.0.0.1:5174/pipeline/1048451e-3b4a-4b66-a8f4-cb865096de2f",
+ "unique": 11,
+ "budget": 10,
+ "rawRequests": 13,
+ "waterfall": 0,
+ "duplicates": [],
+ "failed": [],
+ "breakdown": [
+ "GET /api/auth/me/",
+ "GET /api/projects/1048451e-3b4a-4b66-a8f4-cb865096de2f/",
+ "GET /api/products/",
+ "GET /api/projects/",
+ "GET /api/billing/summary/",
+ "GET /api/billing/ledgers/?page=1&page_size=10",
+ "GET /api/billing/trend/",
+ "GET /api/auth/team/members/",
+ "GET /api/ai/models/",
+ "GET /api/ai/tasks/",
+ "GET /api/ops/notifications/?page_size=100",
+ "POST /api/projects/1048451e-3b4a-4b66-a8f4-cb865096de2f/generate-base-asset/",
+ "GET /api/projects/1048451e-3b4a-4b66-a8f4-cb865096de2f/pending-assets/"
+ ],
+ "elapsedMs": 5702,
+ "problems": [],
+ "warnings": [
+ "首屏接口数 11 > 预算 10(架构性过量拉取,待决策)"
+ ],
+ "pass": true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/core/test/_verify/base-asset-seed-cards-2026-06-16T10-24-47-678Z.png b/core/test/_verify/base-asset-seed-cards-2026-06-16T10-24-47-678Z.png
new file mode 100644
index 0000000..f51e635
Binary files /dev/null and b/core/test/_verify/base-asset-seed-cards-2026-06-16T10-24-47-678Z.png differ
diff --git a/core/test/_verify/person-detail-fixed-2026-06-17T05-43-02-617Z.png b/core/test/_verify/person-detail-fixed-2026-06-17T05-43-02-617Z.png
new file mode 100644
index 0000000..3409d94
Binary files /dev/null and b/core/test/_verify/person-detail-fixed-2026-06-17T05-43-02-617Z.png differ
diff --git a/core/test/_verify/person-detail-modal-2026-06-17T05-41-27-545Z.png b/core/test/_verify/person-detail-modal-2026-06-17T05-41-27-545Z.png
new file mode 100644
index 0000000..b5ab0e2
Binary files /dev/null and b/core/test/_verify/person-detail-modal-2026-06-17T05-41-27-545Z.png differ
diff --git a/core/test/_verify/person-detail-modal-zoom-2026-06-17T05-41-46-987Z.png b/core/test/_verify/person-detail-modal-zoom-2026-06-17T05-41-46-987Z.png
new file mode 100644
index 0000000..d5e3b7f
Binary files /dev/null and b/core/test/_verify/person-detail-modal-zoom-2026-06-17T05-41-46-987Z.png differ
diff --git a/core/test/_verify/pipeline-empty-state-2026-06-16T10-17-22-402Z.png b/core/test/_verify/pipeline-empty-state-2026-06-16T10-17-22-402Z.png
new file mode 100644
index 0000000..c95e955
Binary files /dev/null and b/core/test/_verify/pipeline-empty-state-2026-06-16T10-17-22-402Z.png differ
diff --git a/core/test/_verify/real-product.png b/core/test/_verify/real-product.png
new file mode 100644
index 0000000..9301138
Binary files /dev/null and b/core/test/_verify/real-product.png differ
diff --git a/core/test/_verify/real-product.webp b/core/test/_verify/real-product.webp
new file mode 100644
index 0000000..fedfced
Binary files /dev/null and b/core/test/_verify/real-product.webp differ
diff --git a/core/test/_verify/script-generated-tags-2026-06-16T10-20-15-919Z.png b/core/test/_verify/script-generated-tags-2026-06-16T10-20-15-919Z.png
new file mode 100644
index 0000000..9add19d
Binary files /dev/null and b/core/test/_verify/script-generated-tags-2026-06-16T10-20-15-919Z.png differ
diff --git a/core/test/_verify/script-with-tags-2026-06-16T10-21-07-598Z.png b/core/test/_verify/script-with-tags-2026-06-16T10-21-07-598Z.png
new file mode 100644
index 0000000..3cc2568
Binary files /dev/null and b/core/test/_verify/script-with-tags-2026-06-16T10-21-07-598Z.png differ
diff --git a/core/test/_verify/setup-card-2026-06-16T10-17-57-634Z.png b/core/test/_verify/setup-card-2026-06-16T10-17-57-634Z.png
new file mode 100644
index 0000000..f35c5e2
Binary files /dev/null and b/core/test/_verify/setup-card-2026-06-16T10-17-57-634Z.png differ
diff --git a/core/test/_verify/stage2-current-2026-06-17T05-39-54-736Z.png b/core/test/_verify/stage2-current-2026-06-17T05-39-54-736Z.png
new file mode 100644
index 0000000..4c3f012
Binary files /dev/null and b/core/test/_verify/stage2-current-2026-06-17T05-39-54-736Z.png differ
diff --git a/core/test/_verify/stage2-loaded-2026-06-17T05-40-45-717Z.png b/core/test/_verify/stage2-loaded-2026-06-17T05-40-45-717Z.png
new file mode 100644
index 0000000..a907519
Binary files /dev/null and b/core/test/_verify/stage2-loaded-2026-06-17T05-40-45-717Z.png differ
diff --git a/core/test/_verify/tag-capsules-2026-06-16T10-22-39-528Z.png b/core/test/_verify/tag-capsules-2026-06-16T10-22-39-528Z.png
new file mode 100644
index 0000000..1f595a9
Binary files /dev/null and b/core/test/_verify/tag-capsules-2026-06-16T10-22-39-528Z.png differ
diff --git a/core/test/_verify/triview-result-2026-06-17T01-48-45-815Z.png b/core/test/_verify/triview-result-2026-06-17T01-48-45-815Z.png
new file mode 100644
index 0000000..b1bfafc
Binary files /dev/null and b/core/test/_verify/triview-result-2026-06-17T01-48-45-815Z.png differ
diff --git a/core/test/_verify/triview-result.png b/core/test/_verify/triview-result.png
new file mode 100644
index 0000000..36a570c
Binary files /dev/null and b/core/test/_verify/triview-result.png differ
diff --git a/core/test/流程 (1).md b/core/test/流程 (1).md
new file mode 100644
index 0000000..779df31
--- /dev/null
+++ b/core/test/流程 (1).md
@@ -0,0 +1,93 @@
+# 流程
+
+1. 进入脚本显示空状态,脚本助手显示三个按钮引导点击
+
+
+
+2. ai全生:即ai生成全部的脚本镜头,需要询问用户风格和人物设定,默认给推荐选项,可以修改
+
+
+
+
+
+
+
+
+一句话主题:用户输入一句话,比如小红书种草视频,ai根据用户输入的进行脚本生成,(若是有需要获取的数据,比如用户没有说明是什么风格和人物设定也可以和ai全生一样询问用户
+
+
+自带脚本:用户上传自己的脚本文件,ai从脚本文件中拆分脚本镜头,(若用户的脚本信息不充足,也可以询问用户,ai在用户的脚本基础上补全脚本)
+
+3. ai输出脚本后,自动从脚本中提取信息,如人物:女生、同事,场景:卫生间
+显示在脚本镜头的顶部标签,可以编辑,若添加/删除则自动带入输入框胶囊:一条修改,悬浮显示:添加/删除人物/场景:xxx,可以发送确定更改,删除则撤销
+
+
+
+
+
+4. 确定脚本后进入到基础资产,基础资产有创建项目时选定的商品、人物、场景,人物、场景资产来自脚本页面提取的,没有生成三视图的商品卡片会显示“缺三视图”标签,悬浮标签显示三视图影响视频的生成效果,建议生成
+
+
+
+点击商品卡片中ai生成三视图按钮则会在卡片右侧出现生成三视图的弹窗,会有重跑和采用的按钮,需记录生成的三视图版本,可以切换查看不同版本三视图,并且可以选择采用哪个版本的三视图
+
+
+
+有哪些人物和场景在脚本阶段已经定好了,那么在基础资产页面就会有对应的卡片占位,在确认脚本进入到基础资产页的时候就可以自动生成,生成图片需要有一个loading的按钮
+
+
+
+生成人物、场景提示词由ai根据脚本生成,卡片需要显示提示词,提示词支持用户自己修改,点击重跑则会根据用户输入的提示词重跑生成立绘图片,重跑的图片会覆盖当前显示的卡片立绘,可以点击卡片进入到详情去切换立绘的应用,点击替换则是去到演员库使用现有的资产替换图片
+
+
+
+演员库有平台预设好的演员,也可以自己上传自己的人物,点击添加演员会去到添加人物的工作台,可以ai生成人物,也可以切换到本地上传自己的人物图片保存
+
+
+
+
+
+在基础资产点击人物卡片显示对应的详情弹窗,人物详情弹窗需显示立绘/三视图,提示词输入框和重跑按钮,提示词输入框和重跑按钮对应的是立绘,用户修改提示词重跑立绘图片需要保存生成历史,在详情页显示ai生成立绘的版本,可以点击切换,鼠标悬浮立绘大图,在立绘的右下角会显示两个icon:下载、查看大图,
+
+下载:下载当前立绘,
+
+查看大图:点击查看立绘大图,
+
+人物三视图是根据立绘自动生成的,不同的立绘对应不同的三视图,图片生成中需要有一个loading的动态icon,生成完显示三视图,鼠标悬浮三视图,在三视图的右下角会显示三个icon:重跑、下载、查看大图,
+
+重跑:重新生成新的三视图,
+
+下载:下载当前三视图,
+
+查看大图:点击查看三视图大图,
+
+三视图与立绘同理,也需要保存三视图的生成版本,在三视图的下方显示三视图版本的小预览图即可
+点击应用到当前项目按钮即把立绘和三视图应用到当前项目中
+场景的详情弹窗则不需要显示三视图
+
+
+
+5. 故事板根据前面的脚本和基础资产生成,一张故事板对应一条15s以内的视频,这里需要根据前面的分镜划分,15s以内的分镜在一张故事板里,(一个脚本时长不一定在15s内所有会有多个故事板),左侧分栏则是故事板的预览,中间大图是当前选择的故事板的大图,右分栏是详情,故事板的提示词由ai输出,用户可以自由编辑修改,点击整张重跑即根据提示词把当前选中的这张故事板重跑
+
+现在不允许跳过故事板,去掉底部栏跳过故事板的按钮,没有故事板则鼠标悬浮在“确认故事板,开始生成视频”的按钮时显示气泡提示先去生成故事板
+
+
+
+6. 视频根据故事板和基础资产生成,因为故事板已经包含了一条视频所需要的画面、台词、人物,点击“确认故事板,开始生成视频”后视频自动生成,不需要再点击开始生成视频,在没有视频拼接导出的功能清空下,隐藏“上传视频”的按钮,右上角只需要有“全部重跑”和“批量下载”两个按钮即可
+
+全部重跑:所有视频重新ai生成
+
+批量下载:批量下载所有视频
+
+视频生成中卡片需显示loading动态icon
+
+视频卡片去掉上传按钮
+
+
+
+视频详情底部按钮修改为“应用当前视频”,重跑按钮改为放在提示词下面,点击重跑则ai根据提示词重跑当前这条视频,历史版本未有也应该显示一个卡片占位,有一个loading的动态icon
+
+
+
+7. 拼接导出先不做,隐藏
+