cut-story
决定视频是什么。机械剪辑只会收紧说话的顺序;此环节决定哪些主题块留存、以什么顺序、钩子在哪里。这是唯一能将25分钟的长篇大论变成6分钟视频的阶段,也是最能决定是否有人观看的阶段。
参数:$project 是项目别名,$target 是可选的目标时长(分钟)。完整请求文本在 $ARGUMENTS 中。如果未给定别名,则使用会话钩子中 PIPELINE_STATE 命名的项目,并说明选择了哪个。
下面的动词名称遵循构建合约。如果 python engine/ve.py --help 有不同意见,则以 CLI 为准——使用其名称并提及差异。
前提条件
projects/$project/project.json存在,且stage为transcribed或更后阶段。transcript.path可解析,并且transcript.word_count已设置。- 如果
stage仍为intake,则停止并先运行转写技能。
绝不要悄无声息地重复运行此环节。如果 story.blocks 已存在,先显示当前决策,并询问是修改还是替换。
步骤 1 - 获取可读的转写稿
逐词 JSON 不可读。先将其扁平化:
python engine/ve.py transcript flatten $project --numbered
这会将以每25个词为间隔带有词索引标记的运行文本输出。词索引是 story 块存储的锚点——绝不存储秒数,绝不存储时间码。
步骤 2 - 当转写稿很长时,调度 transcript-analyst
如果 word_count > 2500(大约15分钟的德语演讲),则调度 transcript-analyst 代理,而不是内联阅读转写稿。
原因:一个5000词的转写稿会消耗你本会话所需的大部分上下文,而分析器返回大约40行。你自己阅读也会产生偏见——刚读过每一句,感觉每句话都很重要。新的上下文切片更狠,这是正确的。
给代理提供:扁平化转写稿路径、目标时长、来自 output.platform 的平台、以及用户 $ARGUMENTS 中的任何指示。它会返回候选块及其决策和理由。你仍然拥有最终决定权——审查它的删除,并否决用户明确要求保留的任何删除。
低于2500词时,自己阅读转写稿。
步骤 3 - 一句话命名视频
在任何块决策之前,写一个德语句子,说明观众在结尾时会相信什么他们一开始不相信的东西。展示给用户。
如果写不出那个句子,说明素材中还没有一个视频。直白地说出来并停止——建议补录,而不是拼凑出一个无定形的东西。这是一个真实的结果,诚实交付比一个整洁的6分钟空壳更有用。
之后的每个决策都要对这个句子负责。
步骤 4 - 对转写稿进行分块
一个块是一个可以被移动的意义单元:30秒到3分钟,一个观点。块是连续的词范围,它们无间隙、无重叠地铺满整个转写稿。
不要在停顿处切块。在主题变化处切块——说话者自己的路标在德语中是可靠的:also, jetzt zum Thema, das andere ist, kurz noch, um nochmal zurückzukommen, was viele nicht wissen。
步骤 5 - 做出决策,倾向于删除
默认期望:删除录制内容的40-60%。 如果超过70%的内容被保留,说明没有做出任何决策——回去更严格地应用删除测试。
按顺序应用的删除测试:
- 信念测试。 移除该块。观众结尾时的信念会改变吗?如果不,删除它。这是主要测试;其余的都是它的快捷方式。
- 第二示例测试。 同一观点的两个示例:保留更具体的一个,删除另一个。说话者重复是为了思考,而不是为了教学。
- 孤儿测试。 为已被删除的铺垫而设置的内容现在成了噪音。删除它,并在每次其他删除后重新检查——孤儿会级联出现。
- 热身测试。 几乎任何录制的头60-90秒都是清嗓子。默认删除并告知用户你做了。这一条规则比所有填充词去除加起来更能改善视频。
- 总结测试。 对刚说过内容的口头总结("also nochmal kurz zusammengefasst")是讲话的拐杖,不是结构。除非视频是真正的教学内容且很长,否则删除。
保留信号,最强优先:数字、名字、日期、说话者承认的具体错误、具体的工作示例。具体性是存在的最强保留信号。 抽象框架很廉价,可以在十秒内重录;而具体的轶事则不行。
对于命运取决于最终时长的块,使用 "decision": "maybe"。将 maybe 保持在20%以下——超过这个比例就是优柔寡断,而非细致入微,用户将不得不做你被要求做的工作。
如果设置了 $target,进行合理性检查:将保留块的词数相加,除以说话者的实测语速(word_count / 源时长(分钟))。在写任何内容之前报告估算值。德语讲话者的头部特写语速大约为每分钟130-160词。
步骤 6 - 找到钩子
钩子几乎从不在录制开始处。人们会在热身和停止表演后,很晚才到达他们真正的观点。
先搜索最后三分之一。 寻找:一个听起来错误直到被解释的主张、一个比预期大或小的数字、一个承认的失败、一个利害关系("das hat mich zwei Wochen gekostet")。选择15-25秒——一两句话,不要一个段落。
将其写为 story.hook,包含 word_range 和一个德语 note 说明为什么它被移动了。将钩子前移是几乎总是正确的唯一重新排序。
步骤 7 - 排序,并且仅在你能够说出理由时才重新排序
重新排序只有两个合法理由:
- 钩子移到最前。
- 一个块回答了后面块提出的问题,所以它必须位于之前。
其他一切都保持录制顺序。重新排序口语材料会破坏后向引用,并且在渲染之前你不会听到破坏——到那时已经运行了三个阶段。
引用完整性检查,对每个被移动的块都是强制性的。 重新阅读被移动块的前两句话,寻找后向引用。在德语中这些会悄无声息地断裂:also, deswegen, deshalb, dadurch, dabei, wie gesagt, das, dieser/diese/dieses, außerdem, trotzdem, andererseits, wie eben erwähnt。如果一个被移动的块以这些词开头,要么将该块推迟一句话开始,要么将其标记为 maybe 并告知用户它需要一个过渡词。不要移动它并期待最好的结果。
步骤 8 - 写 story 块
将 story.blocks[] 和 story.hook 精确地按照 docs/edl-schema.md 中定义的 schema 写入 projects/$project/project.json:id、word_range(左闭右开,以词索引为单位)、label(德语)、decision(keep|drop|maybe)、order(输出顺序,可能与录制顺序不同)、rationale。
不可协商的规则:
- 没有任何内容被删除。 被删除的块保留在数组中,带有
"decision": "drop"。每个决策必须可以通过切换一个字段来逆转。用户会不同意你的一些删除,并且必须能够撤消它们而无需重新运行该环节。 rationale是一个德语分句,说明为什么,而不是什么。 "trägt das kernargument" 是有用的;"spricht über Frame-Snapping" 是一个标签,不是理由。order在保留块上是紧密的,从0开始。被删除的块获得其录制顺序的索引;它们是不活跃的,但不能冲突。- 将
stage设置为"story"。不要触碰segments[]——那是 cut-rough 的领域。
然后向用户展示一个紧凑的表格:顺序、标签、决策、预计分钟数。那个表格是可交付成果,而不是 JSON。
步骤 9 - 交接
明确说明机械剪辑现在将仅在保留块内运行,这既是正确的也是更便宜的——对即将被删除的素材进行填充词和重拍检测是浪费工作。然后提供 cut-rough 技能。
失败模式
| 症状 | 原因 | 修复 |
|---|---|---|
| 一切看起来都很重要 | 在转写稿很长时内联阅读 | 调度 transcript-analyst;新的上下文切片更狠 |
| 保留了85%的素材 | 没有做出任何编辑决策 | 对每个块重新应用信念测试 |
| 重新排序后视频跳跃异常 | 后向引用断裂 | 对每个被移动的块执行步骤7检查 |
word_range 间隙或重叠 | 块没有铺满 | 块必须是连续的且左闭右开 |
| 用户拒绝大多数删除 | 步骤3中的句子错误 | 与用户一起重写一句话论点,然后重新执行 |