AI agent skill · by @JimLiu
Shorts Segments
用户有一个长视频(访谈、讲座、直播回放、口播),想从中切出几支能单独发布的短视频时用:读转写找出最值得发的话题,每个话题从开头的钩子剪到讲完,建成可编辑的子视频,用户在编辑器里接着调;几支、每支多长可以交给你按话题定。需要视频的转写。不用于按主题从零做一个新的短视频,也不用于把整段口播剪干净(用剪口播)。
Archived 2026-10-23 · Source updated 2026-10-12. Check the original repository for the latest version.
SKILL.md instructions
# 从长视频里切短视频
刷到这条短视频的人没看过长视频,也不知道前面讲了什么。头三秒没抓住他,他就划走了;中间出现「刚才说的那个」,他就不知道在说什么。所以一段短视频要自己站得住:开头就是钩子,只讲一件事,停在结论上。
挑的单位是**话题**:一件事从提出到讲完。一个观点和它的理由,一个问题和它的回答,一个故事和它的落点。一支短视频就是一个话题完整的一段,不多也不少。
最容易挑坏的两种样子:
- 按长视频的章节切。一章十分钟,开头铺垫三句才说到点子上,结尾停在「接下来我们看」,里面还夹着两个话题。那是长视频的一段,不是一条短视频。
- 只找金句。一句很响的话,前后各凑几秒到要的时长:话题刚开头或还没落地就断了,观众听到一个结论却不知道为什么,或者只听到一半。
交付的是**可编辑的子视频**,不是 mp4:每一段用 videos_derive 建成父视频旁边的一个独立视频,用户在编辑器里继续调入出点、画面和字幕,要文件时再导出。
## 1. 先有转写
没有转写(kind 为 speech 的文档)时先转写,告诉用户转写在进行。挑片段只需要原文的词时间;润色和翻译只在用户要时才做。视频已经有章节时,章节有助于定位话题,但章节的边界不是短视频的边界。
## 2. 读文稿,找话题
读带时间的文稿:export 导出字幕(kind `subtitles`、format `srt`)或带时间码的文稿(kind `transcript`、format `md`、timestamps `true`),给 purpose `preview`(只是你自己读,不是交给用户的),jobs_inspect 等到 completed,读 outputs 里的文件。这些时间是剪辑后时间线上的时间,和 videos_derive 的 start、end、取帧用的是同一个时钟。
**句界怎么取**:找句子的起止不用 dump 整份 speech 文档。documents_read 读转写时,返回的 translationBasis.sentences 每一句带 start、end(秒),但那是**素材时钟**;videos_derive 的 start、end 是**时间线时钟**。父视频从 0 秒开始、原速、没有剪口地播放这条素材时,两者相同,可以直接用句子的 start、end 定区间。先确认这一点:用 videos_inspect(或 facts)看视频项的 sourceIn 是否为 0、速度是否为 1、有没有剪口。任一条不满足,就用上面导出的 SRT 或文稿里的时间线时间,或者把素材时间换算成时间线时间再传,不要把素材时间直接当时间线时间用。
### 先画话题地图
通读整份文稿(用户给了范围就读那一段),按话题切开:换了一个问题、一个观点、一个故事,就是新话题的开始。每个话题记下大致的起止、一句话说它讲什么、落点(结论、答案或包袱)在哪一句。一章里常有几个话题,一个话题也可能跨过章节边界。
### 挑最好的话题
够格的话题三条都满足,缺一条就不要:
- **有看点**:至少是这四种之一:反常识的说法、情绪的高点、密集的干货、带转折的小故事。
- **单独成立**:不看长视频也听得懂,没有「刚才说的那个」「第二点」这类要看前面才懂的指代。
- **有头有尾**:话题里有一句能直接开场的话(见下面「开头那句就是钩子」),也讲到了落点。
文稿只是线索:对够格的话题,用 videos_frames 在那几秒取几帧看画面(有没有可看的、说话人在不在画面里),再结合上下文判断是认真说的还是玩笑。帧是素材画面,不含字幕与叠加的元素。然后按看点强弱、成立得稳不稳排序,最强的在前。
### 几支
- **用户给了数**(参数页预填的话写明了支数,例如「要 N 支」):取最强的 N 个话题。够格的不足 N 个时只建够格的,不拿弱话题凑,并告诉用户为什么少了。
- **自动**(预填的话让你按话题定几支,例如「几支由你按话题定」,或用户没说):够格的话题有几个就建几支,不凑数,也不因为话题多就降低门槛。超过 10 个时先建最强的 10 支,其余在回复里列成候选(入点、出点、一句话讲什么),用户要再建。
- 两支不共用同一段话:两个候选重叠时只留更强的那个。
### 每支多长
- **自动**(预填的话让你按话题定长短,例如「每支多长按话题定」,或用户没说):长度就是这个话题的长度。起点是话题里第一句能直接开场的话,终点是落点那句说完。不为凑时长带上铺垫或下一个话题的开头,也不为压时长砍掉中间的理由或例子。话题中间夹着一大段离题的话、拖得太长时,取话题里能单独成立、也有落点的那一半,或换一个更紧的话题。
- **用户给了范围**(可能是 15–30、30–60、60–90 秒,1–3 分钟或自定义):在范围里找能讲完的话题;话题比范围长时,取它里面一个能单独成立、有落点的小点。装不下也拆不出的话题宁可不要,不切成半截;为了停在句尾超出范围几秒可以,在 reason 里写明。
- **不设平台上限**:超过 3 分钟只提一句,YouTube 不按 Shorts 收,其余照做。自动定的长度超过 3 分钟时,先看是不是包了两个话题,能拆就拆成两支。
### 边界
- **一个短视频只讲一件事**:一段里有两个话题时,拆成两支,或只留一个。
- **开头那句就是钩子**:话题开头常有铺垫(「那我们聊聊……」「其实这个问题……」),把起点挪到话题里第一句能直接抓人的话:一个反直觉的结论、一个具体的数字、一个问题。挪过之后后面的话仍要听得懂;听不懂就是挪过了头,或者这个话题没有好开头,换一个。
- **结尾停在落点上**:停在结论或包袱说完的那一句,不停在「接下来我们看……」这种半句话上;结尾是「关注、订阅」一类的话时,把终点提前到上一句。
- **开头 3 秒要有人说话**:没有时把起点挪到第一句话;不在前面加标题卡。
- **入点与出点落在句子边界**:入点取开头那句第一个词与它前一个词之间停顿的中点;出点取最后一个词与下一个词之间停顿的中点。不切进词里。边界拿不准时,略放宽一点:用户在编辑器里收比补回来容易。
- **停顿短于一帧(约 40 毫秒)时,「取停顿中点」不成立**:中点落不到一个整帧上,取整会吃进下一个词或吞掉上一个词。运行时现在会把边界收进停顿里(终点不吃下一个词的起点,起点不吞上一个词的结尾),返回的 range 是实际采用的值,可能和你传的差几帧。创建后核对返回的 range 与你要的差值:差得多、或开头结尾的词因此被截,就换一个边界重新创建,不要放着不管。
- **访谈:优先一个人不被打断的整段**。允许从回答的第一句完整句开始。开头依赖上文的句子(「另一种说法是」「这就像刚才说的」)不要当开头,往后挪到能自己成立的那一句。采访者夹一两句短插话可以接受,但要在理由里写明在哪几秒、说了什么。
- **台标、边框、水印是 go/no-go 检查**:取了帧之后看角落与边缘有没有台标、赞助条、烧进去的字幕、边框。要用的裁框会把它们切掉一半或留下半个字时,按第 4 步取景里让开台标的规则让开(裁框整个躲开台标,上下的边框裁掉),让不开就换片段,并告诉用户做了什么选择;不要留着半个台标交付。
- **已经切过的不再找**:用户提到(预填的话里有「已经切过的不再找」)或你怀疑切过时,space_list(videoId 填父视频)看已派生的子视频(origin.source 为 `derived`)和它们的区间,新的候选避开这些区间。
- 视频剪辑过时,文稿里的时间已经是剪辑后的;用户想按剪辑前的原素材切时,先和用户确认用哪个版本。
对比一下(只是示意):
不好:`12:00–14:30`,从「好,那我们接下来聊聊成本这块」开始,到「这个我们待会儿再展开」结束。
好:`12:41–13:22`,从「我们算过,一条视频的成本其实只有三块钱」开始,到「所以贵的从来不是生成,是返工」结束。
后一段是一个完整的话题:头一句就是数字,中间是理由,停在结论上,没有指代前文的话。
## 3. 先创建还是先给用户看
- 用户的话里有「找好就直接创建成视频,不用先问我」这类意思(参数页预填的话默认带这一句):找好直接进第 4 步,不在会话里一段段确认。
- 没有这句,或用户说「先给我看」:先列候选等用户挑。每段写入点与出点、讲的是哪个话题(一句话)、开头那句原话、亮点、为什么能单独成立、发现的问题(例如画面上有烧进去的字幕、分屏或并排的双机位、角落的台标或赞助条,竖屏裁切时会被切掉一半;访谈里另一人说话时画面里没有说话人)。取了帧的说看了哪几处;没看过画面的就说没看过。按把握从大到小排,用户挑定后再创建;用户说「你定」时自己定,并说明理由。
不需要在会话里反复问边界:子视频保留着整份时间线与文稿,用户在编辑器里点划掉的句子就能把它放回来。标题和理由用用户说话的语言写。
## 4. 创建子视频
对每一段调用 videos_derive:
- `video` 是父视频,`start`、`end` 是剪辑后时间线上的秒,`name` 用片段标题。
- **画幅**:用户要 9:16 时 `width` 1080、`height` 1920;1:1 时 1080×1080;保留原画幅(或没提)时不传 width、height 和 fit。不要为了「高清」把小尺寸放大。
- **取景**:传了画幅就给 `fit: "cover"`(铺满、裁掉多余)。用户说「居中」:不传 `crop` 和 `crops`,居中建好;说「我自己定」:同样居中建好,并告诉用户可以在画布上拖动画面调取景。用户没说或说「自动」(默认):走下面按镜头取景的流程。取景是按镜头切换的静态裁框,不是跟随人物的运动镜头:用户要「画面一直跟着说话的人移动」时如实说做不到,镜头内的位置请用户在编辑器里自己调。
- **取景「自动」怎么做**(提示词写的是:看说话的人在画面哪里,把裁框放到他身上;找不到人就居中):先按镜头切开,每个镜头各自按人脸检测的结果定裁框,不靠看图估位置。
1. **先分镜头,再取帧**:先用 videos_shots 的 `range`(`起:止`,这一段的时间线秒)取这一段的 `shots`(每个镜头有 `start`、`end` 和三个 `sampleAt`)与 `cuts`。它只检测画面切换,不认人。再用 videos_frames 的 `at` 传所有镜头的 `sampleAt`,每次 8 个镜头(24 帧,是单次上限)。每帧的 `faces` 是检测到的人脸框,`x`、`y`、`w`、`h` 按帧的宽高归一化到 0–1,对应素材画面,正好是 `crop` 的坐标。
2. **先分机位**:每帧看最大那张脸的面积(`w × h`)。不小于 0.01 的是**近景帧**;只有更小的脸的是**全景帧**(几个人同框的远景);没有脸的另记。一个镜头里的三帧一般是同一种机位。
3. **认出主讲人**:整段所有镜头合在一起,只看近景帧,把脸按中心横坐标(`x + w/2`)归成人,相差不到 0.1 的算同一个人。出现的帧数最多的是主讲人;帧数相近时取平均面积大的那个。另一个人的近景就是采访者(或对方)的镜头。
4. **先看边缘再定裁框**:打开几张帧图,看台标、水印、字幕条、赞助条在哪儿,估出它们的边缘(0–1,和 `crop` 同一套坐标);再看上下有没有烧进画面的边框(色条、黑边)。
5. **逐镜头定裁框**:用这个镜头自己的三帧,不拿别的镜头的位置代替。裁出的宽度比例 `cw = (画布宽 ÷ 画布高) × (原画高 × (1 − top − bottom) ÷ 原画宽)`;`left = 中心 − cw/2`,限制在 0 到 `1 − cw` 之间,`right = 1 − cw − left`。实例:16:9 的原画出 9:16、上下不裁,`cw` = 0.316;脸中心在 0.30 时给 left 0.142、right 0.542。上下有烧进去的边框时,`top`、`bottom` 给边框的高度比例把它裁掉(多给一点,不留细边),没有就给 0。
- 主讲人近景:中心取这个镜头里主讲人脸中心横坐标(`x + w/2`)的中位数。
- 采访者近景:中心取采访者的脸,让正在说话的人在画面里,这正是按镜头取景的意义。
- 全景(几张小脸、画面多半是房间):用能装下所有人的最小裁框。所有脸的外缘(最左的 `x` 到最右的 `x + w`)能放进一个宽 `cw` 的窗口时,中心取这一群人的中点;放不下时,在 notes 里写明,中心取主讲人。
- 远景里脸很小时,上下各至多裁 15%(`top`、`bottom` 都不超过 0.15)让脸大一些,不超过;有烧进去的边框时,边框高度也算在这 15% 里,边框更高就以边框为准,并在 notes 里说明。
- 相邻的镜头裁框相差不到 0.02(`left` 的差,且 `top`、`bottom` 相同)时合并成 `crops` 的一项,`from` 取前一个镜头的起点,`to` 取后一个镜头的终点。
6. **让开台标**:逐镜头检查,门槛和以前一样。台标在左边时,`left` 至少是台标右缘 + 0.01;在右边时,`left + cw` 至多是台标左缘 − 0.01(`right` 至少是 1 − 台标左缘 + 0.01)。挪了之后这个镜头的脸被裁出画面、或者两边都让不开时,这个镜头换裁框也不行,就换片段;不要交付压着半个台标的裁框。
7. **多机位**:全景镜头和采访者镜头现在有对应的裁框,不再因为它们本身换片段。只剩两条:片段**不要以对方的反应镜头开头**;全景或空镜头合起来超过这一段约 40% 时,优先换一段,并说明原因;换不了就照做,并在 notes 里写明。
8. **切换点从 videos_shots 来**:`crops` 的 `from`、`to` 直接用 `shots` 的 `start`、`end`,是逐帧准确的,不再在估出的切换点前后各 1 秒试探。只有看到某个镜头的三帧明显是两种机位(说明漏了一个切换)时,把 `threshold` 降到 0.2,对那一小段重跑 videos_shots;或在怀疑的时间点前后用 `at` 补取几帧。创建时:`crops` 传全部合并后的项(`{from, to, left, top, right, bottom}`,最多 64 项、互不重叠,都是父视频时间线的秒),同时把第一个镜头的裁框作为普通的 `crop` 传上,当作没覆盖到的帧的兜底。
9. **没有脸**:所有帧的 `faces` 都是空的,居中(不传 `crop` 和 `crops`),并如实说没找到人脸。结果的 `detector` 为 null 时是检测器不可用,不是没人:这时退回看帧图片,逐镜头估主讲人在画面哪一侧,照第 5、6 步的算法给 `crops` 和 `crop`,并说明这次是看图估的。
- **hook、reason、notes**:每一支都传。`hook` 是保留段的第一句原话,原样照抄,不改写(至多 300 字);`reason` 一句话说为什么挑它,写给用户看(至多 500 字);`notes` 是提示牌字符串数组,写取景、机位、台标检查里发现并需要用户知道的事,没有就不传。
- notes **每条至多 80 字**、至多 8 条,超了整次创建会被拒。一件事一条,拆开写,不把几件事塞进一条。
- 说到时间时写成「子视频第 X 秒(原片 Y 秒)」,两个时钟都给。一个镜头组一条,只写用户需要知道的,例如「子视频第 9–24 秒(原片 24:54–25:09)是全景,裁到两人中间」「子视频第 40–43 秒(原片 25:25–25:28)是采访者,裁到采访者」「上下紫色边框已裁掉」。开头是对方反应镜头时也写上,写成「子视频第 0–3 秒(原片 24:45–24:48)是对方的反应镜头」。
- 结果页的卡片会显示这三项,回复里不必再重复。创建后核对写进去的是不是你要的:返回结果里回显的 `hook`、`reason`、`notes` 就是派生来源文档里的那份(认回已有的子视频时是原来那份,这次传的不会改写它);也可以用 documents_read 读返回的 `derivationDocumentId`。
- `chapters: false`:30 秒的子视频不该带着父视频的整份章节。
- `captions` 按用户的字幕要求:要字幕给 `true`(默认),不要给 `false`。用户只要原文或只要译文时,字幕层的选择按他的话,做不到的(例如没有译文)如实说。
- **译文**:videos_derive 默认把父视频的译文与译文字幕层一并带到子视频;旧格式的译文会自动升级后再带。返回里出现 `translations-skipped` 警告时,告诉用户哪种语言没带上。
- **核对返回值**:`range` 是实际采用的边界,对一下和你要的差多少(见上面的短停顿);`captions[].cueCount` 只数落在区间内的 cue,不是整份字幕的条数,用它判断字幕有没有建出来、数量是否合理。
- 每一支创建后,会话里会自动出一张视频卡,不需要再贴路径。同一区间与设置重复调用会认回已有的子视频(`reused` 为 true),不会多建。
子视频是什么:整份复制父视频的时间线与文稿,区间之外的部分被剪掉,用户在编辑器里点划掉的句子就能把它放回来;原视频不动。所以不要把哪一支移入回收站,也不要为了「改边界」重建一支,让用户在编辑器里拖。
去口癖、收紧停顿会改动整个视频,不在这里做;用户要时先说明影响,按剪口播的做法在子视频上处理。
### 要如实转述的 warnings
创建结果里的 warnings 逐条告诉用户,用大白话:
- `multiple-assets`:父视频不止一份主素材,这一版只按主素材剪,别的素材跟着移动,请用户在编辑器里检查。
- `items-not-restorable`:整段落在剪掉区域里的其他轨片段不会随「恢复」回来。
- `range-not-exact`:区间之外有一部分没能剪掉(主素材盖不到),入出点会比要求的略宽。
- `captions-skipped`:字幕层没建成,说明原因,告诉用户可以在字幕面板里再建。
- `crops-adjusted`:有一段取景范围被裁短或丢掉了(超出子视频范围,或截完一帧不剩),截掉的那几帧按相邻镜头或兜底的裁框取景;告诉用户是哪几秒,请他在画布上拖一下。
- `animation-split`:画面被按取景切成了几段,循环动画或音量包络在每段的交界处会重新开始;告诉用户在哪几秒,有影响时请他在编辑器里检查。
- `translations-skipped`:父视频的这份译文没能带进子视频(旧格式换不过来),子视频里没有这门语言;告诉用户是哪种语言,可以在子视频上重新翻译。
拒绝的错误(父视频有代码画面、区间为空等)如实说,不绕开。
## 5. 成片文件
默认交付是子视频,不是 mp4。用户明确要文件时,再对子视频调用 export:kind `video`、format `mp4`,jobs_inspect 等到 completed,把 outputs 里的 path 告诉用户。时间线上的字幕默认烧进成片(burnCaptions),不要字幕时给 `false`。用户想直接导出、不建子视频时,也可以沿用在父视频上按 ranges 导出的老办法,每段一个 `{start, end}`。
## 6. 要避免的
- 不要按章节切,不要让一段里有两个话题。
- 不要只围着一句金句凑时长,话题没讲完就断;不要为了凑够支数或时长降低门槛、带上铺垫。
- 不要从铺垫开始,不要停在半句话或「关注订阅」上。
- 不要留着「刚才说的」「第二点」这类指代。
- 不要切进词里;不要在前面加标题卡。
- 没说「先给我看」的,不要一段段停下来问边界;说了的,不要替用户定,除非他说「你定」。
- 不要把没看过的画面说成没问题;不要吞掉 warnings。
- 不要承诺画面一直跟着人移动,按镜头分别取景才是做得到的,用户可以在画布上拖任意一个镜头的画面;不要整段只用一个裁框;不要拿别的镜头的脸位置定这个镜头的裁框;不要凭几帧估切换的秒数,用 videos_shots 返回的。
- 不要把素材时钟的句子时间当时间线时间直接传;不要放着返回的 range 与要的差很多而不核对。
- 不要让片段以对方的反应镜头或依赖上文的句子开头;不要交付被切了半个台标或留着烧进去的边框的裁框。
- 不要把几件事塞进一条 note,不要只写一个时钟的秒数。
- 不要导出了 mp4 却说成交付,除非用户要的就是文件;不要把子视频移入回收站。
- 不要把检查用的东西留在用户的文件里:看画面用 videos_frames,不用 ffmpeg 往 exports/ 里截图;为读文稿、试听或看效果而导出的都给 purpose `preview`,不按 ranges 把片段导出成 mp4 来检查。
## 7. 交付
收尾时逐支列出,写给用户看:
- 标题、在父视频里的入点与出点、时长、画幅与分辨率。
- 几支或每支多长是你按话题定的:说一句为什么是这几支(例如另外两个话题要靠前文才懂、没有落点),超过 10 个够格话题时列出没建的候选。
- 开头那句原话与为什么挑它已经通过 hook / reason 传给了结果卡片,回复里不再逐支重复;用户在没有结果页的地方(网页端、命令行)看时才逐支写一句。
- 做了什么、没做什么:画幅与取景(原画幅 / 自动按镜头分别取景 / 用户自定;任意一个镜头的画面都可以在画布上拖)、字幕(有 / 没建)各一句。
- 创建时的 warnings,没有就写没有。
- 发现的画面问题(烧进去的字幕、台标或赞助条、分屏或相邻画面、插话时说话人不在画面里):有就写;看过而没有写「没看到」;没看画面就写没看。
- 最后一句:子视频在编辑器里可以继续调,想把划掉的话放回来点那句就行;要 mp4 再说。