千枢汇·带货素材自动混剪
概述
你把带货口播稿(或字幕)交给本技能,它把口播一句句配到你的视频素材上,裁段拼接成一条成片,
并生成一份能在剪映里直接打开的草稿工程 —— 画面、音轨、字幕、转场都已就位,进剪映只做精修。
| 维度 | 说明 |
|---|---|
| 输入 | 1 份定稿口播(纯文本 / SRT / 配音音频)+ 一批视频素材(有无原声均可,素材音频一律忽略、只认画面) |
| 产出 | 剪映草稿工程(视频轨 + 音轨 + 字幕轨 + 自适应叠化转场 + 《交付说明.txt》)|单文件分镜审阅网页|无声成片预览|带口播成片预览 |
| 它替你做 | 时间轴对齐(SRT > ASR > 字数估算)、逐句 3 候选分镜匹配、长句自动切两画面、素材占比与间隔约束、跨草稿防撞画面台账、增量重跑(没变的段不重裁) |
| 它不做 | 不写文案——口播稿请用千枢汇文案家族技能;不评审美——只认可验证的硬事实;不替你重出草稿——生成草稿会替换你剪映里的同名工程,必须显式要求 |
| 原片硬字幕 | 默认自动处理(--subs burn):逐段实测字幕矩形 → 羽化糊掉素材里别人的硬字幕 → 按你这份稿子重绘;只糊不绘、字幕交给草稿字幕轨用 --subs strip;完全不动用 --subs off。水印 / 角标不做(仍在剪映内自行裁切或遮盖) |
| 交付前保障 | 画面帧数 = 配音时长(硬校验)、逐段区间重叠检测、跨草稿台账查重、素材体检与环境体检前置 |
触发词:【混剪:】 + 任务描述(素材路径 · 口播/字幕 · 音频)。
> 千枢汇 = 品牌与达人资源对接枢纽(抖音电商带货达人/招商团长)。本技能服务达人侧"一条带货视频从口播稿到可精修草稿"的最后一公里:把口播文案/字幕匹配到用户拍摄或提供的产品展示素材上,输出剪映可打开的草稿工程。文案创作不在本技能范围内——口播稿请用千枢汇文案家族技能(见文末衔接)。
触发方式
- 显式前缀:【混剪:】后跟任务描述(素材路径 + 口播/字幕 + 音频等)。
- 隐式触发:用户给"口播文案/字幕文件 + 视频素材文件夹",要求自动剪辑、画面匹配、生成剪映草稿。
前置环境检查(每次开工先做)
- 一键体检(推荐,v1.8.0):
python scripts/doctor.py --work-dir <工作目录>—— 一次查清 ffmpeg/ffprobe 是否可用、pymediainfo/faster-whisper/yaml/rapidocr-onnxruntime装没装、剪映目录与版本、技能包完整性(内置草稿库在位)、工作目录写权限与磁盘空间,每项给修复建议。看到[ERR]先修再开工(缺 ffmpeg 这类,往下跑必然失败)。下面 1~5 是它逐项展开的细节。 - FFmpeg 可用:
ffmpeg -version(本机在D:\ffmpeg\bin)。 - 剪映 Pro 已安装(草稿根
%LOCALAPPDATA%\JianyingPro\User Data\Projects\com.lveditor.draft)。 - 当前模型支持读图(Read 工具能查看 jpg)。不支持 → 停下,明确告知用户需切换到支持视觉的模型会话继续,不要硬跑匹配。
> 例外:若frames/tags.json有效(见 Step 4),本次不需要读图,无视觉模型也能跑完。 build_draft.py必须用装了pymediainfo的解释器——本机只有 venv 里有:
C:\Users\Test\.workbuddy\binaries\python\envs\default\Scripts\python.exe。其余脚本用任一解释器均可。- 做原片字幕处理(Step 7 的
--subs,默认开)需要 OCR:rapidocr-onnxruntime——
python -m pip install rapidocr-onnxruntime(也建议用同一个envs\default)。
没装 → 用--subs off跳过,或先装上。不启用字幕处理时不会 import 这个依赖。 - 走 ASR(Step 2 档2)时用装了
faster-whisper的 venv 解释器(同一个envs\default)。
首次使用要联网下模型,国内可加HF_ENDPOINT=https://hf-mirror.com走镜像,或--model <本地模型目录>,
或直接用--estimate/ 改用手上的 SRT 降级。有 SRT 或用--estimate时用任一解释器均可。
> 命令执行面声明:本技能所有命令仅限 ffmpeg / ffprobe(视频探测、抽帧、裁剪、合成)与 python(运行本技能自带脚本),无跨技能包引用。
> 网络行为声明(如实):全流程只有一处会联网——transcribe_align.py 走 ASR 时,faster-whisper 首次使用需从模型仓库(默认 HuggingFace)下载一次模型权重并缓存到本机;模型下好后同一 --model 不再联网。国内可加 HF_ENDPOINT=https://hf-mirror.com 指向镜像,或用 --model <本地模型目录> 指定本地权重;完全不想联网就用 --estimate --duration <秒数> 走纯字数估算(零依赖、离线可用)。其余所有步骤(抽帧、裁段、拼接、审阅页、生成草稿)均不发起任何网络请求,审阅页也不连外网(静态单文件、可离线打开)。
执行流水线
Step 0 · 建任务清单
建任务清单(环境支持 TaskCreate 就用它)共 7 项:① 素材盘点抽帧 ② 时间轴(SRT / ASR / 估算)③ 视觉标签(复用或读图)④ 候选与审阅页(可选规则化自动通过)⑤ 用户确认选择 ⑥ 裁段拼接 ⑦ 生成剪映草稿 + 交付说明。
> 中途接手 / 隔天回来,先跑这一句(v1.9.0):python scripts/pipeline.py <工作目录> —— 它按目录的实际状态算出"做到第几步、卡在哪、下一步敲什么命令",只读、一个字节都不写。加 --resume 会把能自动的步骤(抽帧 / 审阅页 / 转 config / 裁段拼接)一次补跑完,跑到「该你读图」「该你选画面」就停下并告诉你;它绝不自动生成剪映草稿(那会替换你剪映里的同名工程),要 --build 显式加。--json 可拿机读结论。
Step 1 · 素材盘点与 ASCII 化
- 列出素材目录所有视频,用 ffprobe 探测每条的分辨率/帧率/时长。
- 中文路径必坑:Git Bash 下 ffmpeg/ffprobe 传中文路径报 Illegal byte sequence。先把素材复制为 ASCII 名(python 一行:
python -c "import shutil; shutil.copyfile(r'<中文原路径>', r'<work_dir>/s1.mp4')",多条依次 s1~sN),原件不动。 - 素材放
<work_dir>/根下或<work_dir>/tmp/都行——脚本(find_source_video)按「工作目录根 →tmp/」顺序自动查找,s1.mp4/s1.mov等常见扩展名都认。主推根目录;两处都找不到才会[fatal] 第 N 句用的素材 s1.mp4 不在 <work_dir> 里。 - 工作时调 python 一律用
C:/...形式路径——Windows 版 Python 不认/c/...的 MSYS 路径。 - 素材体检(v1.9.0,建议开工前先跑一次):
bash python scripts/inspect_materials.py <工作目录> # 直接指定素材(不进目录扫描):--videos s1.mp4 s2.mp4 # 已知文案总长就带上,承载能力判断更准:--text-len 37.2 # 目标画布非默认竖屏时:--canvas 1080x1920 换报告位置:--out <路径> # 希望致命项时退出码非 0(接自动化):--strict 机读结论:--json
产出《素材体检报告.md》:逐条给画幅 / 分辨率 / 时长评级,再做整体判断(条数够不够、素材承载能力够不够、有没有重复素材、有没有"加了新素材但还没抽帧")。
看到「画幅偏宽 → 会被硬拉伸变形」就先决定怎么处理:cut_segments.py --fit contain(等比缩放 + 补黑边,不裁内容)或--fit cover(等比放大 + 裁满,无黑边但裁掉边缘);不改就仍是历史行为stretch。
> ⚠️ 它只按文件元数据判断,不看画面内容——"这条素材拍得好不好看、产品有没有露脸"是 Step 4 读图的事,别指望体检报告回答。
Step 2 · 拆句计时(时间轴三档降级:SRT > ASR > 估算)
优先级固定,别跳档:手上有 SRT 就用 SRT,没有才考虑 ASR,都没有才估算。
- 档1 · 有 SRT(最高置信,精确时间码):
python scripts/parse_srt.py <字幕.srt> <work_dir>/srt_parsed.json,输出每句 start/end/dur。 - 档2 · 无 SRT、有口播音频(推荐走 ASR 真实边界,别拿字数硬估):
bash python scripts/transcribe_align.py audio.mp3 --text 口播稿.txt --out <work_dir>/srt_parsed.json # 纯 ASR(没有文本稿,用识别结果自己按标点切句):省略 --text # 零依赖降级(不装模型、不联网):加 --estimate --duration <音频秒数> # 长音频求快:--model tiny ;模型下不动:HF_ENDPOINT=https://hf-mirror.com 前缀,或 --model <本地模型目录> # 误把 .srt 传给 --text?脚本认得出时间码,会拦下(退出码 2)并让你改走档1的 parse_srt.py
三条铁律:① 文本以你的稿子为准,ASR 只给时间边界(价格/规格 ASR 常错,但那些字本来就不要);
② 对齐判据是"吞到覆盖率不再提升",不是固定阈值;③ 样本要同语言纯人声口播。 - 档3 · 都没有(仅文本稿):按 4~5 字/秒估时长、每句加 0.3~0.5s 呼吸余量,人工构造 entries(格式同 srt_parsed.json)。
- 三档输出的
srt_parsed.json都带source(srt/asr/estimate)与low_confidence:
非srt来源下游(审阅页/交付说明)会提示"低置信时间轴,重点核对每句时长"。 - 记录音频实际时长(若提供 mp3:
ffprobe -show_entries format=duration),Step 6 会用它做一致性校验。 - 需要 ASR 时用 venv 解释器(faster-whisper 只在 venv);
parse_srt.py与--estimate路径用任一解释器均可。
Step 3 · 场景自适应抽帧
跑 scripts/extract_frames.py——用 FFmpeg 场景检测找画面切换点:动作密集素材自动抽密、摆拍慢镜头自动抽稀、长静止段兜底撒帧:
python scripts/extract_frames.py s1.mp4 s2.mp4 ... --out frames
# 可选:--scene 0.35 阈值 / --min-gap 2.0 最小抽帧间隔 / --long-gap 8.0 长静止兜底
# --max-per-min 20 帧数上限 / --head 0.5 片头强制抽帧 / --fallback-interval 3.0 零切换兜底间隔
输出三份:
- frames/s{素材}_{序号}.jpg(540 宽)
- frames/manifest.json —— 每帧对应素材内真实时间秒,读图前必须先看它,禁止按旧帧号公式换算
- frames/sources.json —— 素材指纹表(文件名/字节数/时长/分辨率/帧率/帧数),标签库与跨草稿台账都靠它判断"素材有没有被换过"
两个已内置的兜底(v1.5.0):
- 片头强制抽帧:场景检测只在"画面变化处"出点,视频第 0 秒没有可比帧 → 开头镜头永远没帧。--head 0.5 兜住它(带货前 3 秒最关键)。
- 零切换退化:素材是连续长镜头/手持/镜头色调接近时,场景分数可能全部低于阈值(实测真实硬切 ≈0.73,低对比度切换只有 0.03~0.05)→ 脚本打 [warn] 并退化为 --fallback-interval 固定间隔抽帧。看到这条 warn 说明兜底生效,但要知道这批素材没有硬切点、可选镜头更少。
> 成本提示:素材动静混合时,自适应通常比固定 3s 省 ~30% 帧数且不漏关键动作;
> 若用户明确说素材全是摆拍慢镜头,可改回固定间隔抽帧(fps=1/3)。
> 抽帧有密度上限 --max-per-min(换算 cap=时长/3),短素材镜头多时提到 40~60,否则会吃掉真正的切换点。
Step 4 · 视觉标签(★先复用,再考虑读图)
这仍是流程里唯一需要视觉模型的环节,也是唯一"越用越省"的环节。
4a. 先查标签库能不能复用(详情见 references/tags-schema.md):
读 frames/tags.json + frames/sources.json,三条全过才能跳过读图:
1. tags.json 存在且 schema == 1;2. sources.json 存在;
3. tags 里每个素材的 key 与当前 sources.json 的指纹完全一致(指纹 = 文件名+字节数+时长)。
- 全部一致 → 跳过 4b/4c,直接进 Step 5,并在交付时注明"本次复用了标签库"。
- 部分一致 → 只对不一致的素材走 4b,其余复用,然后合并写回。
- 全部不一致 / 无 tags → 正常走 4b/4c。
4b. 读图理解画面(模型不支持读图 → 停在这里,提醒用户切换后把话发回来继续)
- 先读 frames/manifest.json 拿每帧真实时间,再用 Read 逐张查看关键帧(可并行多张提速)。
- 记录每段素材:一句话总述 + 分段时间表(时间区间 → 画面内容 → 关键视觉元素:盖开合/勺孔与勺子收纳/密封圈/颗粒(盐还是糖?不确定写"未确认")/玻璃通透度/罐身颜色/可读文字与品牌贴纸的有无/厨房或影棚背景/是否人手入镜)。
- 画面上的字幕/水印/贴纸文字一律忽略——不要把它们当画面内容描述、不参与口播语义匹配;但要按类型记进 overlay_text(none/subtitle/watermark/sticker/logo/mixed),供后续优先推干净画面。
- 严禁脑补画面里不存在的内容。
4c. 写回标签库:按 references/tags-schema.md 的 schema 把结果写成 frames/tags.json(含 key 指纹 + overlay_text),供下次复用。用户若指出某段描述不对,先改 tags 再往下走。
Step 5 · 候选生成 + 审阅网页(用户确认关)
5a. 写 candidates.json:每句口播给 3 个候选,每个候选含 src(素材前缀)、srcIn(推荐起始秒)、conf(高/中/低)、why(画面依据,不许脑补)、frame(选一张真实帧图文件名,用于缩略图)。
- 每段视频时长 = SRT 该句 dur(严格),实际裁切窗口 = [srcIn, srcIn + dur]。
- 匹配依据只来自 4b/复用的标签,描述里真实看到什么就写什么。
5a½ · 可选:规则化自动通过(把没争议的句子先替你选掉)
python scripts/auto_accept.py candidates.json # 默认 dry-run,只打报告不写文件
python scripts/auto_accept.py candidates.json --write # 确认后再写 selection_auto.json
- 五条规则全过才自动通过:R1 未越界 / R2 未被台账用过 / R3 区间干净(不带硬字幕水印)/ R4 关键词命中(句子内容词与候选描述有交集)/ R5 无歧义(合格候选唯一,或最高命中者严格高于其余)。
- 刻意不用模型自报置信度——它校准差、系统性偏高,越"看起来没问题"的句子越容易藏错配。
- 产物
selection_auto.json是预填:在审阅页「应用这段 JSON」一次性载入,你只审剩下没选的句子,再导出完整selection.json。它不会跳过人工确认。
5b. 生成审阅网页:
python scripts/build_review_ui.py candidates.json --out review.html
# 想让审阅页变成"可单文件带走"的一版(帧图 base64 内嵌,约几百 KB):加 --inline-images
# 长句提示阈值与生成 config 时保持一致(默认都是 3.5s):--split-over 3.5
生成单文件 review.html(纯静态,不起服务)。页面能力:左口播右候选缩略图;键盘 1/2/3 选、↑/↓ 或 j/k 换句、Enter 下一句、Backspace 清除、0 回第一句;全部采用推荐(优先挑干净(无硬字幕/水印)→ 未被台账用过 → 未越界 → 以前跑得好的候选)/清空;带硬字幕/水印的候选默认置灰并在卡片打「带X」标签,可点「字幕水印候选:弱化中」开关切换预览;带水印/角标的候选标红打「下架风险」并在页顶点名(只提示、不拦截,仍可点选);读同级 selection_auto.json,在候选卡显示「自动通过依据(字面命中):xx」;若 candidates.json 每句填了可选字段 shot_hint,会显示「文案侧镜头提示:xxx」;手动指定"起始秒 + 素材前缀";超素材时长与"与台账上次已用区间重叠"直接打标;这段画面以前用过的草稿表现好就打「★ 跑得好」(数据回流);句长达到阈值的句子提前打「长句 · 生成草稿时会切两画面」(阈值用 --split-over 与 apply_selection 对齐,默认同为 3.5s;给 0 = 不提示);时间轴若为低置信(asr/estimate)页顶会提示重点核对句界;选择自动存 localStorage,刷新不丢;导出选择结果 给出 selection.json(可一键复制 / 下载 / 粘贴回填)。
- present_files 打开
review.html,告诉用户:键盘 1/2/3 点选 → 导出选择结果 → 把 JSON 贴回来。 - 同时按
references/storyboard-template.md产出分镜匹配表 md 存档(不再作为主要确认载体)。 - 用户没回贴 selection.json 之前,不得进入 Step 6。
5c. 素材片段防重复使用(v1.4.0 硬规则)
- 单条草稿内:优先为每句口播找未使用过的画面;同一素材不同区间可多次使用,但区间尽量不交叠;实在无替代画面才允许复用,且必须在分镜表标注"⚠复用 + 理由"。
- 多条草稿(矩阵铺量):先跑 python scripts/cut_segments.py --show-ledger "<工作目录>" 看已用区间,再挑没被占用的时间段;几条草稿尽量共用同一个 --ledger。
- cut_segments.py 会做两级检测:单草稿内重叠([warn])+ 跨草稿撞区间([warn-ledger]),>0.2s 即提示复核。
Step 6 · 选择转 config(含交付前校验)
用户回贴 selection.json 后存到工作目录,然后:
python scripts/apply_selection.py selection.json --out config.json --work-dir <工作目录>
# 常用:--project-name "工程名" --strict 有问题就停 --fill-missing 允许缺句顺延
# --transition-mode adaptive|fixed|hardcut --transition-sec 0.25
# 长句切画面(v1.7.0,默认开):--split-over 3.5 --split-min-part 1.2
# --split-mode auto|candidate|shot --no-split(整句一个画面)
# 备选清单来源:--candidates <candidates.json>(默认 <工作目录>/candidates.json)
# 素材占比与间隔(v1.8.0):--max-share 0.4(单素材占画面总时长上限)
# --min-gap-lines 2(同素材两次出现至少要隔的段数)
# --balance(超限时自动把超用素材的句子换成其它候选;首句保留不动。默认只告警不换)
# 合并多份选择(后者覆盖前者):apply_selection.py sel_auto.json selection.json --out config.json
- 多份 selection 可合并:
selection位置参数接受一个或多个文件(如"自动通过结果 + 人工补选"),后面的覆盖前面的。 - 转场模式(v1.5.1):
--transition-mode adaptive(默认,自适应叠化)/fixed(固定时长--transition-sec)/hardcut(硬切,不加转场)。素材节奏很快、或想要干净硬切时用hardcut。
本步做四件事(这是"防大坑"的地方,详见references/tech-pitfalls.md坑21/22/23):
1. 覆盖度:句子没选全 → 默认报错要求补齐(--fill-missing才允许沿用上一句顺延,并会告警)。
2. 越界钳制:候选"起始点 + 句时长"超出素材总长时,把起始点前移(换用该素材更早的画面),而不是把段裁短——裁短会破坏音画同步。前移会打[warn],要回看一眼前移后画面还配不配得上这句。
3. 时长一致性:字幕首句起始是否 ≈0;字幕末句结束 vs 音频实际时长,差 > max(0.5s, 2%) 就告警。口径是"画面总长由字幕决定、音频整条铺",所以误差从后段累积,必须按末句结束来比。不要用 sum(段时长) 去比音频——字幕句间停顿在草稿里是留白、不占画面,那是正常的。
4. 跨草稿台账核对:本次选的区间是否与以前草稿用过的高度重叠。
5. 首句画面提醒(v1.8.0):第 1 句若带叠加文字会告警(0-1 秒是观众第一眼,最忌别人的水印/字幕);干净则回一条[check]。
6. 素材占比与间隔(v1.8.0):单素材占画面总时长 >--max-share(默认 0.4)、或同素材两次出现间隔 <--min-gap-lines(默认 2)段 → 告警;--balance可让脚本自动把超用素材的句子换成该句的其它候选(首句保留不动、只换不越界且不带字的)。素材条数少时占比约束物理上做不到(2 条素材单条下限就是 50%)→ 只告警、绝不报错。 - 长句切画面(v1.7.0,默认开):句长 ≥
--split-over(默认 3.5s)的句子会被拆成两小段,第二段按--split-mode找:auto(默认)先试该句的其它合格候选(跨素材优先,画面更丰富)、再试同素材离句中点最近的真实镜头切换点(切点取自frames/manifest.json,容差 ±1.2s);candidate/shot只走其中一条。挑不到合格第二段就不拆,并逐句说明原因(如"备选越界/带字""同素材没有靠近句中点的切点")——绝不硬拆。硬约束:每小段 ≥--split-min-part(默认 1.2s)、不越界、不带硬字幕水印;两小段之和严格等于该句时长,所以音频与字幕一个字都不用动、音画不会漂。产出的config.json多两个键:placements(每段绝对起播秒)与segments_meta[].idx/part/parts。 - 有
[fatal]时不生成 config.json,先修问题。 - 黑场尾段自动取
clamp(音频时长 - 段时长合计, 0.4, 3.0)(注意口径:这里是"段时长合计",不是字幕末句结束。预览文件里画面轨的实际长度就是各段之和,字幕间隙不占画面长度)。作用只是让预览总长更接近音频。
Step 7 · 裁段拼接 + 生成草稿 + 交付说明
python scripts/cut_segments.py config.json <work_dir>/cut_preview.mp4
# 看台账:python scripts/cut_segments.py --show-ledger "<work_dir>"
# 清空台账重建(会先自动备份 .bak-<时间戳>):python scripts/cut_segments.py --reset "<work_dir>"
# 关闭台账:--no-ledger 换共享台账:--ledger <路径> 指定草稿名:--draft-name "xxx"
# 不出带口播预览:--no-audio-preview
# 增量重跑(v1.9.0,默认开):--rebuild 强制全清重裁
# 画幅(v1.9.0):--fit stretch|contain|cover(默认 stretch=拉伸,同历史行为)
# 对齐预览(v1.9.0):--preview-mode aligned|tight(默认 aligned) --gap-fill freeze|black(默认 freeze 定格)
# 原片硬字幕处理(v1.10.0,默认 burn):--subs burn|strip|off --srt <字幕轴,默认 srt_parsed.json>
- 裁剪统一
-an静音——无论素材带不带音轨都同样处理,成片声音只来自用户提供的口播音频轨。 - 段数可以多于句数(v1.7.0):长句拆两段后
cuts/里段数 > 字幕句数,脚本按 config 的segments逐段裁、按placements摆位;告警一律按"第几句·前/后段"说,不会拿段序冒充句序。 - 脚本裁剪前查两级重叠(单草稿内 + 跨草稿台账),裁剪后把本次区间写回
used_ranges.json(按素材指纹记录,素材换过自动失效;原台账无法解析时先备份再写;v1.7.0 起顺带记下来源的idx/part,供复盘"哪句总在用同一段画面")。 --reset可独立清空台账(不用先给 config),清空前会自动备份成.bak-<时间戳>。- 两个预览各司其职(v1.9.0 起口径统一到了代码层):
cut_preview.mp4= 紧凑版(段紧挨着拼 + 黑场尾)——只用来"快速看画面顺序对不对"。cut_with_audio.mp4= 对齐版(默认):按 config 的placements摆段,句间停顿用定格上一帧填(--gap-fill black改成黑场,忠实还原草稿里"空隙就是黑")。总长≈音频总长,时间轴与剪映草稿逐秒一致,所以能直接听"音画节奏对不对"。--no-audio-preview可关。- 想回到旧口径(段紧挨着拼):
--preview-mode tight(注意那样音画是错位的,只能看画面顺序)。 - 为什么值得多这一步:草稿是按绝对时刻摆段的,预览若"段紧挨着拼",同一个成片就有两条不一样的时间轴 —— 预览里"第 20 句在 12.3s"和草稿里根本不是同一时刻,节奏根本听不准。
- 增量重跑(v1.9.0):
cuts/_manifest.json记着每段指纹(素材指纹 + 起始秒 + 时长 + 宽高/帧率/CRF/preset/fit)。重跑时没变的段直接复用、不跑 ffmpeg(打印「复用 N 段|重裁 M 段」),段数变少时清掉多余的旧段,对齐预览的填充段同样按需复用。只改几句画面时省下大量时间。--rebuild强制全清重裁。 - 画幅处理(v1.9.0):
--fit stretch(默认,直接拉伸,与历史行为一致)/contain(等比缩放 + 补黑边,不裁内容)/cover(等比放大 + 裁满,无黑边但裁掉边缘)。素材体检提醒"画幅不符会被拉伸变形"时用它。 - 原片硬字幕处理(v1.10.0,默认开):
--subs burn(默认)逐段实测字幕矩形 → 羽化糊掉 → 按srt_parsed.json重绘本技能字幕;strip只糊不绘(字幕交给草稿字幕轨);off完全不动(老快路径)。某段测不到字幕候选就跳过不糊;没有字幕轴时burn自动降级为strip并告警。subs已进段指纹——切档会自动全量重裁,不会复用没糊过的旧段。 - 草稿字幕轨与 burn 互斥(v1.10.0):
burn时字幕已烧进画面,build_draft.py会自动不生成字幕轨(否则叠成重影);要可编辑字幕轨就用--subs strip或build_draft.py --keep-subtitle-track。 - 黑场尾段补齐紧凑版预览长度。
# 必须用装了 pymediainfo 的 venv 解释器!
C:\Users\Test\.workbuddy\binaries\python\envs\default\Scripts\python.exe scripts/build_draft.py config.json
- 视频轨按 config 的
placements+segments摆段(v1.7.0):长句拆出的两小段在此是连续的两个时刻,字幕仍是一句一条;缺这两个键时退回老口径(一句一段、按字幕绝对时间码摆)。 - 自动铺:视频轨 + 字幕轨(SRT 原文)+ 音频轨(整段 mp3),并生成 《交付说明.txt》(草稿路径/三轨说明/自检数字/精修清单/打不开草稿的兜底方案/中途某一步挂了怎么接着跑/工作目录文件清单)。
- 主轨自动静音(v1.4.0):保存后自动把视频轨全部片段 volume=0,与裁切
-an形成双保险。要保留素材原声就写"mute_source_audio": false。 - 转场按 config 的
transition_mode(来自 apply_selection 的--transition-mode):adaptive取相邻两段中较短者的 1/3(封顶transition_max默认 0.25s、下限 0.12s,短句自动缩短避免"糊切");fixed用固定transition_sec(自动钳到较短段的一半);hardcut不加转场。 - 剪映版本自检(v1.5.1):生成前只读
%LOCALAPPDATA%\JianyingPro\Apps\目录名比对基线 5.9,低于基线打[warn]、探测不到记unknown,只提醒不阻断(换机器/未装剪映也不会卡住流程)。 - 新字幕轨样式(内置):
style=TextStyle(size=7.0, color=白)+clip_settings=ClipSettings(transform_y=-0.6)= 中下部 cy≈0.80。勿传 font_size/color_rgb(add_text_simple 会静默忽略,见坑10);transform_y 单位=半画布高、负值向下(-0.8=底部 cy0.90)。 - 内置关键坑已处理:① 手动把 transition append 到
materials.transitions;② 不传 fps 给 JyProject;③ 修 draft_meta_info.json 的 draft_name。 - 原片硬字幕自动处理(v1.10.0,默认开)——
--subs burn|strip|off(默认burn):逐段实测字幕矩形 → 羽化糊掉 → 按srt_parsed.json重绘本技能字幕。产出里会打印「糊了 N 段 / 未检出字幕跳过 M 段」;某段没测出字幕就是跳过不糊(宁可漏,不可误伤产品包装字)。没有字幕轴时 burn 自动降级为 strip 并告警。 需要 OCR:pip install rapidocr-onnxruntime。 - ⚠ 与草稿字幕轨互斥——
burn时字幕已烧进画面,build_draft.py会自动不生成字幕轨(否则叠成重影)。要可编辑字幕轨就裁段时用--subs strip,或build_draft.py --keep-subtitle-track。 - 素材水印/角标不做自动处理(糊水印属另一类操作,本技能不碰)——请提醒用户在剪映内裁切或遮盖。
Step 8 · 交付与收尾
- 带口播成片预览已由 Step 7 自动产出(
cut_with_audio.mp4,画面静音 + 配音有声);若被--no-audio-preview关掉,可手动补:ffmpeg -i cut_preview.mp4 -i audio.mp3 -map 0:v -map 1:a -c:v copy -c:a aac -shortest cut_with_audio.mp4。 - present_files 交付:
review.html(审阅页,可重开改选)+ 剪映草稿工程路径(文字告知)+ 带口播成片预览cut_with_audio.mp4+ 分镜表 md + 交付说明.txt。 - 提醒用户剪映打开草稿后可精修:封面、字幕字号(建议 36~44pt)、加 BGM、价格贴纸、导出参数。
- 交付时顺带把「数据回流」那一句命令告诉用户(v1.7.0)——《交付说明.txt》【四】第 8 条已写进去了,口头再说一遍更保险:
bash python scripts/rate_ledger.py list "<work_dir>" # 看榜:已评草稿 / 素材表现榜 python scripts/rate_ledger.py rate "<work_dir>" --perf 好 --note "跑了 3 万播放" # 缺省 = 最近一次草稿 python scripts/rate_ledger.py rate "<work_dir>" --draft "混剪_0922-1010" --perf 很好 # 指定草稿 python scripts/rate_ledger.py clear "<work_dir>" --draft "混剪_0922-1010" # 撤销表现分
表现分只写台账的perf/perf_note字段,区间记录一条都不动。 - 把 Step 6 的所有
[warn]原样复述给用户——尤其是时长不匹配和跨草稿撞区间,这两类必须让用户知情确认。 - 若素材带硬字幕(
overlay_text含subtitle):按--subs的实际档位如实说明——burn=已糊掉原字幕并重绘本技能字幕(草稿无字幕轨);strip=已糊掉原字幕、字幕在草稿字幕轨里;off=未处理,需用户在剪映内遮盖。水印/角标(watermark/logo/mixed)一律未处理,要提醒用户自行裁切或遮盖。 - 把
pipeline.py一起交代给用户(v1.9.0):以后改了选择、改了文案、或隔几天回来接着弄,跑一句
python scripts/pipeline.py "<work_dir>"就知道哪几步已完成、哪几步过期了、下一步该敲什么命令;
加--resume可直接把能自动的步骤补跑完,遇到「该你读图」「该你选画面」它会停下(不会自动生成草稿)。
素材体检报告(素材体检报告.md)也在同一目录,素材有变动时它同样会提醒。
Resources
全包自包含:无跨技能依赖(v1.4.1 起内置剪映草稿生成库)。命令执行面仅限 ffmpeg / ffprobe / python;依赖与环境要求见「前置环境检查」。
脚本速查
| 脚本 | 一句话 |
|---|---|
_common.py |
共享工具:路径 / 素材指纹 / 台账 / 回流分数 / 版本号 |
extract_frames.py |
场景自适应抽帧 |
parse_srt.py |
SRT → 结构化时间轴 |
transcribe_align.py |
无 SRT 时用 ASR 对齐时间轴(可纯估算兜底) |
build_review_ui.py |
生成单文件分镜审阅网页 |
auto_accept.py |
规则化自动通过(人只审有争议的句子) |
apply_selection.py |
你的选择 → config.json(含长句切画面) |
cut_segments.py |
逐段裁切拼接(增量重跑 / 对齐预览 / 原片字幕处理) |
strip_subs.py |
原片字幕处理内核(糊掉 + 重绘) |
build_draft.py |
生成剪映草稿工程 + 《交付说明.txt》 |
rate_ledger.py |
成片表现回流,喂给下一批选片 |
doctor.py |
开工前环境体检 |
inspect_materials.py |
开工前素材体检 |
pipeline.py |
一键续跑:按目录实际状态算进度 |
preflight_check.py |
发版前「文档 ↔ 代码」一致性自检 |
selftest.py |
技能自测(七组回归,不依赖素材) |
scripts/ · 主流程(按流水线顺序)
_common.py— 共享工具:素材探测 / 素材文件定位(find_source_video:根目录 →tmp/兜底 + 多扩展名)/ 素材指纹(source_key/key_of——台账与标签库一律走它,同一个键的读写必须用同一个构造函数)/ JSON 读写 / 区间合并 / 台账读取与查询(load_ledger/ledger_ranges/ledger_lookup:一次拿到"用没用过"+"以前表现好不好")/ 数据回流(parse_perf/perf_by_src/PERF_LABELS/PERF_CN:表现档位 很好/好/一般/差 ⇄ 4/3/2/1)/ 中文 2-gram 与单字切分(cjk_terms/cjk_chars,供关键词匹配与 ASR 对齐)/ overlay 分类(load_tags/overlay_at)/ 剪映版本探测(detect_jianying_version/jy_version_check)/ 版本号(从 SKILL.md 读,避免版本漂移)。其余脚本import _common即可。extract_frames.py— 场景自适应抽帧:FFmpeg scene 检测找切换点 → 动作抽密、慢镜抽稀、长静止段兜底;零切换时退化固定间隔并告警;片头强制抽一帧。输出帧图 +manifest.json(每帧真实时间)+sources.json(素材指纹)。parse_srt.py— SRT → 结构化 JSON(逐句 n/start/end/dur/text),支持中文路径;--source标记时间轴来源(srt/asr/estimate),输出带schema/source/low_confidence。transcribe_align.py— 音频时间轴对齐(无 SRT 的正解):faster-whisper 识别口播音频 → 文本以用户稿子为准、只用 ASR 的时间边界(2-gram 覆盖率对齐,"吞到覆盖率不再提升"判据);无文本稿则按标点切句;--estimate零依赖字数估算(按音频总长整体缩放)。三档都产出与 parse_srt 同结构的srt_parsed.json。需用装了 faster-whisper 的 venv 解释器;首次联网下模型,国内可走 HF 镜像。 误把.srt传给--text会被认出来并拦下(提示改用parse_srt.py,不产出半成品)。build_review_ui.py— 分镜审阅网页生成器:读candidates.json(+ sources/ledger/tags)→ 单文件review.html。左口播右候选缩略图、键盘点选、超时长/上次已用告警、带硬字幕水印候选置灰打标、以前跑得好的画面打「★ 跑得好」(数据回流)、长句打「会切两画面」提示(--split-over)、水印/角标候选标红打「下架风险」(只提示、不拦截)、读同级selection_auto.json在候选卡显示「自动通过依据(字面命中)」、展示文案侧shot_hint镜头提示、localStorage 暂存、导出selection.json(复制/下载/回填)。全部采用推荐的顺序=干净 → 未用过 → 不越界 → 以前跑得好 → 候选原序。不起本地服务;--inline-images可把帧图内嵌成可带走的单文件。auto_accept.py— 规则化自动通过:按 R1~R5 可验证硬事实(未越界/未被台账用过/区间干净/关键词命中/无歧义)把无争议句子先选掉,产出selection_auto.json作审阅页预填(v1.8.0 起含evidence命中依据)。默认 dry-run(--write才落盘);刻意不用模型自报置信度;证据完全打平时用「数据回流」的表现分做并列裁决(--min-hits/--max-used可调);报告里单列一行「下架风险」候选提示。apply_selection.py—selection.json→config.json(支持多份合并,后者覆盖前者),含越界起始点前移、音频与字幕时长一致性校验、跨草稿台账核对、转场模式--transition-mode、长句切画面(--split-over/--split-min-part/--split-mode/--no-split/--candidates,产出placements与segments_meta[].idx/part/parts)、首句带字告警、素材占比/间隔约束(--max-share/--min-gap-lines/--balance)、黑场尾自动计算。有致命问题时不生成 config。cut_segments.py— 按 config 的 segments 逐段裁切(统一-an静音,--fit stretch|contain|cover决定非 9:16 素材怎么塞进画布)+ 原片硬字幕处理--subs burn|strip|off(默认 burn,v1.10.0;--srt指字幕轴,默认srt_parsed.json;subs进段指纹,切档自动全量重裁;无字幕轴时 burn 降级为 strip) + 黑场尾段 + concat 拼接 + 带口播预览cut_with_audio.mp4;增量重跑(v1.9.0):cuts/_manifest.json记段指纹(含输出参数),没变的段直接复用、段数变少清多余旧段,--rebuild强制全清;对齐预览(v1.9.0):带音预览默认按placements摆段、句间停顿用定格/黑场填充(--gap-fill freeze|black,填充段放cuts/_gap/、按需复用),与剪映草稿逐秒一致(--preview-mode tight退回旧口径);段数可多于句数(长句拆两段),告警按"第几句·前/后段"说;裁剪前做单草稿内重叠 + 跨草稿台账两级检测,裁剪后写回台账(含来源idx/part);--show-ledger看已用区间+表现分、--reset独立清空并自动备份、--no-ledger本次不查不写。strip_subs.py— 原片字幕处理内核(v1.10.0):fit_transform(与cut_segments.fit_filter同语义的 stretch/contain/cover 画幅归一化)/measure_band(逐段 OCR 实测字幕矩形:先按「中心 y + 中心 x」二维聚类把同一行两侧的包装文字分出去,再只合并垂直相邻且横向中心接近的簇以处理多行字幕;单帧孤证不算数)/blur_rect(矩形内四向羽化高斯糊)/draw_sub(按实测字高重绘,过长自动缩字号)/SubStripper(出片流水线接口,mode=burn|strip,逐段矩形缓存work/subs_bands.json)。也可单段自测出样片:python strip_subs.py --src 素材.mp4 --ss 20 --nf 90 --srt srt_parsed.json --out 样片.mp4(可选--fps/--size 1080x1920/--fit/--t-offset)。需rapidocr-onnxruntime。build_draft.py— 生成剪映草稿工程:视频轨(按 config 的placements+segments摆段,支持长句拆两段 + 转场按transition_mode+ 手动注册 transition)+ 字幕轨(读cuts/_manifest.json的params.subs:burn时自动跳过,避免与画面上的字幕叠成重影;--subs可覆盖、--keep-subtitle-track可强制保留) + 音频轨 + 主轨自动静音 + 修 draft_name + 剪映版本自检 + 《交付说明.txt》(含断点续跑指引、长句拆分说明、字幕处理档位说明、数据回流回填命令)。直写内置vendor/pyJianYingDraft,无跨包依赖。需用装了 pymediainfo 的 venv 解释器运行。rate_ledger.py— 数据回流入口(v1.7.0):list看草稿表现榜与素材表现榜、rate --perf 很好/好/一般/差 [--draft 名] [--note 备注]回填表现分(缺省作用于最近一次草稿)、clear --draft 名撤销。只写台账的perf/perf_note/perf_at三个字段,区间记录一条不动;表现分只做偏好,不参与任何硬判据。--json输出给程序读。
scripts/ · 护栏与自检
doctor.py— 开工前环境体检(v1.8.0):查 ffmpeg/ffprobe 是否可用、pymediainfo/faster-whisper/yaml装没装、剪映安装目录与版本、技能包完整性(内置草稿库在位)、工作目录写权限与所在盘剩余空间,每项给修复建议;--work-dir <目录>顺带查该目录。有致命项(缺 ffmpeg 等)退出码非 0,先修再开工。inspect_materials.py— 素材体检(v1.9.0):开工前看这批素材"够不够、对不对"——画幅(非 9:16 会被硬拉伸变形)、分辨率、时长、条数、承载能力(素材总时长 vs 文案时长)、重复素材、"加了新素材但还没抽帧",产出素材体检报告.md。以工作目录里实际存在的素材文件为准(而不是迷信sources.json那张"抽帧那一刻"的快照),有现成指纹就直接用、没有才现场探测。只按文件元数据判断,不看画面内容、不评审美;默认不阻断流水线(--strict才在致命项时退出码非 0)。参数:--videos/--text-len/--canvas/--out/--json。pipeline.py— 一键续跑(v1.9.0):按工作目录的实际状态算九步进度(时间轴 → 抽帧 → 标签 → 候选 → 审阅页 → 选择 → config → 裁段 → 草稿),打印各步「完成 / 缺失 / 过期」与下一步该敲的命令;不带--resume时纯只读,一个字节都不写。--resume只自动跑安全步骤(抽帧 / 审阅页 / 转 config / 裁段拼接),跑到「该你读图」「该你选画面」就停下并说明该做什么;绝不自动生成剪映草稿(会替换你剪映里的同名工程),要--build显式加。过期判断基于文件时间与素材指纹,报告里会注明"仅供参考"。--json可拿机读结论。preflight_check.py— 发版前自检:把「文档说的」与「代码做的」做机器比对——SKILL.md 里出现的每个--flag是否都有脚本定义、脚本/references/vendor 是否都在文档里被交代、_common.py的文件名常量有没有漏写、frontmatter 必填键与 description 引号配对、skill_version()与 frontmatter 是否一致、审核风险词残留、全部脚本能否编译。改完技能跑一遍,退出码非 0 就别发。selftest.py— 技能自测:守护七组曾写错的逻辑——时间轴对齐判据(错了会让句子静默少一半)、素材定位顺序(根目录与tmp/的优先关系)、台账写回判据(错了会让--reset后首次裁剪误报"台账损坏")、长句切画面的拆分不变量(两段之和=句时长 /placements与segments等长 / 第二段不挑带字候选)、开工护栏(风险分级只按类型、--balance默认关且素材不够时不震荡)、v1.9.0 增量与对齐(段指纹必须含输出参数、复用必须先确认旧段非空、gap 之和必须严格等于目标总长、画幅判据方向不能反、续跑必须把"人工步骤"报成缺失而不是假装能自动跑)、v1.9.1 复查修复(BOM 剥除 / 时间码容错 / 编号正则不吃小数点 / 画布非法值告警 / 标签双向校验(新素材必须触发读图而不是复用)/sources.json缓存对账 / 填充段指纹必须含参数 / 首句 0 秒不生成前导填充 /doctor走子进程查 venv / 抽帧集合对账 / 依赖文件缺失判过期 /_manifest.json是数组不崩 /save_json原子写 / 草稿前导填充段落位)。不依赖任何素材:素材定位组与拆分组用空文件,台账组用 ffmpeg 现场合成 2 秒测试片,机器上没有 ffmpeg 时该组明确跳过(ffmpeg 不在 PATH 里就用--ffmpeg-dir <目录>指定)。动过transcribe_align.py/parse_srt.py/extract_frames.py/cut_segments.py/apply_selection.py/auto_accept.py/build_review_ui.py/build_draft.py/_common.py/doctor.py/inspect_materials.py/pipeline.py就跑一遍。(strip_subs.py是纯追加模块、不影响老路径;但它与cut_segments.py/build_draft.py有联动,改过就一并走 Step 7 的端到端手测。)
vendor/
pyJianYingDraft/— 内置剪映草稿生成库(自 pyJianYingDraft-open 项目 vendor,已剔除进程控制器 jianying_controller,仅保留草稿工程 JSON 生成能力;唯一第三方依赖 pymediainfo)。
references/
tech-pitfalls.md— 实战沉淀的坑清单(P0/P1/P2 分级 + v1.5.0 坑17~25 + v1.5.1/v1.6.0 坑26~36(ASR/自动通过/转场开关/版本自检/素材定位/稿子误传/台账判据) + v1.6.1 坑37~38(自检脚本别做"变形躲扫描"、全称声明必须覆盖最坏路径) + v1.7.0 坑39~42(拆段后段序≠句序、第二段必须挑不能硬拆、台账读写键必须同一套、表现分只做偏好不进硬判据) + v1.8.0 坑43~45(风险分级只能按类型不能按归属、占比约束在素材少时物理不可达、再平衡会改用户选择必须显式开关) + v1.9.0 坑46~50(段指纹漏输出参数会复用错尺寸的段、复用判据漏「文件非空」会让残段静默进成片、预览与草稿是两条时间轴必须对齐、素材体检不能迷信 sources.json 那张抽帧快照、一键续跑绝不能替用户重出草稿) + v1.9.1 坑51~57(清理格式的正则必须拿真实数据回测、带 BOM 的文件首行会被静默丢掉、标签库单向校验会让新素材覆盖已有标签、环境自检要查"真正会跑它的那个解释器"、分批追加的脚本不能整体覆盖上一批、剪映主轨第一段必被拉到 0s 要补前导填充段、"这一步做完没有"不能只看一个信号) + v1.10.0 坑58~61(按「素材」取字幕带会取到并集→每段糊掉 21% 画面、只按纵向找字幕行会把包装文字并进来、烧录字幕与草稿字幕轨会重影、「同一个产物两条生成路径」必须对拍——逐帧重采样时间基准差 1 帧 / 画幅变换语义不一致) + 解法 + 交付前验证命令),裁剪拼接和生成草稿前必读。tags-schema.md— 视觉标签库 tags.json 的 schema、字段填写规范(含overlay_text覆盖文字分类及其风险分级:水印/角标/混合=下架风险、硬字幕=可自动处理(v1.10.0)/贴纸=需留意)、复用判定规则(第 4 步跳过读图的依据)。storyboard-template.md— 分镜匹配表的 Markdown 模板与生成准则(存档用)、用户确认话术。
产物文件(工作目录)
srt_parsed.json(时间轴,带 source/low_confidence)|candidates.json(AI 候选)|review.html(审阅页)|selection_auto.json(规则化自动通过结果,可选)|selection.json(用户选择)|config.json(可复现参数)|cut_preview.mp4(无声成片)|cut_with_audio.mp4(带口播成片预览)|cuts/(逐段片段 + _manifest.json 段指纹 + _gap/ 填充段)|subs_bands.json(逐段字幕矩形缓存,--subs 开启时才有)|frames/(帧图 + manifest + sources + tags)|used_ranges.json(跨草稿台账)|交付说明.txt
与千枢汇文案技能家族衔接
- 口播稿来源:【千川素材:】→ qianshuhui-qianchuan-sucai(千川投流素材);【新文案:】→ qianshuhui-xinwenan(判品 + 5 条终稿 + 推荐);【爆款文案仿写:】→ qianshuhui-baokuan-fangxie;【开头优化:】→ qianshuhui-kaipianyouhua。
- 本技能拿到定稿口播(纯文本或 SRT 字幕)后即承担"画面匹配 + 工程生成";文案家族技能产出后如需成片,可引导触发本技能。
- 本技能自包含(v1.4.1 起内置草稿生成库),与 jianying-editor 技能无依赖关系。
版本变更记录
v1.10.0 | 原片硬字幕处理(--subs burn 默认开)——把 v1.3.0 砍掉的能力装回来,且这次的实现不会再踩当年的坑:
- ① 为什么能用:v1.3.0 移除它的理由是「pyJianYingDraft 蒙版坐标系不可靠,盖不准」。那条理由只对剪映蒙版路线成立;现在改在
cut_segments.py裁段的像素层直接糊(产物是普通 mp4,全程不碰蒙版坐标系)→ 当年那个阻断理由不再成立。 - ② 怎么做:新增
scripts/strip_subs.py,裁每一段时逐段实测它自己那一条字幕矩形(OCR 三层过滤:字高 1.4~5.0%、横向居中 ±0.12、宽度 6~98%)→ 矩形内四向羽化高斯糊 → 再按本技能自己的字幕文本(<work_dir>/srt_parsed.json,与草稿字幕轨同源)画回原位。重绘的文字不用 OCR 猜,直接查表,所以逐字准确、和你稿子一字不差。 - ③ 三条铁律(都是老坑换来的):绝不取并集(按素材取并集曾在每一段糊掉 21% 画面高度)→ 逐段实测它自己那一条;只糊字幕矩形、不做全宽横条(全宽会连带糊掉产品包装上的印刷字);某段测不到字幕候选就跳过不糊(宁可漏、不可误伤)。多行字幕会整块糊掉(只糊最底那行会留下上一行原字幕),但只合并垂直相邻且横向中心接近的簇 —— 顶部固定标题与底部口播字幕相距很远,不会被并进来。
- ④ 顺带解决了重影:字幕烧进画面后,草稿不再生成字幕轨(
build_draft.py读cuts/_manifest.json的params.subs自动判断),字幕相关文案也写进《交付说明.txt》。想要可编辑字幕轨:裁段时用--subs strip(只糊不绘,字幕交给草稿字幕轨),或build_draft.py --keep-subtitle-track强制保留。 - ⑤ 开关与指纹:
--subs burn|strip|off(默认burn)、--srt <字幕轴>(默认srt_parsed.json)。subs已进段指纹 —— 从off切到burn会自动全量重裁,不会复用没糊过的旧段(同一类静默错误的预防)。没有字幕轴时burn自动降级为strip并告警。 - ⑥ 不必再手工预处理素材:以前得先把素材的字幕自己处理掉、拼成一条长条再喂进来;现在直接用原素材即可。
- ⑦ 修掉一个既有崩溃:
build_draft.py的write_delivery_note()引用了main()的局部变量plan/head_pad(没有global声明)→ 每次都会 NameError,交付说明永远写不出来(草稿已存盘所以只表现为末尾报错)。改成显式传参。 - ⑧ 回归:
selftest.py七组全绿;端到端实测——a) 源↔成片逐帧对齐精确到 0 帧偏移(修掉了--subs路径重采样写成(k+1)/fps导致比fps=滤镜慢 1 帧的 bug),b) burn 与 off 两条路径只在字幕矩形内差 78,矩形外 2.3~3.0(=重编码基线)→ 零误伤,c) 草稿 JSON 实测tracks=['video'],零文字段。
v1.9.1 | 全包 BUG 复查与修复(33 项 · 不改产出形态、不改任何现有参数的默认值):
- ① 静默数据损坏(最危险,3 条)——
transcribe_align.py剥行首编号的正则会吃掉小数点(19.9元到手价变9元到手价,等于直接改你的文案)→ 已改成只认"数字 + 分隔符 + 空白"的真编号;parse_srt.py遇到带 BOM 的 SRT 会静默吞掉第一句(丢的正好是开场钩子,退出码还是 0)→ 已剥 BOM,并在"解析出 0 句"时报错退出;_common.tags_valid_for()原为单向校验(只查"标签里有的",不查"素材里新加的")→ 新加素材会被判成"没变"而重打标签、覆盖已有标签("更省"变"更费"还丢数据),已补no_tag检查。 - ② 崩溃 / 挂死(8 条)——
--fallback-interval 0曾死循环吃满内存、--canvas 0x0曾除零裸崩、_manifest.json是数组时曾 AttributeError、ffprobe 不在 PATH 时曾抛 FileNotFoundError、空entries曾 IndexError 裸崩……全部改成中文友好提示 + 非 0 退出,不再吐 Python 堆栈。 - ③ 前导填充段(新能力)——剪映会把主轨第一段强制拉到 0 秒(内置库
vendor/pyJianYingDraft/script_file.py的源码铁律)。此前若首句不从 0 秒开始,草稿里首句画面会比口播早首句起点秒。现在cut_segments.py会自动生成一段等长的前导填充(默认定格首帧--gap-fill freeze,可切黑场),build_draft.py把它摆在主轨最前 → 主轨仍从 0 起、首句真身落在正确的绝对时刻,对齐预览与剪映草稿两边一致。首句本来就从 0 起时不生成。 - ④ 自检查错了方向——
doctor.py一直用"当前解释器"探测依赖,于是把装在 venv 里的pymediainfo/faster-whisper/yaml误报成没装(长期那 3 条 WARN 全是误报)。现改为先查 venv 再查当前解释器并注明装在哪;修完 0 项致命 / 0 项提醒。 - ⑤ 进度判断不再只看一个信号——
pipeline.py抽帧过期原只比 mtime(新加素材不触发重跑)→ 改为与sources.json做集合对账;依赖文件缺失时 mtime 返回 0 会让0 > x恒假、把没做的步骤误报成已完成 → 已补存在性检查;--resume补跑后done计数曾不重算 → 已同步刷新。 - ⑥ 其它健壮性——
transcribe_align.py中文路径判定改为"看整条绝对路径"(原只看文件名,漏掉"目录带中文");extract_frames.py分批抽帧改为读回并合并已有产物(原为整体覆盖,第二批会抹掉第一批);save_json改原子写(先写.tmp-<pid>再os.replace);apply_selection.py台账缺sources.json时不再假打 ✓;--min-gap-lines改按句算(长句拆两段曾必然误报);审阅页跨盘符缩略图不再全灭。
内部:selftest.py新增第 7 组 19 项回归(BOM / 时间码容错 / 编号正则不吃小数 / 画布回退 / 标签双向校验 / 缓存对账 / 填充段指纹 / 前导填充 / doctor 子进程探测 / 集合对账 / 原子写 …),七组全绿。
v1.9.0 | 二批 · 流程与产物升级(四项):
- ① 素材体检前置
inspect_materials.py——开工前先看这批素材"够不够、对不对":画幅(非 9:16 会被硬拉伸变形,人脸变胖)、分辨率(短边过低放大后发虚)、时长(<2s 装不下任何一句)、条数(<3 条时占比约束物理上做不到)、承载能力(素材总时长 vs 文案时长,撑不起就会反复复用、有重播感)、重复素材(字节+时长完全相同),产出《素材体检报告.md》。只按文件元数据判断,不看画面内容、不评审美;默认不阻断流水线(--strict才在致命项时非 0 退出)。配合cut_segments.py --fit stretch|contain|cover:默认仍是stretch(与历史行为一致,不改你现有成片的观感),想不变形就用--fit contain(等比缩放 + 补黑边,不裁内容)或--fit cover(等比放大 + 裁满,无黑边但裁边缘)。 - ② 增量重跑——
cut_segments.py在cuts/_manifest.json里记段指纹(素材指纹 + 起始秒 + 时长 + 宽高/帧率/CRF/preset/fit),重跑时没变的段直接复用、不跑 ffmpeg;段数变少时清掉多余的旧段。50 句的活儿只改 3 句画面 → 从"重裁 50 段"变成"只重裁 3 段"。--rebuild强制全清重裁(等价旧行为)。指纹里必须含输出参数:漏了它,改尺寸后会复用旧尺寸的段,cuts/ 里混两种画幅还不报错。 - ③ 预览与草稿对齐(代码层)——此前
cut_with_audio.mp4是"段与段紧挨着拼",而剪映草稿是按placements绝对时刻摆段,于是同一个成片有两条不一样的时间轴:预览里"第 20 句在 12.3s"和草稿里根本不是同一时刻,音画节奏在预览里根本听不出来。现在带音预览也按placements摆,句间停顿用定格上一帧填(--gap-fill black可切成黑场,忠实还原草稿里"空隙就是黑"),总长≈音频总长,听到的就是成片真实节奏。无声的cut_preview.mp4仍保持紧凑(它的用途是"快速看画面顺序");--preview-mode tight可整体退回旧口径。 - ④ 一键续跑
pipeline.py——整条流水线 9 步、中间既要切模型读图又要人工审阅,"做到哪了"最耗人。《交付说明.txt》那份指引是写完就不变的静态说明,本脚本是按目录实际状态现算:pipeline.py <工作目录>只体检(一个字节都不写),--resume自动补跑能自动的步骤(抽帧 / 审阅页 / 转 config / 裁段拼接),跑到「该你读图」「该你选画面」就停下并告诉你下一步。绝不自动生成剪映草稿(那会替换你剪映里的同名工程,属破坏性动作),要--build显式加。
v1.8.0 | 开工前护栏包(六项 · 均不改产出形态):
- ① 环境体检
doctor.py——开工前把"这台机器跑不跑得动"一次查清:ffmpeg/ffprobe 是否可用、pymediainfo / faster-whisper / yaml 装没装、剪映目录与版本、技能包完整性(内置草稿库在位)、工作目录写权限与所在盘剩余空间,每项给修复建议;有致命项时退出码非 0。它查机器环境,preflight_check.py查文档↔代码,两者互补。 - ② 下架风险提示——按
overlay_text类型分级(水印/角标/混合 = 下架风险;硬字幕/贴纸 = 需留意),审阅页把这些候选标红并在页顶点名、auto_accept.py报告里单列一行[下架风险]。只提示、不拦截(审阅页仍可点选,由你拍板)——这是刻意口径:读图有"不抄字"铁律,分不清"谁的水印",所以只按类型给风险档,不承诺识别平台水印。 - ③ 首句画面专项提醒——第 1 句若带叠加文字,
apply_selection.py告警(0-1 秒是观众第一眼,最忌别人的水印/字幕);干净则回一条[check]。只提醒,换画面仍回审阅页。 - ④ 素材占比与间隔约束——
--max-share(默认 0.4)单素材占画面总时长上限、--min-gap-lines(默认 2)同素材两次出现的最小间隔,超限告警;--balance可让脚本自动把超用素材的句子换成别的候选(首句保留不动)。素材条数少时占比约束物理上做不到(2 条素材下限就是 50%)→ 永远只告警、绝不报错。 - ⑤ 文案侧镜头提示——
candidates.json支持每句可选字段shot_hint("这句想要什么画面"),审阅页原样展示「文案侧镜头提示:xxx」;上游文案技能本次不改(手工填也能用)。 - ⑥ 自动通过依据可见——
auto_accept.py把命中词与理由写进selection_auto.json的evidence,审阅页候选卡显示「自动通过依据(字面命中):xx」,让"AI 为什么挑它"看得见;明确标注仅是字面命中、不等于语义理解。
v1.7.0 | 长句切画面 + 数据回流(两项 · 主菜):
- ① 长句切画面——原先是"一句口播 = 一段连续画面",一句 5~6 秒就一个镜头挂到底,观感像 PPT。现在
apply_selection.py会把句长 ≥--split-over(默认 3.5s)的句子自动拆成两小段,第二段依次尝试:该句的其它合格候选(跨素材优先)→ 同素材离句中点最近的真实镜头切换点(切点取自frames/manifest.json,容差±1.2s);挑不到合格第二段就不拆并说明原因(绝不硬拆)。约束:每小段不短于--split-min-part(默认 1.2s)、不越界、不带硬字幕水印,两小段之和严格等于该句时长——所以音频与字幕一个字都不用动,音画不会漂。config.json因此新增placements(每段绝对起播秒)与segments_meta的idx/part/parts;build_draft.py按placements摆段(字幕仍是一句一条),cut_segments.py的告警改说"第几句·前/后段"。开关:--no-split关掉、--split-mode candidate|shot限定第二段来源;审阅页对达标的句子会提前打「长句 · 生成草稿时会切两画面」。 - ② 数据回流——新增
rate_ledger.py:成片发出去后花 1 分钟给这条草稿打个表现档位(很好/好/一般/差),记录写进跨草稿台账的perf字段;下一批选片时技能自动把跑得好的画面往前推——审阅页打「★ 跑得好」标、全部采用推荐与auto_accept.py的并列裁决优先高分区间,--show-ledger还能直接看草稿表现榜与素材表现榜。表现分只做"偏好",绝不参与任何硬判据(合规/时长/越界一律不看它)。用法:rate_ledger.py list <工作目录>看榜、rate_ledger.py rate <工作目录> --perf 好 --note "跑了 3 万播放"打分(--draft指定草稿,缺省=最近一次)、rate_ledger.py clear <工作目录> --draft <名>撤销。顺带修掉审阅页查台账用素材前缀而非素材指纹的静默失效(--show-ledger能查到、页面却永远显示"没撞过"),台账写入同时记下idx/part。
v1.6.1 | 安全审计整改(SkillHub 云鼎实验室对 1.6.0 的评估反馈)
- ① 删掉自检脚本里的措辞词表——原
preflight_check.py内置一批平台敏感词,并把词拆成两半、运行时再拼接,本意只是"不想让词表文件自身被误判",但这种写法在形态上等同于刻意回避外部扫描,风险远大于收益,该检查项已整体删除;脚本定位收窄回它本来该干的事——"文档说的和代码做的是否一致",措辞审查交还平台。 - ② 网络行为声明改为如实——原文写"无网络请求"不成立(ASR 首次使用要联网下载模型权重),已明确写出唯一会联网的那一处、可指定的镜像与本地模型目录、以及完全离线的
--estimate降级路径。 - ③ 审阅页标题转义——
build_review_ui.py的@@TITLE@@取自candidates.json的meta.product(可由用户自定义),此前直接插入 HTML,现按页面内其它字段的同一处理方式转义,消除本地页面注入点。
v1.6.0 | 时间轴与人工关口升级(三项 · 主菜)
- ① ASR 时间轴对齐——没有 SRT 时不再"拿字数硬估":
transcribe_align.py用 faster-whisper 识别口播音频出真实时间边界,文本始终以用户稿子为准、只用 ASR 的时间(价格/规格 ASR 必错,故绝不采用其识别文本);对齐判据是"吞到覆盖率不再提升"而非固定阈值(实测小分母集合上阈值会卡死、吞掉整段);降级链 SRT > ASR > 字数估算,三档都产出带source/low_confidence的srt_parsed.json,非 SRT 来源下游会提醒重点核句界。 - ② 规则化自动通过——
auto_accept.py用 R1~R5 可验证硬事实(未越界/未被台账用过/区间干净/关键词命中/无歧义)把"显然没争议"的句子先选掉,人只审有争议的几句;默认 dry-run,产物selection_auto.json只作审阅页预填;刻意不用模型自报置信度(校准差、系统性偏高,恰好在容易出错的句子上给高分)。 - ③ 台账开关——
cut_segments.py --reset <路径>可独立清空台账重建(清空前自动备份成.bak-<时间戳>),--no-ledger本次不查不写。 - ④ 收尾补丁:
_common.find_source_video统一素材定位(工作目录根 →tmp/兜底 +.mp4/.mov/.m4v/.mkv/.flv),修掉"文档说放 tmp/、脚本只认根目录"的旧不一致;transcribe_align.py会认出误传给--text的.srt(时间码行含数字、会被当句子读进来)并拦下指路parse_srt.py。 - ⑤ 发版前全包复查修正:修掉
cut_segments.py写回台账时把合法空台账误判为"原台账无法解析"(--reset后必然触发,见坑36);统一全包"风险措辞"等表述;写明黑场尾口径是"段时长合计"而非字幕末句结束;交付说明的断点续跑命令不再写死素材路径。
v1.5.1 | 快赢包(五项)
- ① 硬字幕/水印标记——
tags.json新增overlay_text枚举(none/subtitle/watermark/sticker/logo/mixed),审阅页把带字候选置灰 + 打「带X」标签,「全部采用推荐」优先挑干净画面,auto_accept.pyR3 也据此挡掉不干净区间(v1.5.1 当时仍不提供去/盖字幕,只做"优先选干净画面 + 交付时提醒";该限制已于 v1.10.0 解除——裁段时可选自动糊掉原字幕并重绘本技能字幕,见文首 v1.10.0 条目); - ② 带口播成片预览——
cut_segments.py额外产出cut_with_audio.mp4(画面静音 + 配音有声,--no-audio-preview可关); - ③ 断点续跑入口——《交付说明.txt》新增【六、中途某一步挂了怎么接着跑】,逐步给出重跑命令与幂等性说明;
- ④ 剪映版本自检——
build_draft.py只读%LOCALAPPDATA%\JianyingPro\Apps\目录名比对基线 5.9,只提醒不阻断; - ⑤ 转场模式开关——
apply_selection.py --transition-mode adaptive|fixed|hardcut(+--transition-sec)按素材类型切换转场策略。
v1.5.0 | 可用性升级(四项)
- ① 视觉标签库复用——读图结果沉淀成
frames/tags.json(素材指纹校验),同一批素材再做文案时跳过读图,成本从 O(素材数) 降到 0(见references/tags-schema.md); - ② 分镜审阅网页——
build_review_ui.py生成单文件review.html,左口播右候选缩略图、键盘 1/2/3 点选、超时长与"上次已用"告警、自动暂存、导出selection.json,把第 5 步从"对着 md 表格想象画面"变成"看着图点三下"; - ③ 跨草稿已用区间台账——
used_ranges.json按素材指纹记录每次草稿用过的源内区间,cut_segments.py裁剪前后各查一次,多条草稿撞画面会告警(矩阵铺量用--show-ledger先看后挑); - ④ 交付说明与时长校验——
apply_selection.py做"音频 vs 字幕时长一致性 + 候选越界起始点前移",build_draft.py额外写出《交付说明.txt》(草稿路径/三轨说明/自检数字/精修清单/打不开草稿的兜底方案)。另修:场景检测"零切换"静默退化(退化为固定间隔抽帧并告警)、片头强制抽一帧(--head)。
v1.4.1 | 安全合规重构(SkillHub 云鼎实验室审核反馈)
- ① 移除对同机 jianying-editor 技能的 sys.path 跨包依赖——内置
scripts/vendor/pyJianYingDraft(剔除进程控制器,仅保留草稿生成库),build_draft.py 改为直写 pyJianYingDraft 原语; - ② allowed-tools 收窄至文件工具(Read/Write/Edit/Glob/present_files),命令执行仅限 ffmpeg/ffprobe/python;
- ③ 工程名清洗逻辑内置。
v1.4.0
- ① 素材片段防重复使用规则(单草稿内区间尽量不交叠、跨草稿不受限但尽量换区间;cut_segments.py 裁剪前自动检测同素材区间重叠并告警);
- ② build_draft.py 保存后自动把主轨全部片段 volume=0(素材原声双保险,config
"mute_source_audio": false可关)。