字幕
這是一件事,不是流程的一段。 用戶什麼時候喊它就什麼時候做——剛剪完可以做, 做完又刪了兩句可以再做一遍。
它只有一個前提:賬本已經存在。不是因為它排在剪輯後面,而是因為沒有賬本, 它不知道哪幾句留著、各自落在成片的第幾秒。
需要 edit-list.json(賬本)、transcript.json(逐詞稿)
產出 subtitles.json
幹完就停,不指揮用戶下一步。
先讀取並執行 業務 Skill 的階段合同, 判據見 字幕校對規則,專名寫法見 AI 用詞詞典。
誰說了算什麼
這是這一段的地基,其餘都從這裡推出來。
剪口播 說了算「留哪些話、在什麼時候」 ← 時間的唯一真相
字幕 說了算「屏幕上顯示什麼字」 ← 顯示的唯一真相
一屏字幕存的是詞 id 列表 + 顯示文字,不存秒數。時間每次從賬本現算。 於是兩本賬沒有第二份時間可以走偏,失效也能精確到屏:「第 7、第 12 屏的詞被剪掉了」, 而不是那句誰也點不動的「字幕可能已過期」。
字幕存自己的文字是故意的。 轉錄回答「他說什麼」,字幕回答「給人看什麼」—— 標點、去掉的口頭禪、專名的正式寫法,這些本來就該不一樣。逼一份字串同時幹兩件事, 字幕就永遠加不了逗號。
0. 就緒
先執行 檢查更新 的「就緒檢查」——skills 是否
最新、Runtime 是否配套;插件根也在那裡定位(本文命令裡的 <插件根> 都代入
那個字面路徑)。只有「就緒」才繼續;「需新會話」或「停」按它的處置執行
(含「禁止自製替代界面」禁令),業務 Skill 不自帶環境邏輯。
若就緒結果為 runtime.kind=desktop-managed,直接複用桌面 App 已安裝的穩定 CLI 與
同一 launchd/windows-task 服務;不要解析 Electron 路徑、另裝依賴或起第二個
Runtime。
1. 入口斷言
node "<插件根>/scripts/ensure-running.cjs" --json
node "<插件根>/scripts/videocut-cli.cjs" inspect "<項目目錄>" --json
| 斷言 | 不成立時 |
|---|---|
edit-list.json 存在且有片段 | 說清楚缺賬本,讓用戶先喊剪口播。不要自己去剪。 |
transcript.json 存在 | 項目沒準備好,停止。不要自己造一份。 |
不要斷言 source_cut.mp4,也不要去轉錄。 字幕兩樣都不需要——見下一節。
2. 改字:先詞典,後文稿
不需要重新轉錄。 原來那份逐詞稿已經帶著時間戳,賬本知道哪幾段留著—— 每個詞落在成片的第幾秒是算出來的,不是再聽一遍聽出來的:
詞在源片的第幾秒 轉錄裡就有
哪幾段留著 賬本裡就有
詞在成片的第幾秒 兩者一算就出來
再送一遍 ASR 只是把同樣的話重新聽一次,花錢、花時間,而且聽得更差——專名要重新改一遍。
(transcript retranscribe 是上一版設計的遺留,那時字幕打算靠轉寫剪後影片拿時間軸。
字幕改成錨詞 id 之後這個問題就沒了。做字幕不要用它。)
兩件不同的工具,都要用。
# 詞典:這個說話人的固定寫法,不需要證據
node "<插件根>/scripts/videocut-cli.cjs" transcript dictionary "<項目目錄>" --dictionary "<插件根>/references/ai-term-dictionary.md" --json
# 文稿:作者手上有稿子時才做,逐處要證據
node "<插件根>/scripts/videocut-cli.cjs" transcript align "<項目目錄>" --script "<口播稿檔案>" --json
詞典 永遠這麼寫 不看上下文,直接改,列出改了哪幾處
文稿 上下文對得上才這麼寫 逐處要證據,對不上的報「不敢定」,不猜
為什麼必須有詞典,光靠文稿不行:口播會重錄。真實項目裡同一句錄了四遍, 於是「連接叉」「叉是」這些上下文全都出現不止一次,align 只能報「不敢定」—— 它按規矩不猜,因為名字寫錯比聽錯更糟。三處「叉」它只敢改一處。 詞典沒有這個問題:在這個說話人的作品裡,「叉」就是「X」。
詞典只有一份,在插件級 references/ai-term-dictionary.md:它改的是轉錄,
而剪口播和字幕吃同一份轉錄。不要在這個 skill 下面再建一份。
改完要看那份清單。 詞典不看上下文,所以它也會改錯——比如把說話人真的說的 「Skills」(Claude Skills,複數專名)normalize 成「Skill」。看到不對就改詞典, 不要在命令這邊打補丁。
transcript align 只報不改。要應用它的提案,把 corrections 轉成 [{wordId, text}] 再跑:
node "<插件根>/scripts/videocut-cli.cjs" transcript correct "<項目目錄>" --file "<修正檔案>" --json
改完轉錄,引用了這些詞的字幕屏會在同一步裡跟著改寫,回報 subtitles.updated。
改不動的(那一行被人重寫過)進 needsAttention,報出來讓人看,不猜。
詞典裡沒有、文稿裡也沒有一個寫法能確認正確時,不許猜。 報出來讓用戶補詞典—— 補進詞典下一條影片就自動對了,猜對一次下次還要再猜。
3. 分屏
node "<插件根>/scripts/videocut-cli.cjs" subtitle build "<項目目錄>" --json
四條規則,按順序:
① 這裡刪掉過話 刪掉的兩邊在時間軸上挨著,意思上毫無關係。
刪掉的是「靜音」不算 —— 把句子中間的停頓剪掉,不能把句子劈開。
② 任何標點 火山給的,句號和逗號都算 —— **和剪口播分段是同一個粒度**,
兩邊斷在同一處。標點比任何時間證據都強:說話人可以兩句連著
說不喘氣,也可以在一句中間停頓。
③ 段落邊界 + 停頓 **只在這個詞沒有標點時才用**。它是「沒標點時靠段落猜句子結束了」,
有標點就該由②和逗號那條管 —— 它們會考慮屏夠不夠長,③ 不會。
(在帶標點的邊界上也觸發③,真實項目從 40 屏變 43 屏,切出更多碎屏)
④ 觀眾聽到長停頓 句子內部要斷,得有更長的靜音才夠格。
剪口播和字幕吃同一份標點,粒度也一樣:一個逗號一段 / 一屏。
碎片(一兩個字)會被並掉,但不跨句號並 —— 「你看」開啟新的一句, 不是上一句的尾巴,往前並會得到「…調用Grok CLI你看」,兩句糊在一起。
說話人說得快的短句會留下來(真實項目上「每天早上」「執行任務」各 0.6 秒)。 那是他真的這麼說的,不報警。 一個逗號一屏必然產生這種屏, 為它報警等於對正常說話報警——報多了就沒人看警告了。
剩下比一屏長的,均攤拆成幾屏,一屏一行。切出一兩個字的碎片,說明②那個邊界 其實不是句號,把碎片並回上一屏。
命令回報四件事,都要看:
stale 被剪輯改動的屏 —— 精確到第幾屏、丟了哪幾個字
tooFast 字太多、時間不夠讀
transcriptMoved 轉錄已經不是當初那一份了
已經有字幕時 —— 這裡要停下來問
不加 --replace 它會直接拒絕。這是這個 skill 裡唯一要徵求用戶同意的地方,
因為 --replace 衝掉的是人花時間做的分屏和措辭,產品自己恢復不了。
用戶想改幾個字 不要 build。讓他在 Studio 裡直接改,或者告訴你改哪幾屏。
用戶要推倒重來 確認過了再加 --replace。
4. 複核:在 Studio 裡逐屏看
node "<插件根>/scripts/videocut-cli.cjs" open "<項目目錄>" --json
打開後切到左欄的**「字幕」標籤頁**。一行一屏:左邊序號和時間,右邊就是字,點進去直接改。
- 回車 = 從游標處另起一屏
- 行首退格 = 併入上一屏
- 右欄「參數 → 字幕」四個預設選一個,全片一個樣式
- 畫面上能直接看到字幕,位置和字號跟畫面成比例——預覽和成片是同一套數
複核時至少讓用戶確認:專名對不對、有沒有吞字、斷句讀起來順不順、一屏停留夠不夠讀完。
5. 到 subtitles.json 為止
這一段做完了。 不做物理剪切、不做分鏡、不做動畫、不渲染成片,也不催用戶下一步。
報告必須分開寫:Product 結構化 readback 為 API/readback PASS;真實同項目瀏覽器幀 審核才是 visual frame PASS;沒有人實際看過字幕跟畫面對不對時一律為 human listening UNVERIFIED,不得用 DOM、截圖或檔案探測替代。
邊界:燒進畫面不是這一段的事
產出方式定的是燒進畫面,而畫面是導出那一段畫的。字幕的產出就是 subtitles.json ——
裡面的尺寸全是畫面的百分比,導出按輸出解析度換算成像素即可,兩邊同一套數。
今天導出的 mp4 裡沒有字幕,那一步還沒做。報告裡要寫清楚這個後果, 不要說「字幕做好了」就完事——用戶會以為成片裡有。
恢復與失敗
subtitles_exist:已經有字幕了。先問,別直接--replace。revision_conflict:另一處也在寫。重新讀取,不自動覆蓋。- 詞典報「第 N 行讀不懂」:那是一行格式壞掉的表格行。規則只認表格行(
| 正確寫法 | 常見誤識別 |), 散文和列表都會被安靜忽略。 transcript correct報「must not change any word id, time or gap flag」: 改字的提案裡混進了改時間的東西。改字就只改字。runtime_unhealthy:不要循環重裝。- 任何失敗都不得把「轉寫完成」說成「字幕做好了」。ASR 出來的是原料,不是產物。