diff --git a/RULES.md b/RULES.md
index 45ebd37..1e17c01 100644
--- a/RULES.md
+++ b/RULES.md
@@ -11,11 +11,11 @@
- 详见 `CLAUDE.md` 立项决策段 + `.memory/plan.md` 七步管线拆解
- 风格:`04-Dark-Gallery-Ambient`(路径:`~/Projects/research/20260305-网页风格库/04-Dark-Gallery-Ambient.md`)
- 第一冲刺:步骤 1-4(下载 / 拆轨 / 关键帧 / ASR+翻译)
-- 当前产品方向(2026-05-19 再确认):信息流广告快速复刻默认进入“三字段抽卡”工作流。主界面为“左侧素材输入列 + 右侧信息流复刻工作表”。用户粘贴 TK 链接或上传视频后点击“开始分析”,系统自动下载源视频;下载完成后并行启动两条路:音频文案路提取原音频文案/字幕,并分析讲话人、语速节奏、背景音乐/环境声/音效;视频视觉路自动抽取参考帧,供人工选择可用主体并生成相似主体白底视图。产品图上传后独立形成产品资产包,自动识别视角/结构/比例并补缺角度。分镜工作台按逐句时间轴默认只露“文案 / 场景一句话 / 人物+产品+动作”,产品素材池、批量控制、三字段、视频候选和高级区都必须可折叠;视频候选无内容时默认不占大面积,有候选时默认只显示迷你缩略条,展开后才显示 4-grid。单条默认抽 4 张视频候选,顶部支持整片一键抽卡;首尾帧、视觉规划、产品出现方式和旧 6 字段保留在“高级”抽屉与后端 quick-plan 自动展开中,不能再作为客户默认闸门。
+- 当前产品方向(2026-05-19 再确认):信息流广告快速复刻默认进入“三字段候选生成”工作流。主界面为“左侧素材输入列 + 右侧信息流复刻工作表”。用户粘贴 TK 链接或上传视频后点击“开始分析”,系统自动下载源视频;下载完成后并行启动两条路:音频文案路提取原音频文案/字幕,并分析讲话人、语速节奏、背景音乐/环境声/音效;视频视觉路自动抽取参考帧,供人工选择可用主体并生成相似主体白底视图。产品图上传后独立形成产品资产包,自动识别视角/结构/比例并补缺角度。分镜工作台按逐句时间轴默认只露“文案 / 场景一句话 / 人物+产品+动作”,产品素材池、批量控制、三字段、视频候选和高级区都必须可折叠;视频候选无内容时默认不占大面积,有候选时默认只显示迷你缩略条,展开后才显示 4-grid。单条默认生成 4 个视频候选,顶部支持整片批量生成候选;首尾帧、视觉规划、产品出现方式和旧 6 字段保留在“高级”抽屉与后端 quick-plan 自动展开中,不能再作为客户默认闸门。
## 部署事实
- 平台:VPS `76.13.31.179`(Ubuntu 24.04 / Docker Compose / Coolify Traefik)
-- 发布状态:已部署并验证(2026-05-19,三字段抽卡工作流 + 折叠紧凑候选区);`https://marketing.skg.com` 已启用应用内登录页,未登录 API 返回 401,认证后首页 200;容器内 `/health` 返回 `ok:true`
+- 发布状态:已部署并验证(2026-05-19,三字段候选生成工作流 + 折叠紧凑候选区);`https://marketing.skg.com` 已启用应用内登录页,未登录 API 返回 401,认证后首页 200;容器内 `/health` 返回 `ok:true`
- 主站 / 前端:`https://marketing.skg.com`
- API / 后端:`https://marketing.skg.com/api`
- 代码仓库 / Gitea:`https://git.kang-kang.com/kangwan/20260512-skg-tk`
diff --git a/api/main.py b/api/main.py
index 93f188a..7fb79fb 100644
--- a/api/main.py
+++ b/api/main.py
@@ -6214,7 +6214,7 @@ def _enqueue_storyboard_videos(job: Job, frame: KeyFrame, req: GenerateStoryboar
bg.add_task(render_storyboard_video, *task_args)
else:
threading.Thread(target=render_storyboard_video, args=task_args, daemon=True).start()
- update(job, generated_videos=items + job.generated_videos, message=f"视频抽卡已提交 · 分镜 {frame.index + 1} · {count} 张")
+ update(job, generated_videos=items + job.generated_videos, message=f"视频候选已提交 · 分镜 {frame.index + 1} · {count} 条")
return ids
@@ -6239,7 +6239,7 @@ def _batch_generate_worker(job_id: str, req: BatchGenerateStoryboardReq) -> None
count = max(1, min(12, int(req.count_per_row or 4)))
concurrency = max(1, min(8, int(req.concurrency or 4)))
frames = list(job.frames)
- update(job, message=f"整片一键抽卡已启动 · 0/{len(frames)} 条", error="")
+ update(job, message=f"整片视频候选生成已启动 · 0/{len(frames)} 条", error="")
done = 0
def submit_one(frame: KeyFrame) -> None:
@@ -6274,15 +6274,15 @@ def _batch_generate_worker(job_id: str, req: BatchGenerateStoryboardReq) -> None
)
_enqueue_storyboard_videos(job, frame, video_req, None)
except Exception as e:
- update(job, error=f"分镜 {frame.index + 1} 抽卡失败:{str(e)[:220]}")
+ update(job, error=f"分镜 {frame.index + 1} 候选生成失败:{str(e)[:220]}")
finally:
done += 1
- update(job, message=f"整片一键抽卡进行中 · {done}/{len(frames)} 条")
+ update(job, message=f"整片视频候选生成中 · {done}/{len(frames)} 条")
with ThreadPoolExecutor(max_workers=concurrency) as executor:
futures = [executor.submit(submit_one, frame) for frame in frames]
wait(futures)
- update(job, message=f"整片一键抽卡已提交 · {len(frames)}/{len(frames)} 条 · 每条 {count} 张")
+ update(job, message=f"整片视频候选已提交 · {len(frames)}/{len(frames)} 条分镜 · 每条 {count} 个候选")
@app.post("/jobs/{job_id}/storyboard/batch-generate-all", response_model=Job)
@@ -6294,7 +6294,7 @@ def batch_generate_all_storyboard(job_id: str, req: BatchGenerateStoryboardReq)
if not job.frames:
raise HTTPException(400, "no frames to generate")
threading.Thread(target=_batch_generate_worker, args=(job_id, req), daemon=True).start()
- update(job, message=f"整片一键抽卡已启动 · {len(job.frames)} 条 · 每条 {max(1, min(12, int(req.count_per_row or 4)))} 张")
+ update(job, message=f"整片视频候选生成已启动 · {len(job.frames)} 条分镜 · 每条 {max(1, min(12, int(req.count_per_row or 4)))} 个候选")
return job
diff --git a/docs/source-analysis.html b/docs/source-analysis.html
index 39d5636..5d2d46a 100644
--- a/docs/source-analysis.html
+++ b/docs/source-analysis.html
@@ -569,7 +569,7 @@
业务管线
- 当前产品方向已收窄为“信息流广告快速复刻”:主界面左侧是素材输入列,右侧是信息流复刻工作表。顶部固定显示 01-09 流程顺序和每一步的判定依据,编号不再是装饰文本,而是按素材任务、源视频、音频文案、抽帧、主体资产、产品资产、分镜文案、三字段规划和视频候选这些状态解锁。用户粘贴 TK 链接或上传视频后点击“开始分析”,系统自动下载源视频;下载完成后并行启动音频文案路和视频视觉路。音频文案路提取原音频文案/字幕,分析讲话人、语速节奏、背景音乐/环境声/音效,并为后续新口播和分镜文案提供时间轴;视频视觉路同步抽取参考帧,参考帧只用于人工选择主体并生成相似主体白底视图。产品图上传后独立形成产品资产包:自动识别视角、左右/上下/内外侧、结构点、比例和风险,并补缺角度。最终分镜规划按逐句时间轴把文案、相似主体资产和产品资产汇合;客户默认只看“文案 / 场景一句话 / 人物+产品+动作”三字段,一键为单条抽 4 张视频候选或整片批量抽卡。首尾帧、视觉规划、产品出现方式等细节保留在高级抽屉和后端自动展开逻辑里,不再作为客户默认闸门。
+ 当前产品方向已收窄为“信息流广告快速复刻”:主界面左侧是素材输入列,右侧是信息流复刻工作表。顶部固定显示 01-09 流程顺序和每一步的判定依据,编号不再是装饰文本,而是按素材任务、源视频、音频文案、抽帧、主体资产、产品资产、分镜文案、三字段规划和视频候选这些状态解锁。用户粘贴 TK 链接或上传视频后点击“开始分析”,系统自动下载源视频;下载完成后并行启动音频文案路和视频视觉路。音频文案路提取原音频文案/字幕,分析讲话人、语速节奏、背景音乐/环境声/音效,并为后续新口播和分镜文案提供时间轴;视频视觉路同步抽取参考帧,参考帧只用于人工选择主体并生成相似主体白底视图。产品图上传后独立形成产品资产包:自动识别视角、左右/上下/内外侧、结构点、比例和风险,并补缺角度。最终分镜规划按逐句时间轴把文案、相似主体资产和产品资产汇合;客户默认只看“文案 / 场景一句话 / 人物+产品+动作”三字段,一键为单条生成 4 个视频候选或整片批量生成候选。首尾帧、视觉规划、产品出现方式等细节保留在高级抽屉和后端自动展开逻辑里,不再作为客户默认闸门。
01
素材输入 有当前素材任务即通过;输入框只负责创建或切换任务。
02
源视频下载 job.video_url 存在即通过;created/downloading 视为运行中。公开视频默认不带 cookies 下载;只有 TikTok 明确要求登录态时才配置 YTDLP_COOKIES_FILE,生产容器禁止使用 YTDLP_COOKIES_FROM_BROWSER=chrome。
@@ -579,7 +579,7 @@
06
产品素材池 product_refs 有记录即通过;不限量上传,后续按分镜最多挑 6 张。
07
分镜文案 逐句时间轴生成后进入分镜;新口播可单段或整片改写。
08
三字段规划 客户默认只编辑文案、场景一句话、人物+产品+动作;高级抽屉保留首尾帧和 6 字段。
-
09
视频候选 单条默认抽 4 张候选;候选区默认收起为状态条/迷你缩略条,展开后才显示 4-grid。
+
09
视频候选 单条默认生成 4 个候选视频;候选区默认收起为状态条/迷你缩略条,展开后才显示 4-grid。
@@ -594,7 +594,7 @@
web/app/globals.css全局主题变量、登录页视觉样式、信息流工作台同源品牌 token、ReactFlow 样式引用,以及本地开发态 nextjs-portal 遮挡隐藏规则。工作台在 skg-board-theme 内定义 --skg-gold-1、--skg-gold-2、--skg-cream、--skg-bg-*、--skg-text-*、--skg-radius-* 和按钮阴影等变量,并新增 skg-board-brand、skg-stat-card、skg-primary-action、skg-secondary-action、skg-empty-state 等样式。暗色工作台复用登录页金色聚焦、米白主按钮和弱暖光氛围;明亮模式通过 skg-board-theme--light 复用同一套结构,改成暖白底、白色 panel、黑底主 CTA 和深色文本,不另起一套界面。
web/app/page.tsx产品工作台主状态:jobs、activeJobId、生成任务状态;主渲染为全屏素材输入列 + 信息流广告复刻工作表;“开始分析”会把 job 放入并行素材分析队列,下载完成后触发 triggerTranscribe 解析音频,并触发 analyzeJob 自动抽 12 张参考帧,形成“音频文案路 + 视频视觉路”同步推进;底部吸附音频条和旧全局浮动主题按钮不再从主界面渲染,避免和工作台内的明暗模式切换重复。
web/components/ad-recreation-board.tsx信息流广告复刻工作表:顶部先展示与登录页连续的 SKG brand strip,包含 SKG 字标、“未来健康 · 营销内容工作台”和“营销内容工作台 · TK 二创”;右侧素材/任务/视频/文案统计改为米白 stat 卡片,主动作按钮统一走 skg-primary-action,次动作走 skg-secondary-action,空状态复用 AnimatedLoginCharacters。顶部由 buildWorkflowSteps 统一生成 01-09 流程顺序、状态和判定依据,WorkflowOrderBar 展示完整顺序,WorkflowStepBadge / PipelineLane / 分镜列标题共用同一套编号。左侧素材输入只负责链接/上传和任务切换,不再重复放横版原视频预览;右侧顶部用“音频文案、抽帧参考、相似主体、产品素材池”四个状态条显示后台并行进度。源视频工作区展示视频下载状态和默认折叠的文案依据。音频解析结果改成默认折叠的辅助信息,展开后同一行看讲话人/节奏/背景音;主工作区左侧放大为按 9:16 显示的竖版原视频播放器,播放器内覆盖“当前点抽帧”,按当前播放秒数手动补参考帧;右侧上方是音频波形 / 切点参考,下方左侧是参考帧池,右侧是逐句时间轴;下一行只保留“相似主体 / 主体模板”。音频波形用参考图式的连续灰色包络显示响度、停顿和密集爆点,顶部同时显示当前播放秒数、总时长和鼠标指针停点秒数。视频播放时通过 requestAnimationFrame 平滑驱动波形播放线,同时同步高亮并滚动当前句;点击音频波形或字幕行会跳转原视频时间。逐句时间轴左侧参考帧池的主入口是“自动抽帧 12 张”,一键按动作峰值目标重新抽取 12 张源视频参考帧,优先抓手势、表情变化、节奏点和镜头变化;缩略图按竖版完整比例显示不裁切并用更多列紧凑铺开,点选状态直接叠在参考帧池缩略图上,鼠标停留会通过固定浮层放大展示完整帧。“生成 10 张高清图”放在下方相似主体白底视图区,不和抽参考按钮平齐;如果用户没有勾选帧,默认把全部关键帧作为主体参考,勾选后只传已选帧;生成区可在“透明骨架 / 普通真人”之间切换,可选择桌面导入的 5 套内置形象作为创意方向,并可填写统一主体方向,例如年轻女性、更运动、更高级。关键帧和相似主体白底视图都用更小的竖版缩略图密排;白底视图只展示每个 view 的最新一张,缩略图上提供“重新生成这一张”和“删除这一张”,单张重生会用 replace_views=true 替换同一视角。前端调用 generateSubjectAssets 时按主体类型传 subject_style=transparent_human 或 source_actor,按需传 character_id,并使用 reconstruction_mode=similar;后端会把关键帧和内置形象视为同一个主体的创意证据,并锁定同一性别表现、年龄段、体型、材质、风格和视觉身份,同时生成全身多视角 + 肩颈正/左右近景 + 后颈肩背特写,避免整套图出现男女性别、老少年龄或样式混杂。主体生成完成后会形成 subject_consensus_brief,主体模板保存区可预览/编辑这段 brief。音频结果下方是信息流复刻分镜工作台:顶部产品参考区是“同一产品素材池”,不限量上传产品图,不做不同产品身份判断;上传原图推荐长边 1200-2000px、短边至少 600px,但后端会统一生成最长边 1600px、JPEG 92 的 AI 工作副本,并回显尺寸、自动转换和风险标注;上传后按“套在脖子上的 U 形肩颈按摩仪”进行同一产品批量识别,左/右按佩戴者身体左右、上/下按佩戴方向,额外标注内外侧、开口方向、局部结构点、背景类型、用途标签、生成风险和备注,用户只检查备注,鼠标悬停通过固定浮层显示大图预览,能盖过滚动容器和分镜框架;缺视角补图失败时保留重试入口。脚本区在分镜行上方提供“作者想法”和“整片改写”,每行新口播文案可直接编辑并可单段 AI 改写,分镜时间和原内容列压缩为窄摘要列,新口播列进一步收窄,把横向空间留给画面规划和首尾帧。每条音频分镜纵向排列,行内从左到右串起原内容、新口播文案、画面规划/产品融入和历史候选视频槽;画面规划区先选择镜头类型(人物/情绪、人物+产品、产品特写、场景过渡),再用人物/产品开关、首帧规划、尾帧规划和产品出现方式决定这一条到底需不需要产品图或相似主体参考。当前主流程暂停直接调用视频模型,不再提供“生成本条 · Seedance”或“一键提交全部”视频入口;行内新增“首尾帧闸门”,分别显示/生成首帧和尾帧,旧 keyframe 类型首尾帧会被忽略,只认真正的 asset 首尾帧。生成首尾帧时调用 generateSceneAsset,主体只传 subject_brief,不再传主体图;产品按端点选择最多 1-2 张硬参考图,默认正面,侧面/后颈/厚度/特写等关键词会额外补一张对应视角。关键帧只作为前置主体重构证据和行数据承载位置,不再作为后续视频首尾帧参考。视频候选槽只展示历史候选和待生成占位,按钮改为“保存本条规划 / 保存全部规划”。只有该行勾选“产品”时,首尾帧生成才会从产品素材池按端点视角策略自动挑选最多 1-2 张相关产品图;未勾选产品时不会把产品图提交给首尾帧/后续生视频模型,并走纯文字首尾帧。只有该行勾选“人物”时,才会把主体 brief 注入 prompt;否则 prompt 会明确禁止强行添加主角式透明骨架人,后端也不会再给产品特写强加透明骨架人约束。ModelTrace 会在音频解析、产品识别/补图、相似主体高清视图包、脚本改写等入口旁直接展示模型名;所有生图入口都显示并使用 gpt-image-2,没有其他图片模型 fallback;点击后用固定浮层展示模型链路、输入输出和回退逻辑。旧分镜卡、抽帧控制和视频生成组件仍保留在文件里,但当前主路径不渲染。
- AudioStoryboardPlanPanel 三字段抽卡当前分镜主路径:每行默认只显示 skg_copy_*、scene_one_line_*、action_one_line_* 三组中英字段,以及 AI 改写、抽 4 张视频、三字段折叠、候选折叠和高级抽屉按钮。quickPlanStoryboard 把三字段和主体 brief 展开为完整 StoryboardScene,generateStoryboardVideo 默认提交 count=4。候选区默认不占大面积:无候选且未展开时不渲染,已有候选时只显示横向迷你缩略条,点“候选”展开后才用 4-grid 展示进度、hover 视频预览、选中、重生、删除和清空。产品素材池、批量控制、三字段、视频候选和高级区都可折叠,高级抽屉仍展示旧 6 字段、首尾帧 prompt 和首尾帧资产槽,但客户默认不用先处理首尾帧。
+ AudioStoryboardPlanPanel 三字段候选生成当前分镜主路径:每行默认只显示 skg_copy_*、scene_one_line_*、action_one_line_* 三组中英字段,以及 AI 改写、生成 4 条视频、三字段折叠、候选折叠和高级抽屉按钮。quickPlanStoryboard 把三字段和主体 brief 展开为完整 StoryboardScene,generateStoryboardVideo 默认提交 count=4,含义是一次创建 4 个独立视频候选任务。候选区默认不占大面积:无候选且未展开时不渲染,已有候选时只显示横向迷你缩略条,点“候选”展开后才用 4-grid 展示进度、hover 视频预览、选中、重生、删除和清空。产品素材池、批量控制、三字段、视频候选和高级区都可折叠,高级抽屉仍展示旧 6 字段、首尾帧 prompt 和首尾帧资产槽,但客户默认不用先处理首尾帧。
web/components/resource-library/library-drawer.tsx全局资源中心浮窗:由工作台顶部“资源库”按钮打开,叠加在工作台上方但不阻塞主界面;尺寸、位置和当前 Tab 写入 localStorage["skg-resource-library-drawer"]。提示词 Tab 固定 5 列(场景描述、视频描述、主体描述、SKG 文案、产品角度),每列先显示 use_count 排名前 5 的“常用”,再按月份倒序分组;提示词节点常驻复制按钮,hover 可选英文/中文/双语复制,并调用 use 接口。素材 Tab 固定 4 列(主体、产品、场景、视频),节点不可拖动,按月份倒序硬编码排列;“应用到当前 job”只调用后端复制接口,得到普通 ImageRef(kind="asset") 后再写入产品素材池或复制 ID。浮窗顶部最近 24 小时横条混合显示提示词和素材;新建提示词、上传素材、删除前查引用、详情侧栏都在该组件内完成。
AdRecreationBoard 主题切换顶部指标区左侧有“明亮/暗色”按钮,使用 Sun / Moon 图标切换 skg-board-theme--light 类名,并把选择写入 localStorage["skg-board-theme"]。暗色仍是默认模式;明亮模式只改变工作台外观,不改变任务、素材、分镜、模型调用或接口数据。
SourceReferenceBuildPanel“相似主体 / 主体模板”当前承担主体资产生成和主体模板复用的前端入口:顶部用 radio 区分“用模板生成”和“不用模板(从源视频关键帧创新)”,源视频相似 不再作为模板卡混进网格。模板库把 GET /subject-templates 数据库模板和 GET /character-library/skg 内置形象合并成 120px 竖排卡片,选中态统一用 SKG 金色;当选择“不用模板”时模板网格会收起,避免把生成按钮和结果缩略图挤到折叠区域之外。保存为主体模板的名称、备注和按钮固定在模板区底部一行。下方“生成主体视图”独立显示模型链路,支持透明骨架/真人、全部 10 / 常用 4 / 自定义视图;同时新增“主体设定”,默认随机组合性别表现、年龄段、着装风格、地域人种、肤色、体型比例、发型和气质场景,也可切到手动指定。随机组合会在点击生成时解析成一套固定 profile 并传给后端 subject_profile,整包视图共用同一人设,不会一张男一张女或一张年轻一张银发。已有生成结果会优先显示在生成区标题下方,再显示控制项,避免用户生成后还要继续向下找图。主体缩略图放大为可单张重生、删除和 hover 放大的媒体卡;生成中会显示本次请求锁定的素材 ID 和主体设定,切换其他模块不会改变已经提交的生成目标。前端仍传 reconstruction_mode=similar,后端先用 VISION_MODEL 把关键帧/模板图转成非身份化文字 brief;如果 brief 失败,则继续用用户方向、模板文字、内置形象 brief 和结构化主体设定。最终主体图只走 gpt-image-2 的 /images/generations 文字生图,不再把原帧或模板图作为强 image-edit 锚点。
@@ -640,7 +640,7 @@ web/app/page.tsx
-> 开始分析:创建/激活 job → 下载完成后并行触发视频视觉路 analyzeJob 与音频文案路 triggerTranscribe
-> WorkflowOrderBar:01 素材输入 → 02 源视频下载 → 03 音频文案 → 04 抽帧参考 → 05 相似主体 → 06 产品素材池 → 07 分镜文案 → 08 三字段规划 → 09 视频候选;每步从 buildWorkflowSteps 取判定依据和状态
-> 左侧素材输入列 + 右侧 03-06 状态条 + 默认折叠的文案依据 + 源视频工作区(音频解析结果默认折叠,竖版 9:16 原视频播放器放大并内置当前点抽帧,右侧上方连续响度波形显示当前/总时长/指针停点,右侧下方左侧是参考帧池,右侧是逐句时间轴联动滚动;参考帧池缩略图自身显示是否已选,不再单独重复显示已选关键帧;下方只保留相似主体 / 主体模板和相似主体高清视图包;不勾选帧则默认用全部帧,勾选后只用已选帧,可叠加 5 套内置形象;主体模板区分为模板库与本次生成 / 入库草稿,数据库接口未完成前只允许命名和备注,不提交保存)
- -> 信息流复刻分镜工作台:06 同一产品素材池不限量上传 → 自动识别视角 / 背景 / 用途 / 风险 → 人工检查备注 → 07 逐句时间轴 / 原内容 / 新口播文案 → 08 紧凑三字段(文案、场景一句话、人物+产品+动作;可折叠)→ quick-plan 自动展开高级字段 → 单条抽 4 张视频 / 收起态迷你缩略条 / 展开态 4-grid / 再抽追加 / 选中候选 → 09 整片一键抽卡后台批量提交
+ -> 信息流复刻分镜工作台:06 同一产品素材池不限量上传 → 自动识别视角 / 背景 / 用途 / 风险 → 人工检查备注 → 07 逐句时间轴 / 原内容 / 新口播文案 → 08 紧凑三字段(文案、场景一句话、人物+产品+动作;可折叠)→ quick-plan 自动展开高级字段 → 单条生成 4 个视频候选 / 收起态迷你缩略条 / 展开态 4-grid / 追加生成 / 选中候选 → 09 整片一键后台批量提交
-> 底部音频条:不再渲染,音频结果集中到右侧工作表
-> 旧节点/深度素材面板:web/components/nodes/index.tsx、web/components/lightbox.tsx、web/components/storyboard-workbench.tsx(底层保留,当前不作为主入口)
-> API 契约:web/lib/api.ts
@@ -671,9 +671,9 @@ api/main.py
适合怎么描述 “按音频逐句生成产品分镜、每行怎样改写口播、哪几句不需要产品或人物、首帧/尾帧该怎么停、首尾帧是否已经生成并准确、产品素材池识别/补图后的备注是否准确、哪些分镜后续才值得进入单条视频候选”。
-
你看到的区域 三字段抽卡行 / 可折叠视频候选区 / 高级抽屉
+
你看到的区域 三字段候选生成行 / 可折叠视频候选区 / 高级抽屉
主要源码 AudioStoryboardPlanPanel、CompactStoryboardField、StoryboardVideoSlots、StoryboardVideoPreview in web/components/ad-recreation-board.tsx;前端接口是 quickPlanStoryboard、refineStoryboard、batchGenerateAll、generateStoryboardVideo(count) in web/lib/api.ts;后端接口和后台线程在 api/main.py。
-
适合怎么描述 “默认行只露三字段,产品/批量/三字段/候选/高级能不能折叠,候选是否默认不占大面积,AI 改写是否先预览、抽 4 张是否追加、哪个候选被选中、整片一键抽卡进度和失败重试、首尾帧细节是否只在高级里出现”。
+
适合怎么描述 “默认行只露三字段,产品/批量/三字段/候选/高级能不能折叠,候选是否默认不占大面积,AI 改写是否先预览、生成 4 个视频是否追加、哪个候选被选中、整片批量生成进度和失败重试、首尾帧细节是否只在高级里出现”。
你看到的区域 全局资源中心浮窗
@@ -1000,8 +1000,8 @@ ProductRefStateItem {
分镜保存 PUT /frames/{idx}/storyboardupdateStoryboard保存三字段中英镜像、选中视频 ID、4 图槽、时长、改造说明,以及高级抽屉里的镜头类型、人物描述、人物/产品开关、首帧规划、尾帧规划和产品出现方式。
三字段自动展开 POST /jobs/{job_id}/frames/{idx}/storyboard/quick-planquickPlanStoryboard输入 skg_copy_*、scene_one_line_*、action_one_line_* 和 subject_brief,用 REWRITE_MODEL 展开为完整 StoryboardScene,只作为视频 prompt 来源,不直接持久化。
AI 改文案 POST /jobs/{job_id}/frames/{idx}/storyboard/refinerefineStoryboard输入当前三字段和中文反馈,返回新的三字段中英镜像。前端必须先弹改前/改后预览,用户点应用后才写入行状态。
-
单条视频抽卡 POST /jobs/{job_id}/frames/{idx}/storyboard/videogenerateStoryboardVideo新增 count 和 seed,默认一次创建 4 个 GeneratedVideo 任务并立即返回 job;每个候选独立排队、生成、失败或成功。前端提交 prompt 前用 quick-plan 展开,高级首尾帧存在时继续带上,不存在时后端用参考帧/主体图/产品图透明兜底。
-
整片一键抽卡 POST /jobs/{job_id}/storyboard/batch-generate-allbatchGenerateAll输入 count_per_row=4、concurrency=4,后台遍历分镜并提交每行候选;job message 用轮询展示进度。单行失败只写 job error,不阻断其他行。
+
单条视频候选生成 POST /jobs/{job_id}/frames/{idx}/storyboard/videogenerateStoryboardVideo新增 count 和 seed,默认一次创建 4 个 GeneratedVideo 任务并立即返回 job;每个候选独立排队、生成、失败或成功。前端提交 prompt 前用 quick-plan 展开,高级首尾帧存在时继续带上,不存在时后端用参考帧/主体图/产品图透明兜底。
+
整片一键生成候选 POST /jobs/{job_id}/storyboard/batch-generate-allbatchGenerateAll输入 count_per_row=4、concurrency=4,后台遍历分镜并为每行提交 4 个视频候选;job message 用轮询展示进度。单行失败只写 job error,不阻断其他行。
生图 POST /frames/{idx}/generategenerateImage基于关键帧或已选生成图做 image-to-image,目前可用。
@@ -1034,8 +1034,8 @@ ProductRefStateItem {
候选片段
- 当前分镜主路径的抽卡结果:单条默认 4 张,支持再抽追加、选中最终视频、重生/删除/清空候选;整片一键抽卡后台批量提交。
- 不要要求客户先手动生成首帧/尾帧;不要把 prompt 全文塞进默认抽卡区,除非用户展开高级。
+ 当前分镜主路径的视频候选结果:单条默认生成 4 个候选,支持追加生成、选中最终视频、重生/删除/清空候选;整片一键后台批量提交。
+ 不要要求客户先手动生成首帧/尾帧;不要把 prompt 全文塞进默认候选区,除非用户展开高级。
/storyboard/video、generated_videos、AdRecreationBoard
@@ -1058,7 +1058,7 @@ ProductRefStateItem {
分镜工作台 4 图槽和改造说明自动保存。
音频文案轨:点击开始或提取音频后提取原文案、中文翻译、讲话人、语速节奏、背景音乐/环境声/音效;结果集中在右侧工作表展示。
GPT Image 生图;当前 IMAGE_MODEL 和主体 6 视图链路默认使用 gpt-image-2。
-
三字段分镜抽卡:默认行只露文案、场景一句话、人物+产品+动作;支持 AI 改写预览、单条抽 4 张视频、再抽追加、选中候选和整片一键抽卡后台提交。
+
三字段分镜候选生成:默认行只露文案、场景一句话、人物+产品+动作;支持 AI 改写预览、单条生成 4 个视频候选、追加生成、选中候选和整片一键后台提交。
全局资源中心:提示词库和素材库可从顶部“资源库”打开;提示词可复制并计数,素材应用到 job 时会复制成本 job 内普通 asset。
@@ -1108,6 +1108,18 @@ ProductRefStateItem {
变更记录
这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。
+
+
+ 2026-05-19 · 视频候选文案改为生成 4 个视频
+ UI
+ Storyboard
+
+
+
问题: 旧文案里的“抽卡”容易被理解成图片、抽帧或只生成缩略图,不够明确。
+
改动: 前端按钮、候选区标题、Toast、空状态和后端 job message 统一改为“生成 4 条视频 / 4 个视频候选”。接口逻辑不变:count=4 表示一次创建 4 个独立 GeneratedVideo 视频任务。
+
影响: 用户看到的是“生成候选视频”,不是“抽图片”;后续不再用“张”描述视频候选数量。
+
+
2026-05-19 · 固化生产 Docker Web 验收
@@ -1139,21 +1151,21 @@ ProductRefStateItem {
Storyboard
-
问题: 三字段抽卡改造后,候选区默认直接铺开 4-grid,占用每条分镜的大量纵向空间;产品素材池、批量控制、三字段和候选区也缺少统一折叠入口,长列表操作时很难快速扫分镜。
+
问题: 三字段候选生成改造后,候选区默认直接铺开 4-grid,占用每条分镜的大量纵向空间;产品素材池、批量控制、三字段和候选区也缺少统一折叠入口,长列表操作时很难快速扫分镜。
改动: AudioStoryboardPlanPanel 新增板块折叠状态:产品素材池、批量控制 / 作者想法、每行三字段、每行视频候选和高级抽屉都可独立收起。视频候选默认不展开;无候选且未展开时不渲染大区域,有候选时只显示横向迷你缩略条和已选 / 生成中状态,点“候选”或候选标题后才展开 4-grid 大预览。
-
影响: 默认工作台从“每条都展示候选面板”改为“行头控制 + 按需展开”。客户仍可一键抽 4 张、再抽、选中、删除或清空候选,但长分镜列表不会被空候选槽撑高;高级用户展开高级区时继续看到完整视频候选和首尾帧细节。
+
影响: 默认工作台从“每条都展示候选面板”改为“行头控制 + 按需展开”。客户仍可一键生成 4 个视频候选、追加生成、选中、删除或清空候选,但长分镜列表不会被空候选槽撑高;高级用户展开高级区时继续看到完整视频候选和首尾帧细节。
- 2026-05-19 · 分镜生成简化为三字段抽卡流
+ 2026-05-19 · 分镜生成简化为三字段候选生成流
API
UI
Storyboard
问题: 原分镜行把新口播、画面规划、人物描述、首帧、尾帧、产品出现方式和视频槽全部摊开,客户要先理解 6 字段和首尾帧闸门才能生成视频,单条也只能按旧候选逻辑慢慢提交。
-
改动: 默认行改为三字段:文案、场景一句话、人物+产品+动作;每行提供 AI 改写、抽 4 张视频和高级抽屉。高级抽屉保留原 6 字段、首尾帧 prompt 和首尾帧资产槽。候选区改为 4-grid,支持生成中状态、hover 视频预览、选中、再抽追加、单张重生、删除和清空。顶部新增整片一键抽卡,默认每条 4 张并后台提交。
+
改动: 默认行改为三字段:文案、场景一句话、人物+产品+动作;每行提供 AI 改写、生成 4 条视频和高级抽屉。高级抽屉保留原 6 字段、首尾帧 prompt 和首尾帧资产槽。候选区改为 4-grid,支持生成中状态、hover 视频预览、选中、追加生成、单条重生、删除和清空。顶部新增整片一键生成候选,默认每条 4 个候选并后台提交。
影响: StoryboardScene 新增 skg_copy_*、scene_one_line_*、action_one_line_* 和 selected_video_id。后端新增 quick-plan、refine、batch-generate-all,并让 /storyboard/video 支持 count/seed。默认 prompt 仍以英文主值提交,中文只作为镜像显示。
@@ -3190,7 +3202,7 @@ ProductRefStateItem {
问题: Video Gen 节点上方失败/完成任务卡只有整卡点击复制,不够明确;失败任务也无法从界面清掉。
-
改动: 每张视频任务卡左上角增加复制 prompt 按钮,右上角增加删除任务按钮;后端新增 DELETE /jobs/{job_id}/storyboard-videos/{video_id},删除 generated_videos 记录并清理本地任务目录。
+
改动: 每个视频任务卡左上角增加复制 prompt 按钮,右上角增加删除任务按钮;后端新增 DELETE /jobs/{job_id}/storyboard-videos/{video_id},删除 generated_videos 记录并清理本地任务目录。
影响: web/components/nodes/index.tsx、web/app/page.tsx、web/lib/api.ts、api/main.py。
diff --git a/web/components/ad-recreation-board.tsx b/web/components/ad-recreation-board.tsx
index 609e0f1..6005382 100644
--- a/web/components/ad-recreation-board.tsx
+++ b/web/components/ad-recreation-board.tsx
@@ -712,8 +712,8 @@ function buildWorkflowSteps({
id: "video",
no: "09",
title: "视频候选",
- detail: generatedVideoCount ? `${generatedVideoCount} 条候选` : "可抽 4 张",
- judge: "单条默认抽 4 张候选;整片一键抽卡后台提交,失败行可单独重试。",
+ detail: generatedVideoCount ? `${generatedVideoCount} 条候选` : "可生成 4 条",
+ judge: "单条默认生成 4 条视频候选;整片一键批量生成后台提交,失败行可单独重试。",
status: generatedVideoCount > 0 ? "ready" : stepStatus({ ready: false, blocked: !storyboardReady }),
},
]
@@ -1782,7 +1782,7 @@ export function AdRecreationBoard({
})
const workflow = workflowStepMap(workflowSteps)
const statusMessage = job?.message?.startsWith("视频生成已提交")
- ? "视频候选已提交;当前默认按紧凑三字段抽卡,首尾帧细节自动处理。"
+ ? "视频候选已提交;当前默认按紧凑三字段生成候选,首尾帧细节自动处理。"
: job?.message
useEffect(() => {
@@ -3625,9 +3625,9 @@ function AudioStoryboardPlanPanel({
size: "720x1280",
})
onJobUpdate?.(updated)
- toast.success(`分镜 ${row.index + 1} 已提交 ${count} 张视频候选`)
+ toast.success(`分镜 ${row.index + 1} 已提交 ${count} 条视频候选`)
} catch (e) {
- toast.error("视频抽卡失败:" + (e instanceof Error ? e.message : String(e)))
+ toast.error("视频候选生成失败:" + (e instanceof Error ? e.message : String(e)))
} finally {
setQuickVideoBusyRow(null)
}
@@ -4003,9 +4003,9 @@ function AudioStoryboardPlanPanel({
size: "720x1280",
})
onJobUpdate?.(updated)
- toast.success(`整片一键抽卡已启动:${rows.length} 条 × 4 张`)
+ toast.success(`整片视频候选生成已启动:${rows.length} 条分镜 × 每条 4 个候选`)
} catch (e) {
- toast.error("整片一键抽卡失败:" + (e instanceof Error ? e.message : String(e)))
+ toast.error("整片视频候选生成失败:" + (e instanceof Error ? e.message : String(e)))
} finally {
setBatchCardBusy(false)
}
@@ -4242,7 +4242,7 @@ function AudioStoryboardPlanPanel({
className="skg-primary-action inline-flex h-9 items-center justify-center gap-1 px-2.5 text-[11px] font-semibold transition disabled:cursor-not-allowed disabled:opacity-40"
>
{batchCardBusy ?
:
}
- 整片一键抽卡({rows.length}×4)
+ 整片生成候选({rows.length}×4条)
{quickVideoBusyRow === row.index ? : }
- 抽 4 张视频
+ 生成 4 条视频
) : (
-
+
)}
)
@@ -5019,9 +5019,9 @@ function StoryboardVideoSlots({
aria-expanded={expanded}
>
-
视频候选(4 张抽卡)
+
视频候选(每次 4 条)
- {videos.length ? `${videos.length} 张${runningCount ? ` · ${runningCount} 生成中` : ""}` : enabled ? "待抽卡" : "待抽帧"}
+ {videos.length ? `${videos.length} 条${runningCount ? ` · ${runningCount} 生成中` : ""}` : enabled ? "待生成" : "待抽帧"}
{selectedVideo ?
已选 {shortId(selectedVideo.id)} : null}
@@ -5034,7 +5034,7 @@ function StoryboardVideoSlots({
className="inline-flex h-7 items-center justify-center gap-1 rounded-md border border-cyan-300/20 bg-cyan-300/[0.07] px-2 text-[10px] font-semibold text-cyan-100/70 transition hover:border-cyan-300/45 hover:text-cyan-50 disabled:cursor-not-allowed disabled:opacity-35"
>
{busy ?
:
}
- {videos.length ? "再抽 4 张" : "抽 4 张"}
+ {videos.length ? "再生成 4 条" : "生成 4 条"}