refactor: merge storyboard workflow into segment board

This commit is contained in:
2026-05-17 12:06:14 +08:00
parent 7d399b8d33
commit 652a487af8
6 changed files with 53 additions and 33 deletions

View File

@@ -1,11 +1,5 @@
{ {
"entries": [ "entries": [
{
"files_changed": 1,
"message": "Codex 会话活跃 · 最近命令codex · 1 项未提交变更 · 最近提交auto-save 2026-05-14 17:15 (~1)",
"ts": "2026-05-14T09:18:43Z",
"type": "session-heartbeat"
},
{ {
"files_changed": 1, "files_changed": 1,
"hash": "397bae2", "hash": "397bae2",
@@ -3268,6 +3262,13 @@
"type": "session-heartbeat", "type": "session-heartbeat",
"message": "Codex 会话活跃 · 最近命令codex · 分支 main · 1 项未提交变更 · 最近提交auto-save 2026-05-17 11:55 (~1, -1)", "message": "Codex 会话活跃 · 最近命令codex · 分支 main · 1 项未提交变更 · 最近提交auto-save 2026-05-17 11:55 (~1, -1)",
"files_changed": 1 "files_changed": 1
},
{
"ts": "2026-05-17T12:01:08+08:00",
"type": "commit",
"message": "auto-save 2026-05-17 12:01 (+1, ~1)",
"hash": "7d399b8",
"files_changed": 2
} }
] ]
} }

View File

@@ -27,7 +27,7 @@
"type": "web_login" "type": "web_login"
} }
], ],
"description": "SKG 信息流广告快速复刻横向生产板:素材输入列(一个素材就是一次文件任务)→ 音频解析并根据产品内容生成新分镜文案 → 视频关键元素抽帧并直接生成元素/候选片段 → 视频合成列汇总音频和视频片段。", "description": "SKG 信息流广告快速复刻分镜生产板:左侧素材输入列按文件任务管理素材;右侧单一分镜生产板块按分镜纵向排列,每个分镜从上到下对应音频分镜文案、关键元素/抽帧生成、视频生成候选,完整视频合成暂为待接入入口。",
"kind": "app", "kind": "app",
"name": "SKG Marketing Studio / SKG 营销内容工作台", "name": "SKG Marketing Studio / SKG 营销内容工作台",
"ownership": "company", "ownership": "company",

View File

@@ -11,7 +11,7 @@
- 详见 `CLAUDE.md` 立项决策段 + `.memory/plan.md` 七步管线拆解 - 详见 `CLAUDE.md` 立项决策段 + `.memory/plan.md` 七步管线拆解
- 风格:`04-Dark-Gallery-Ambient`(路径:`~/Projects/research/20260305-网页风格库/04-Dark-Gallery-Ambient.md` - 风格:`04-Dark-Gallery-Ambient`(路径:`~/Projects/research/20260305-网页风格库/04-Dark-Gallery-Ambient.md`
- 第一冲刺:步骤 1-4下载 / 拆轨 / 关键帧 / ASR+翻译) - 第一冲刺:步骤 1-4下载 / 拆轨 / 关键帧 / ASR+翻译)
- 当前产品方向2026-05-17 确认):优先做信息流广告快速复刻产出,不再把主界面做成可视化流程节点;主界面为四列横向生产看板:素材输入列(一个素材就是一次文件任务)→ 音频解析 / 新分镜文案列 → 视频关键元素 / 抽帧生成列 → 视频合成列 - 当前产品方向2026-05-17 确认):优先做信息流广告快速复刻产出,不再把主界面做成可视化流程节点;主界面为“左侧素材输入列 + 右侧单一分镜生产板块”。分镜生产板块内,每个分镜从上到下依次包含音频分镜文案、该分镜关键元素 / 抽帧生成、该分镜视频生成;可继续追加草稿分镜,绑定关键帧后保存并生成候选视频。完整视频合成入口保留为待接入能力
## 部署事实 ## 部署事实
- 平台VPS `76.13.31.179`Ubuntu 24.04 / Docker Compose / Coolify Traefik - 平台VPS `76.13.31.179`Ubuntu 24.04 / Docker Compose / Coolify Traefik

View File

@@ -485,7 +485,7 @@
<h2>这个页面是产品协作地图,不是应用功能页。</h2> <h2>这个页面是产品协作地图,不是应用功能页。</h2>
<p> <p>
它把“你看到的界面、你想改的功能、实际要动的源码、可能影响的数据和接口”放在同一个地方。 它把“你看到的界面、你想改的功能、实际要动的源码、可能影响的数据和接口”放在同一个地方。
后续描述需求时,可以直接说“改横向看板的某一列 / 某个素材任务 / 某个接口行为”,这样改动范围会更准,也更容易追踪每次变更带来的影响。 后续描述需求时,可以直接说“改素材输入列 / 某个分镜卡片 / 某个接口行为”,这样改动范围会更准,也更容易追踪每次变更带来的影响。
</p> </p>
<div class="meta-grid"> <div class="meta-grid">
<div class="meta"><b>项目路径</b><span>/Users/kangwan/Projects/business/20260512-20260512-skg-tk-二创验证</span></div> <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="grid-3">
<div class="card"> <div class="card">
<h3>1. 先说你在改哪个产品区</h3> <h3>1. 先说你在改哪个产品区</h3>
<p>例如“素材输入列”、“音频解析 / 新分镜文案列”、“视频关键元素 / 抽帧生成列”、“视频合成列”。不要只说“这里乱”,要指向页面里的功能区。</p> <p>例如“素材输入列”、“分镜生产板块”、“分镜卡片里的音频文案层 / 关键元素 / 视频生成层”。不要只说“这里乱”,要指向页面里的功能区。</p>
</div> </div>
<div class="card"> <div class="card">
<h3>2. 再说这个区应该承担什么职责</h3> <h3>2. 再说这个区应该承担什么职责</h3>
@@ -569,12 +569,12 @@
<section id="pipeline" data-search> <section id="pipeline" data-search>
<h2>业务管线</h2> <h2>业务管线</h2>
<p>当前产品方向收敛为“信息流广告快速复刻横向生产板”:主界面从左到右排列四列,分别是素材输入、音频解析 / 新分镜文案、视频关键元素 / 抽帧生成、视频合成。它不再保留单独的右侧空白画布,素材、文案、关键帧、元素和候选片段都在同一张横向工作表内推进</p> <p>当前产品方向收敛为“信息流广告快速复刻分镜生产板”:主界面左侧是素材输入列,右侧是单一分镜生产板块。每个分镜卡片从上到下对应音频分镜文案、该分镜关键元素 / 抽帧生成、该分镜视频生成,用户可以继续追加草稿分镜并在绑定关键帧后保存和生成候选视频。它不再保留单独的右侧空白画布,也不再把音频、元素和合成拆成多列</p>
<div class="pipeline"> <div class="pipeline">
<div class="step"><div class="num">1</div><h3>素材输入列</h3><p>TK / 信息流视频链接或本地上传;每个素材就是一个文件任务,可在列内切换。</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">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">3</div><h3>关键元素</h3><p>在同一张分镜卡内绑定或使用关键帧,直接查看识别元素、提取元素图和生成图</p></div>
<div class="step"><div class="num">4</div><h3>视频合成列</h3><p>把音频文案和已选候选视频片段作为合成输入;最终完整 mp4 合成接口当前仍是占位。</p></div> <div class="step"><div class="num">4</div><h3>视频生成</h3><p>在同一张分镜卡底部选择模型并生成本分镜候选片段;完整 mp4 合成接口当前仍是占位。</p></div>
</div> </div>
</section> </section>
@@ -586,8 +586,9 @@
<table> <table>
<tbody> <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/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/音频条/生成任务状态;主渲染为全屏横向生产看板</td></tr> <tr><td><code>web/app/globals.css</code></td><td>全局主题变量、登录页视觉样式、ReactFlow 样式引用,以及本地开发态 <code>nextjs-portal</code> 遮挡隐藏规则</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/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/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> <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>
@@ -622,8 +623,9 @@
</div> </div>
<pre>前端主链路: <pre>前端主链路:
web/app/page.tsx web/app/page.tsx
-> 横向复刻看web/components/ad-recreation-board.tsx -> 分镜生产web/components/ad-recreation-board.tsx
-> 四列:素材输入 → 音频解析 / 新分镜文案 → 视频关键元素 / 抽帧生成 → 视频合成 -> 左侧素材输入列 + 右侧分镜卡片列表
-> 每张分镜卡:音频分镜文案 → 关键元素 / 抽帧生成 → 视频生成候选
-> 底部音频条web/components/audio-strip.tsx原音频播放 / 指针 / 英文 / 中文 / 波形 / 英文改写稿) -> 底部音频条web/components/audio-strip.tsx原音频播放 / 指针 / 英文 / 中文 / 波形 / 英文改写稿)
-> 旧节点/深度素材面板web/components/nodes/index.tsx、web/components/lightbox.tsx、web/components/storyboard-workbench.tsx底层保留当前不作为主入口 -> 旧节点/深度素材面板web/components/nodes/index.tsx、web/components/lightbox.tsx、web/components/storyboard-workbench.tsx底层保留当前不作为主入口
-> API 契约web/lib/api.ts -> API 契约web/lib/api.ts
@@ -639,14 +641,14 @@ api/main.py
<h2>界面区域到源码</h2> <h2>界面区域到源码</h2>
<div class="flow"> <div class="flow">
<div class="flow-row"> <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><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>
<div class="flow-row"> <div class="flow-row">
<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><code>StoryboardSegmentCard</code><code>DraftSegmentCard</code> in <code>web/components/ad-recreation-board.tsx</code>;复用 <code>updateStoryboard</code><code>addElement</code><code>cutoutElement</code><code>generateStoryboardVideo</code> 等接口。</span></div>
<div><strong>适合怎么描述</strong><span>关键帧卡片里的元素、生成图、生成片段按钮和横向排列应该怎么组织”。</span></div> <div><strong>适合怎么描述</strong><span>每个分镜内部音频文案、关键元素和视频生成候选从上到下应该怎么对应”。</span></div>
</div> </div>
<div class="flow-row"> <div class="flow-row">
<div><strong>你看到的区域</strong><span>旧深度素材面板(当前不作为主路径)</span></div> <div><strong>你看到的区域</strong><span>旧深度素材面板(当前不作为主路径)</span></div>
@@ -845,8 +847,8 @@ SubjectAsset {
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><span class="tag blue">横向复刻看</span></td> <td><span class="tag blue">分镜生产</span></td>
<td>承载当前主路径:素材输入列按文件任务管理素材;音频 / 分镜列解析音频并从上到下编辑分镜文字;关键元素列横向展示关键帧并直接生成元素和候选片段;合成列汇总音频和候选片段输入</td> <td>承载当前主路径:素材输入列按文件任务管理素材;分镜生产板块按分镜纵向排列;每张分镜卡从上到下编辑音频分镜文案、确认该分镜关键元素、生成本分镜候选视频;底部仅汇总完整视频合成入口</td>
<td>不要再拆回多个画布节点;不要恢复右侧空白画布占位。</td> <td>不要再拆回多个画布节点;不要恢复右侧空白画布占位。</td>
<td><code>web/components/ad-recreation-board.tsx</code><code>web/app/page.tsx</code></td> <td><code>web/components/ad-recreation-board.tsx</code><code>web/app/page.tsx</code></td>
</tr> </tr>
@@ -858,13 +860,13 @@ SubjectAsset {
</tr> </tr>
<tr> <tr>
<td><span class="tag gray">音频条</span></td> <td><span class="tag gray">音频条</span></td>
<td>横向看板第二列触发音频解析,底部 <code>AudioStrip</code> 仍负责原音频播放、字幕/口播文本、波形和配音预览。</td> <td>分镜生产板块顶部触发音频解析,底部 <code>AudioStrip</code> 仍负责原音频播放、字幕/口播文本、波形和配音预览。</td>
<td>不要阻断视觉素材管线。</td> <td>不要阻断视觉素材管线。</td>
<td><code>web/components/audio-strip.tsx</code><code>pipeline_transcribe</code><code>AudioScript</code></td> <td><code>web/components/audio-strip.tsx</code><code>pipeline_transcribe</code><code>AudioScript</code></td>
</tr> </tr>
<tr> <tr>
<td><span class="tag green">候选片段</span></td> <td><span class="tag green">候选片段</span></td>
<td>生成视频结果直接在视频合成列展示和勾选,后续再接组合成片</td> <td>生成视频结果直接显示在对应分镜卡片的视频生成层,可作为后续完整合成输入</td>
<td>不要把 Compose 提前变成最终剪辑台;最终合成仍是占位。</td> <td>不要把 Compose 提前变成最终剪辑台;最终合成仍是占位。</td>
<td><code>/storyboard/video</code><code>generated_videos</code><code>AdRecreationBoard</code></td> <td><code>/storyboard/video</code><code>generated_videos</code><code>AdRecreationBoard</code></td>
</tr> </tr>
@@ -909,12 +911,12 @@ SubjectAsset {
<h2>需求描述模板</h2> <h2>需求描述模板</h2>
<div class="todo"> <div class="todo">
<div class="todo-item"> <div class="todo-item">
<h3>横向看</h3> <h3>分镜生产</h3>
<p>“我在横向复刻看板的素材输入 / 音频分镜 / 关键元素 / 视频合成列,这里应该怎么展示、编辑、保存和触发下一步。”</p> <p>“我在素材输入列或右侧分镜生产板块,这里应该怎么展示、编辑、保存和触发下一步。”</p>
</div> </div>
<div class="todo-item"> <div class="todo-item">
<h3>关键元素列</h3> <h3>分镜卡片层级</h3>
<p>关键帧要横着列几张,每张帧卡里要展示哪些元素、生成图和候选片段入口,哪些按钮应直接生成。”</p> <p>每个分镜从上到下要如何对应音频文案、关键元素和视频生成候选,哪些内容必须跟着同一个分镜走。”</p>
</div> </div>
<div class="todo-item"> <div class="todo-item">
<h3>改分镜字段</h3> <h3>改分镜字段</h3>
@@ -935,6 +937,18 @@ SubjectAsset {
<h2>变更记录</h2> <h2>变更记录</h2>
<p>这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。</p> <p>这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。</p>
<div class="changelog"> <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>StoryboardSegmentCard</code> 从上到下依次包含音频分镜文案、每个分镜需要的关键元素、视频生成候选。新增 <code>DraftSegmentCard</code> 支持先无限追加草稿分镜,再绑定关键帧后保存和生成候选视频。完整视频合成入口保留在底部,后端合成接口仍待接入。本地开发态隐藏 <code>nextjs-portal</code>,避免 Next Issue 浮层遮挡看板截图。</p>
<p><strong>影响:</strong><code>web/components/ad-recreation-board.tsx</code><code>web/app/globals.css</code><code>RULES.md</code><code>.project.json</code><code>docs/source-analysis.html</code>。后续需求应按“素材输入列 + 分镜生产板块 + 分镜卡片三层结构”描述。</p>
</div>
</article>
<article class="change"> <article class="change">
<header> <header>
<h3>2026-05-17 · 看板改为四列横向生产流</h3> <h3>2026-05-17 · 看板改为四列横向生产流</h3>
@@ -944,7 +958,7 @@ SubjectAsset {
<div class="body"> <div class="body">
<p><strong>问题:</strong>左侧抽屉式看板仍像单点操作面板,不符合用户要的“从左往右推进”的广告生产逻辑。</p> <p><strong>问题:</strong>左侧抽屉式看板仍像单点操作面板,不符合用户要的“从左往右推进”的广告生产逻辑。</p>
<p><strong>改动:</strong><code>AdRecreationBoard</code> 改为全屏横向四列:素材输入列按文件任务管理素材;音频解析 / 新分镜文案列把分镜从上到下排列;视频关键元素 / 抽帧生成列把关键帧横向排列,并在每张帧卡上直接生成元素和候选片段;视频合成列汇总音频、候选片段和待接入合成接口。<code>page.tsx</code> 不再渲染右侧空白 ReactFlow 画布。</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> <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> </div>
</article> </article>
<article class="change"> <article class="change">

View File

@@ -124,6 +124,11 @@
} }
} }
/* Next 16 still injects its dev overlay portal for baseline warnings in local screenshots. */
nextjs-portal {
display: none !important;
}
/* ============================================================ /* ============================================================
生产登录页 · 动画角色登录风格 生产登录页 · 动画角色登录风格
============================================================ */ ============================================================ */

View File

@@ -831,7 +831,7 @@ function DraftSegmentCard({
<select value={model} onChange={(e) => setModel(e.target.value as VideoModel)} className="h-10 rounded-md border border-white/10 bg-black/55 px-2 text-[12px] text-white outline-none"> <select value={model} onChange={(e) => setModel(e.target.value as VideoModel)} className="h-10 rounded-md border border-white/10 bg-black/55 px-2 text-[12px] text-white outline-none">
{VIDEO_MODELS.map((item) => <option key={item.value} value={item.value}>{item.label}</option>)} {VIDEO_MODELS.map((item) => <option key={item.value} value={item.value}>{item.label}</option>)}
</select> </select>
<ActionButton disabled={generatingVideo || !draft.frameIndex} onClick={generateVideo}> <ActionButton disabled={generatingVideo || draft.frameIndex === null} onClick={generateVideo}>
{generatingVideo ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Play className="h-3.5 w-3.5" />} {generatingVideo ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Play className="h-3.5 w-3.5" />}
</ActionButton> </ActionButton>