refactor: switch ad workflow to horizontal kanban

This commit is contained in:
2026-05-17 11:27:46 +08:00
parent 201abc60d1
commit 0203a09e57
6 changed files with 48 additions and 44 deletions

View File

@@ -1,12 +1,5 @@
{
"entries": [
{
"files_changed": 1,
"hash": "10ef888",
"message": "auto-save 2026-05-14 16:58 (~1)",
"ts": "2026-05-14T16:59:01+08:00",
"type": "commit"
},
{
"files_changed": 1,
"hash": "237531f",
@@ -3269,6 +3262,13 @@
"type": "session-heartbeat",
"message": "Codex 会话活跃 · 最近命令codex · 分支 main · 1 项未提交变更 · 最近提交refactor: replace flow nodes with ad recreation board",
"files_changed": 1
},
{
"ts": "2026-05-17T11:23:22+08:00",
"type": "commit",
"message": "auto-save 2026-05-17 11:23 (~3)",
"hash": "201abc6",
"files_changed": 3
}
]
}

View File

@@ -27,7 +27,7 @@
"type": "web_login"
}
],
"description": "SKG 信息流广告快速复刻工作台TK/本地视频 → 视频抽帧 → 音频解析生成文案 → 剧情规划与 SKG 产品融入 → Seedance/Kling/Veo3 生成候选片段 → 选择组合成片;主界面为左侧单任务工作表,右侧无限画布暂时清空保留。",
"description": "SKG 信息流广告快速复刻横向生产看板:素材输入列(一个素材就是一次文件任务)→ 音频解析并根据产品内容生成新分镜文案 → 视频关键元素抽帧并直接生成元素/候选片段 → 视频合成列汇总音频和视频片段。",
"kind": "app",
"name": "SKG Marketing Studio / SKG 营销内容工作台",
"ownership": "company",

View File

@@ -11,7 +11,7 @@
- 详见 `CLAUDE.md` 立项决策段 + `.memory/plan.md` 七步管线拆解
- 风格:`04-Dark-Gallery-Ambient`(路径:`~/Projects/research/20260305-网页风格库/04-Dark-Gallery-Ambient.md`
- 第一冲刺:步骤 1-4下载 / 拆轨 / 关键帧 / ASR+翻译)
- 当前产品方向2026-05-17 确认):优先做信息流广告快速复刻产出,不再把主界面做成可视化流程节点;主界面为左侧单任务工作表(素材输入、抽帧、音频文案、剧情规划/产品融入、候选片段),右侧保留但暂时清空无限画布
- 当前产品方向2026-05-17 确认):优先做信息流广告快速复刻产出,不再把主界面做成可视化流程节点;主界面为四列横向生产看板:素材输入列(一个素材就是一次文件任务)→ 音频解析 / 新分镜文案列 → 视频关键元素 / 抽帧生成列 → 视频合成列
## 部署事实
- 平台VPS `76.13.31.179`Ubuntu 24.04 / Docker Compose / Coolify Traefik

View File

@@ -485,7 +485,7 @@
<h2>这个页面是产品协作地图,不是应用功能页。</h2>
<p>
它把“你看到的界面、你想改的功能、实际要动的源码、可能影响的数据和接口”放在同一个地方。
后续描述需求时,可以直接说“改左侧看板的某个工作段 / 右侧画布要承载什么 / 某个接口行为”,这样改动范围会更准,也更容易追踪每次变更带来的影响。
后续描述需求时,可以直接说“改横向看板的某一列 / 某个素材任务 / 某个接口行为”,这样改动范围会更准,也更容易追踪每次变更带来的影响。
</p>
<div class="meta-grid">
<div class="meta"><b>项目路径</b><span>/Users/kangwan/Projects/business/20260512-20260512-skg-tk-二创验证</span></div>
@@ -500,7 +500,7 @@
<div class="grid-3">
<div class="card">
<h3>1. 先说你在改哪个产品区</h3>
<p>例如“左侧看板的视频抽帧区”、“剧情规划 / 产品融入行”、“候选片段选择区”、“右侧空白画布”。不要只说“这里乱”,要指向页面里的功能区。</p>
<p>例如“素材输入列”、“音频解析 / 新分镜文案列”、“视频关键元素 / 抽帧生成列”、“视频合成列”。不要只说“这里乱”,要指向页面里的功能区。</p>
</div>
<div class="card">
<h3>2. 再说这个区应该承担什么职责</h3>
@@ -569,14 +569,12 @@
<section id="pipeline" data-search>
<h2>业务管线</h2>
<p>当前产品方向收敛为“信息流广告快速复刻工作台”:不再把主界面设计成可视化节点流程,而是把单个视频任务放进左侧工作表,按抽帧、音频文案、剧情规划、产品融入、候选片段选择推进。右侧保留无限画布能力,但当前版本先清空,等待后续定义要展示的内容</p>
<p>当前产品方向收敛为“信息流广告快速复刻横向生产看板”:主界面从左到右排列四列,分别是素材输入、音频解析 / 新分镜文案、视频关键元素 / 抽帧生成、视频合成。它不再保留单独的右侧空白画布,素材、文案、关键帧、元素和候选片段都在同一张横向工作表内推进</p>
<div class="pipeline">
<div class="step"><div class="num">1</div><h3>素材输入</h3><p>TK / 信息流视频链接或本地上传,创建单个当前任务</p></div>
<div class="step"><div class="num">2</div><h3>视频抽帧</h3><p>按目标、精度和数量抽关键帧,形成可勾选的分镜池;手动加帧和深度素材处理能力仍在底层保留</p></div>
<div class="step"><div class="num">3</div><h3>音频文案</h3><p>从原视频提取音频并生成口播文案,作为后续剧情规划和产品植入的节奏依据</p></div>
<div class="step"><div class="num">4</div><h3>剧情规划</h3><p>对选中的关键帧逐行填写剧情、产品融入、镜头动作和时长</p></div>
<div class="step"><div class="num">5</div><h3>生成片段</h3><p>按每行分镜调用 Seedance / Kling / Veo 生成候选视频片段,并回写到当前任务。</p></div>
<div class="step"><div class="num">6</div><h3>选择组合</h3><p>在候选片段区勾选适合组合成最终广告的片段;最终合成 mp4 当前仍未实现。</p></div>
<div class="step"><div class="num">1</div><h3>素材输入</h3><p>TK / 信息流视频链接或本地上传;每个素材就是一个文件任务,可在列内切换</p></div>
<div class="step"><div class="num">2</div><h3>音频 / 分镜列</h3><p>先解析音频,再结合产品内容生成或填写新的分镜文字;分镜从上到下按时间排列</p></div>
<div class="step"><div class="num">3</div><h3>视频关键元素列</h3><p>按目标、精度和数量抽关键帧,关键帧横向排列;每张帧卡可直接生成元素、选入分镜并提交候选片段</p></div>
<div class="step"><div class="num">4</div><h3>视频合成列</h3><p>把音频文案和已选候选视频片段作为合成输入;最终完整 mp4 合成接口当前仍是占位</p></div>
</div>
</section>
@@ -588,8 +586,8 @@
<table>
<tbody>
<tr><td><code>web/next.config.mjs</code></td><td>Next.js 构建配置:静态导出、图片不走优化、禁用开发环境左下角 Next Dev Indicator并移除 Next 16 已不支持的 <code>eslint</code> 顶层配置,避免本地 dev 出现配置 Issue 提示。</td></tr>
<tr><td><code>web/app/page.tsx</code></td><td>产品工作台主状态jobs、activeJobId、按 job 隔离的 selectedFrames/音频条/生成任务状态;主渲染改为左侧广告复刻看板 + 右侧空白 ReactFlow 无限画布</td></tr>
<tr><td><code>web/components/ad-recreation-board.tsx</code></td><td>左侧信息流广告复刻工作表:素材输入、视频抽帧、音频文案、关键帧选择、剧情规划/产品融入、候选片段选择</td></tr>
<tr><td><code>web/app/page.tsx</code></td><td>产品工作台主状态jobs、activeJobId、按 job 隔离的 selectedFrames/音频条/生成任务状态;主渲染为全屏横向生产看板</td></tr>
<tr><td><code>web/components/ad-recreation-board.tsx</code></td><td>信息流广告横向生产看板:素材输入列、音频解析 / 新分镜文案列、视频关键元素 / 抽帧生成列、视频合成列</td></tr>
<tr><td><code>web/app/login/page.tsx</code></td><td>生产登录页:访问账号/访问密钥表单、保持登录、错误/成功状态;当前只在原版 Digital Oasis 动态背景上叠加一个组合登录框,桌面端左侧是动态角色,右侧是图标化登录表单;面板左上角展示官网 SKG 字标和中文“营销内容工作台”系统标识。</td></tr>
<tr><td><code>web/app/login/layout.tsx</code></td><td>登录路由专属 layout覆盖全站默认网页标题和描述为空避免 <code>/login</code> 继承工作台 metadata 后在页面源码里继续出现登录界面文字以外的文案。</td></tr>
<tr><td><code>web/components/login/oasis-canvas.tsx</code></td><td>登录页全屏动态视觉层:用 iframe 直接承载下载包 <code>web/public/oasis-source/index.html</code> 的原 WebGPU / Three.js 草场源码;父级登录页只覆盖自己的文案和表单,并在捕获阶段把全局鼠标坐标同时用原生事件和 <code>postMessage</code> 转发给 iframe避免登录面板或输入框遮挡时草地失去鼠标响应。</td></tr>
@@ -624,8 +622,8 @@
</div>
<pre>前端主链路:
web/app/page.tsx
-> 左侧复刻看板web/components/ad-recreation-board.tsx
-> 右侧 ReactFlow 无限画布:当前 nodes=[] / edges=[],先保留空白画布能力
-> 横向复刻看板web/components/ad-recreation-board.tsx
-> 四列:素材输入 → 音频解析 / 新分镜文案 → 视频关键元素 / 抽帧生成 → 视频合成
-> 底部音频条web/components/audio-strip.tsx原音频播放 / 指针 / 英文 / 中文 / 波形 / 英文改写稿)
-> 旧节点/深度素材面板web/components/nodes/index.tsx、web/components/lightbox.tsx、web/components/storyboard-workbench.tsx底层保留当前不作为主入口
-> API 契约web/lib/api.ts
@@ -641,14 +639,14 @@ api/main.py
<h2>界面区域到源码</h2>
<div class="flow">
<div class="flow-row">
<div><strong>你看到的区域</strong><span>左侧信息流广告复刻看板</span></div>
<div><strong>你看到的区域</strong><span>四列横向信息流广告生产看板</span></div>
<div><strong>主要源码</strong><span><code>AdRecreationBoard</code> in <code>web/components/ad-recreation-board.tsx</code>;状态、轮询和接口回写仍在 <code>web/app/page.tsx</code></span></div>
<div><strong>适合怎么描述</strong><span>左侧看板里素材输入、抽帧、音频文案、分镜规划、候选片段选择要如何调整”。</span></div>
<div><strong>适合怎么描述</strong><span>横向看板里素材输入列、音频/分镜列、关键元素列、合成列要如何调整”。</span></div>
</div>
<div class="flow-row">
<div><strong>你看到的区域</strong><span>右侧无限画布</span></div>
<div><strong>主要源码</strong><span><code>ReactFlow</code> in <code>web/app/page.tsx</code>当前传入空 <code>nodes=[]</code> / <code>edges=[]</code>,只保留缩放和平移画布能力</span></div>
<div><strong>适合怎么描述</strong><span>右侧空白画布后续应该展示哪些工作对象、是否需要拖拽、预览或对比”。</span></div>
<div><strong>你看到的区域</strong><span>视频关键元素横向帧列</span></div>
<div><strong>主要源码</strong><span><code>ElementFrameCard</code> in <code>web/components/ad-recreation-board.tsx</code>复用 <code>addElement</code><code>cutoutElement</code><code>generateStoryboardVideo</code> 等接口</span></div>
<div><strong>适合怎么描述</strong><span>关键帧卡片里的元素、生成图、生成片段按钮和横向排列应该怎么组织”。</span></div>
</div>
<div class="flow-row">
<div><strong>你看到的区域</strong><span>旧深度素材面板(当前不作为主路径)</span></div>
@@ -847,17 +845,11 @@ SubjectAsset {
</thead>
<tbody>
<tr>
<td><span class="tag blue">左侧复刻看板</span></td>
<td>承载当前单任务主路径:导入视频、抽帧、解析音频、选择关键帧、填写剧情/产品融入、提交单段视频生成、勾选候选片段。它是当前唯一主工作入口</td>
<td>不要再拆多个画布节点;不要右侧空白画布的职责提前塞回看板</td>
<td><span class="tag blue">横向复刻看板</span></td>
<td>承载当前主路径:素材输入列按文件任务管理素材;音频 / 分镜列解析音频并从上到下编辑新分镜文字;关键元素列横向展示关键帧并直接生成元素和候选片段;合成列汇总音频和候选片段输入</td>
<td>不要再拆多个画布节点;不要恢复右侧空白画布占位</td>
<td><code>web/components/ad-recreation-board.tsx</code><code>web/app/page.tsx</code></td>
</tr>
<tr>
<td><span class="tag violet">右侧无限画布</span></td>
<td>当前只保留 ReactFlow 的无限画布能力,主渲染传空节点和空边。后续如果需要展示素材对比、片段组合或时间线,再明确画布对象后实现。</td>
<td>当前不要恢复 Input / Visual Lab / Audio / Compose 这类流程节点。</td>
<td><code>web/app/page.tsx</code></td>
</tr>
<tr>
<td><span class="tag violet">旧节点 / 深度素材面板</span></td>
<td><code>InputNode</code><code>VisualLabNode</code><code>AudioNode</code><code>ComposeNode</code><code>FrameLightbox</code> 等底层能力暂保留,避免本次大改同时破坏抽帧、音频、素材处理和历史 job 数据。</td>
@@ -866,13 +858,13 @@ SubjectAsset {
</tr>
<tr>
<td><span class="tag gray">音频条</span></td>
<td>左侧看板触发音频解析,底部 <code>AudioStrip</code> 仍负责原音频播放、字幕/口播文本、波形和配音预览。</td>
<td>横向看板第二列触发音频解析,底部 <code>AudioStrip</code> 仍负责原音频播放、字幕/口播文本、波形和配音预览。</td>
<td>不要阻断视觉素材管线。</td>
<td><code>web/components/audio-strip.tsx</code><code>pipeline_transcribe</code><code>AudioScript</code></td>
</tr>
<tr>
<td><span class="tag green">候选片段</span></td>
<td>生成视频结果直接在左侧看板的候选片段区展示和勾选,后续再接组合成片。</td>
<td>生成视频结果直接在视频合成列展示和勾选,后续再接组合成片。</td>
<td>不要把 Compose 提前变成最终剪辑台;最终合成仍是占位。</td>
<td><code>/storyboard/video</code><code>generated_videos</code><code>AdRecreationBoard</code></td>
</tr>
@@ -917,12 +909,12 @@ SubjectAsset {
<h2>需求描述模板</h2>
<div class="todo">
<div class="todo-item">
<h3>左侧看板</h3>
<p>“我在左侧复刻看板的抽帧 / 音频文案 / 分镜规划 / 候选片段区,这里应该怎么展示、编辑、保存和触发下一步。”</p>
<h3>横向看板</h3>
<p>“我在横向复刻看板的素材输入 / 音频分镜 / 关键元素 / 视频合成列,这里应该怎么展示、编辑、保存和触发下一步。”</p>
</div>
<div class="todo-item">
<h3>右侧画布</h3>
<p>右侧无限画布现在是空的,我希望它展示素材对比 / 片段组合 / 时间线 / 预览墙中的哪一种,以及这些对象是否需要拖拽和缩放。”</p>
<h3>关键元素列</h3>
<p>关键帧要横着列几张,每张帧卡里要展示哪些元素、生成图和候选片段入口,哪些按钮应直接生成。”</p>
</div>
<div class="todo-item">
<h3>改分镜字段</h3>
@@ -943,6 +935,18 @@ SubjectAsset {
<h2>变更记录</h2>
<p>这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。</p>
<div class="changelog">
<article class="change">
<header>
<h3>2026-05-17 · 看板改为四列横向生产流</h3>
<span class="tag rose">UI</span>
<span class="tag cyan">Workflow</span>
</header>
<div class="body">
<p><strong>问题:</strong>左侧抽屉式看板仍像单点操作面板,不符合用户要的“从左往右推进”的广告生产逻辑。</p>
<p><strong>改动:</strong><code>AdRecreationBoard</code> 改为全屏横向四列:素材输入列按文件任务管理素材;音频解析 / 新分镜文案列把分镜从上到下排列;视频关键元素 / 抽帧生成列把关键帧横向排列,并在每张帧卡上直接生成元素和候选片段;视频合成列汇总音频、候选片段和待接入合成接口。<code>page.tsx</code> 不再渲染右侧空白 ReactFlow 画布。</p>
<p><strong>影响:</strong><code>web/components/ad-recreation-board.tsx</code><code>web/app/page.tsx</code><code>RULES.md</code><code>.project.json</code><code>docs/source-analysis.html</code>。后续需求应按“四列横向生产流”描述。</p>
</div>
</article>
<article class="change">
<header>
<h3>2026-05-17 · 主界面改为左侧信息流广告复刻看板</h3>

View File

@@ -1007,7 +1007,7 @@ export default function Home() {
<div className="canvas-bg" />
<main className="relative flex h-screen w-screen overflow-hidden">
<AdRecreationBoard data={nodeData} onGenerateVideo={handleQuickGenerateVideo} />
<div className="absolute right-4 top-4 z-30 pointer-events-auto">
<div className="absolute bottom-4 right-4 z-30 pointer-events-auto">
<ThemeToggle />
</div>
{clientReady && <AudioStrip job={audioStripJob} open={!!audioStripJob} onClose={() => setAudioStripJobId(null)} />}

View File

@@ -212,7 +212,7 @@ export function AdRecreationBoard({
</header>
<div className="min-h-0 flex-1 overflow-x-auto pb-2">
<div className="grid h-full min-w-[1520px] grid-cols-[320px_390px_1fr_360px] gap-3">
<div className="grid h-full min-w-[1280px] grid-cols-[300px_360px_minmax(390px,1fr)_320px] gap-3">
<BoardColumn
icon={<Plus className="h-4 w-4" />}
step="01"