feat(core): 故事板改为「一场=分镜表」+ 确认故事板按钮气泡引导
- ai/services.py: 故事板单帧提示词改为按场拆多分镜、纵向排成竖屏分镜表(不同景别/运镜),并锁人物脸/商品一致性 - pipeline.tsx: 底栏统一「确认故事板」,未生成时点击弹气泡引导先生成(不再假装跳过) - pipeline-page.css: 配套 sb-confirm-pop 气泡样式 - 附测试截图与流程文档/perf 产物 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@@ -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}。"
|
||||
"请严格保持各参考图中角色的同一张脸、同一商品的外观与配色,按本镜画面重新构图合成为一张电商竖屏分镜图。"
|
||||
"请严格保持各参考图中角色的同一张脸、同一商品的外观与配色,按本场各分镜画面重新构图,"
|
||||
"合成为一张包含多个分镜格的竖屏分镜表(每格一个分镜画面)。"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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: {
|
||||
: <span className="pill neutral"><span className="dot"></span>历史版本</span>)
|
||||
: <span className="pill neutral"><span className="dot"></span>未生成</span>}
|
||||
</div>
|
||||
<div className="muted-2" style={{ fontSize: "12px", lineHeight: 1.55, marginBottom: "10px" }}>整张故事板由 image-2 一次性输出,包含画面 + 镜头说明。</div>
|
||||
<div className="muted-2" style={{ fontSize: "12px", lineHeight: 1.55, marginBottom: "10px" }}>每个场一张分镜表 · image-2 把该场拆成多个分镜(不同景别/运镜)画进一张竖屏图。</div>
|
||||
<div className="sb-rerun-note">
|
||||
<span className="warn-ic" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" /><path d="M12 9v4M12 17h.01" /></svg>
|
||||
@@ -2656,12 +2663,19 @@ export function PipelinePage(props: {
|
||||
<div className="info"><span className="mono">[ image-2 整张输出 · {sbFrames.length ? `${sbFrames.length} 场` : sbExpectedShots ? `待生成 ${sbExpectedShots} 场` : "0 场"} · 整张重跑,失败不扣 ]</span></div>
|
||||
<div className="hstack">
|
||||
<button className="btn" type="button" onClick={() => goStage(2)}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7" /></svg> 返回资产</button>
|
||||
{adoptedStoryboard ? (
|
||||
<button className="btn btn-primary btn-lg" type="button" onClick={() => goStage(4)}>确认故事板,开始生成视频 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M12 5l7 7-7 7" /></svg></button>
|
||||
) : (
|
||||
/* 没有故事板时不再假装「确认故事板」:走真实 skip-storyboard,把项目阶段如实推进到视频 */
|
||||
<button className="btn btn-primary btn-lg" type="button" disabled={loading} onClick={async () => { await onSkipStoryboard(); goStage(4); }}>跳过故事板,直接生成视频 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M12 5l7 7-7 7" /></svg></button>
|
||||
)}
|
||||
{/* 不再允许跳过故事板:统一「确认故事板」。没生成故事板时点它 → 弹气泡提示先去生成,不放行 */}
|
||||
<div className="sb-confirm-wrap">
|
||||
{sbConfirmHint && (
|
||||
<div className="sb-confirm-pop" role="tooltip">
|
||||
<span className="pop-h">
|
||||
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 9v4M12 17h.01" /><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" /></svg>
|
||||
还没有故事板
|
||||
</span>
|
||||
<span className="pop-body">请先点上方 <b>生成故事板</b>,出图后再确认进入视频生成。</span>
|
||||
</div>
|
||||
)}
|
||||
<button className="btn btn-primary btn-lg" type="button" disabled={loading} onClick={() => { if (!adoptedStoryboard) { setSbConfirmHint(true); return; } goStage(4); }}>确认故事板,开始生成视频 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M12 5l7 7-7 7" /></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 372 KiB |
|
After Width: | Height: | Size: 359 KiB |
|
After Width: | Height: | Size: 179 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 318 KiB |
|
After Width: | Height: | Size: 200 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 207 KiB |
|
After Width: | Height: | Size: 459 KiB |
|
After Width: | Height: | Size: 356 KiB |
@@ -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. 拼接导出先不做,隐藏
|
||||
|
||||