1实现原理 · 为什么它能做到
把「口误」拆成三步流水线:机械找候选 → 必经的审查门 → 只渲染被批准的切点。判断留给 LLM/人,算术留给脚本。
### 1. Find candidates (mechanical) … ### 2. Review (the gate — REQUIRED) … ### 3. Apply approved cuts
结巴(stutter)判定=相邻两词 token 相同且间隔 <0.5s;默认删前留后。
const closeGap = b.start - a.end < 0.5; if (a.token === b.token && closeGap) { … // remove the first utterance, keep the second cut: { start: Number(a.start.toFixed(3)), end: Number(b.start.toFixed(3)) },
重录(retake)与假起点的检测不靠规则枚举,而是先按停顿/句末/16s 上限切段,再用停用词过滤后的签名做 Jaccard 相似度比对。
if (gap > 0.85 || (sentenceEnd && elapsed >= 7.5) || elapsed >= 16) { … const stop = new Set("a an and are as at be but by for from i if in is it of on or so that this to was we with you your they their there what when where why how like um uh".split(" ")); … const score = jaccard(sigs[i], sigs[j]); const sameOpening = sigs[i].slice(0, 4).filter((t, idx) => t === sigs[j][idx]).length >= 2; if (score >= 0.34 || (score >= 0.24 && sameOpening)) {
「短的首段 + 很快重启」判定为假起点,并把类型从 retake 改标 false_start。
const isFalseStart = sameOpening && firstLen < 6 && segments[j].start - segments[i].end < 12; … type: isFalseStart ? "false_start" : "retake",
检测器明确声明「不做决定」,且 SKILL.md 要求逐条读上下文,因为强调式重复与真口误在机械层面同形。
This is MECHANICAL detection only. It proposes candidate cut ranges with rich … context + a confidence + a default recommendation, but it does NOT decide.
批准清单经 apply-cuts.mjs 转成 EDL + 重定时转录;--apply 时才用 ffmpeg trim/atrim + concat 渲染,默认干跑。
if (approved.some(c => c.start < 0 || c.end > duration)) die('Cut range is outside source duration bounds'); … lines.push(`[0:v]trim=start=${r.start.toFixed(3)}:end=${r.end.toFixed(3)},setpts=PTS-STARTPTS[v${i}];`); … const ff = spawnSync("ffmpeg", ["-y", "-i", videoPath, "-/filter_complex", scriptPath, "-map", "[v]", "-map", "[a]", "-c:v", "libx264", "-preset", "medium", "-crf", "18", "-c:a", "aac", "-b:a", "192k", "-movflags", "+faststart", outputPath], { stdio: ["ignore", "ignore", "inherit"] });
2核心能力
3外部依赖
| 类型 | 依赖 |
|---|---|
| cli | Node.js(跑两个 mjs 脚本) |
| cli | ffmpeg(trim/atrim + concat 渲染,libx264/aac) |
| cli | ffprobe(转录未带时长时探源片时长) |
| cli | npx serve(只服务本地审查页 HTML,非上传) |
| cli | node scripts/build-edl-review.mjs(仓库级共享复核工具,不在本 skill 目录内) |
4风险提醒 风险提醒:蓝色 · 知晓即可
- 转录内容会进入 LLM 上下文(间接提示注入面) — 候选的 context/removes/keeps 来自 ASR 文本并被写进 MD 供 agent 逐条阅读;若转录源被污染(远端服务、他人素材),其中的指令式文本可能影响审查判断。脚本本身不执行这些文本。
- 硬连接(hard join)可能留下可听出的音频接缝 — SKILL.md 自述词间切割是硬连接,紧凑素材建议事后加 20-30ms 淡入淡出——这一步本 skill 不自动完成。
- 上游转录与成片的对应关系靠人工保证 — 若 转录与视频并非同一版(例如换过源片),切点会整体错位;master 工作流里需要『Match every transcript to its actual video』这条纪律兜底。
- 写盘不做清理,长期堆积中间产物 — EDL/转录/decisions/filter 脚本/切好的 MP4 都写在项目 assets 目录,脚本无清理逻辑,需靠项目侧 `.gitignore` 与人工整理。
5第二遍独立确认
- [ok] 目录文件清单与产物对照 — 3 个文件(SKILL.md、find-cut-candidates.mjs、apply-cuts.mjs);SKILL.md 承诺的 *.cut-candidates.json/.md 与 *.mistakes-edl.json/transcript.json/decisions.md/filter.txt 均在两个脚本的 writeFileSync 目标中逐一定位到。
- [ok] 网络面反例搜索 — 目录内 0 处 fetch/https 导入;唯一 URL 形态字样是 SKILL.md 的本地命令 `npx serve . -p 8080 -n` 与仓库级脚本名,不构成执行期外发。
- [ok] 凭证面反例搜索 — 0 处 process.env/API_KEY/TOKEN/.env;spawnSync 列表仅 ffprobe/ffmpeg,环境变量未被子进程继承修改。
- [ok] 「只渲染已批准切点」是否被代码强制 — apply-cuts.mjs 第 49-51 行以 --cuts 文件为唯一输入并校验数组与非空范围;find-cut-candidates.mjs 不含任何写视频/批准逻辑,两脚本互不自动串接。
- [ok] 文档参数 vs 脚本 argv — find 脚本解析 <transcript> 与 --out-dir(Usage 行自述一致);SKILL.md 给的命令两种形态都能对上。apply-cuts 解析 --cuts/--video/--output/--out-dir/--apply,与 SKILL.md 的调用示例逐项一致。
- [ok] 上游转录服务是否被算作本 skill 行为 — SKILL.md 只写「Requires a word-level transcript」,未指名任何服务或 key;ElevenLabs helper 属仓库级 scripts/,故按『判级对象=skill 自身目录』记入 reason/risks 而不改档。
6结论
fca023adfb7af7d9…0d30152a82