subtitles:修復 Premiere Pro 字幕
一次性設定:請參閱工具包根目錄的 INSTALL.md。使用外掛時,設定指令為
bash "${CLAUDE_PLUGIN_ROOT}/install.sh" --data "${CLAUDE_PLUGIN_DATA}";若手動安裝(將四個 skills/ 資料夾並排複製到 ~/.claude/skills/),請在工具包根目錄執行 bash install.sh。
腳本位於此技能的 scripts/ 資料夾中。此技能會指向另一個技能 ../rough-cut/...。
技能功能
Premiere 產生的自動轉錄(一個 .json 匯出檔案)通常充滿錯字,尤其是專有名詞(例如攝影師姓名被拆成兩個不相關的字)。whisper.cpp 的轉錄品質好得多。
此技能會在本機重新轉錄影片,然後重建一個與 Premiere 完全相符的格式的 .json 檔案(可直接重新匯入):藉助參考腳本修正名稱、恢復標點與大小寫、將作品名稱加上引號。最後,它會透過強制對齊將時間戳記重新對齊到音訊上(whisper 的時間戳記會漂移)。
- 是:本機轉錄、名稱修正、標點與大小寫、作品名稱引號、音訊時間重新對齊(強制對齊)、與 Premiere 格式完全相同的檔案,可直接重新匯入。
- 否:剪輯或粗剪影片(那是
rough-cut的功能)、翻譯、重新同步原本正確的字幕檔、.srt/.vtt字幕(此處的格式是 Premiere 的原生 JSON)。
預期輸入
- 從 Premiere 匯出的影片(
.mp4/.mov):包含要轉錄的音訊。 - 從 Premiere 匯出的字幕
.json檔案:提供要複製的目標格式(鍵值、speakerUUID、語言)。 - 影片的參考腳本,任何可讀取的格式皆可(純文字、Markdown、Google 文件、Notion 頁面、貼上的文字):這是專有名詞拼寫的權威來源(人物、作品、地點、品牌)。如果沒有,請索取,或者只修正明顯的錯字,並對任何不確定的名稱保留 whisper 的拼寫。
語言
排版(標點符號周圍的間距)、帶重音符號的字母、標點符號集、引號和拼寫標準化都存在於 languages/<code>.json 檔案中(內建 fr 和 en),絕不寫在程式碼中。語言透過 --lang <code> 選擇,否則使用 Premiere JSON 的語言,再否則使用 whisper 轉錄記錄的語言,最後預設為 en。檔案運作方式及如何新增語言:請參閱 ../rough-cut/references/languages.md(機制相同;此技能有自己的 languages/ 資料夾)。
需求(每台機器僅需設定一次)
whisper-cli + ffmpeg + 模型 ~/Models/whisper/ggml-large-v3-turbo.bin。請參閱 ../rough-cut/references/whisper-setup.md(共享設定)。檢查:which whisper-cli ffmpeg && ls ~/Models/whisper/。
強制對齊(將時間戳記重新對齊到音訊上,步驟 6b):
pip3 install --break-system-packages ctc-forced-aligner torch torchaudio unidecode
首次執行時會下載一個約 1.2 GB 的 ONNX 模型(快取目錄 ~/ctc_forced_aligner/)。檢查:python3 -c "import ctc_forced_aligner"。
工作流程
以下的
scripts/...指令假設你位於技能資料夾中。工作目錄可在兩次 shell 呼叫之間重設:可以一次cd進入技能資料夾,或者為每個腳本加上絕對路徑。工作檔案(音訊、轉錄、修正)應放在任何同步資料夾之外的暫存資料夾中。
1. 檢查影片與輸入格式
首先:備份原始檔案。 Premiere 可能會在重新匯出時改寫輸入的 .json 檔案,而它是驗證步驟 7 時間的唯一同步真相:
cp "<Reel.json>" /tmp/subs_original_premiere.json
ffprobe -v error -show_entries format=duration:stream=codec_type,r_frame_rate \
-of default=noprint_wrappers=1 "<video>"
記下持續時間(最後一個字必須落在持續時間內)和 fps。然後檢查輸入的 Premiere JSON 以確認格式:
python3 scripts/inspect_format.py "<Reel.json>"
它會列印出頂層/區段/字詞的鍵值、speaker UUID、語言、區段數量,以及逐區段的當前文字(= 要修正的錯字列表)。預期格式記錄在 references/premiere-format.md 中:如果檢查結果顯示不常見的鍵值,請閱讀該文件。
2. 在本機轉錄(whisper.cpp)
python3 scripts/extract_audio.py "<video>" /tmp/subs_audio.wav
python3 scripts/transcribe.py /tmp/subs_audio.wav /tmp/subs_transcript.json --model large-v3-turbo --language <code>
在 Apple Silicon 上,3 分鐘的影片約需 8 秒。轉錄結果包含帶有 text(已加標點、區分大小寫)和時間戳記 words 的區段。
2b. 如果 whisper 未加標點(連續輸出):重新加標點
在快速獨白中,whisper 有時會回傳一個沒有標點且沒有大寫的串流(區段在句子中間斷開,沒有 ./,)。明顯症狀:build_subs.py 報告 eos: 0。沒有標點的字幕無法閱讀。快速檢查:python3 scripts/words_of.py /tmp/subs_transcript.json 0 1 2 --plain。
如果是這種情況,請自行重新加標點(這是 LLM 的工作,不是 whisper 的):重寫每個區段的 text,加上標點和句子開頭大寫,保持 whisper 的字詞完全不變:只加入標點和大小寫;詞彙修正(名稱、縮寫)留在 corrections.json 中。標點符號永遠附加在單字上(so?,而不是 so ?):前面有空格的符號會變成一個獨立的 token,而對齊程式會默默地丟棄它(曾經有 114 個 ?/! 一次全部遺失)。build_subs.py 會自行套用語言對應的間距(法文是無間斷空格)。將結果放入一個 JSON {index: "標點文字"} 中,然後:
python3 scripts/repunctuate.py --transcript /tmp/subs_transcript.json --punct /tmp/punct.json --output /tmp/subs_transcript_punct.json
該腳本會拒絕你新增、刪除或更改任何字詞(它會顯示差異):這樣才能保持字詞與時間的對齊不變。注意區段之間的流暢度:延續句子的區段以小寫開頭,開始新句子的區段以大寫開頭。在後續步驟中使用這個已加標點的轉錄結果(步驟 6 中的 --transcript)。
另外,刪除任何結尾幻覺:在最後的寂靜中,whisper 經常編造一行字幕,例如“Thanks for watching”(每種語言的典型行數列在其 languages/<code>.json 檔案的 whisper_hallucinations 中)。使用 seq_rule N 到 0 將其刪除。另一種幻覺:連續且文字相同的區段,其字詞的持續時間接近零(start==end),是在寂靜中重複發明的句子(例如“here we go”三次)。偵測方式:區段 i 和 i+1 文字相同且字詞持續時間為 0。修正:在建立字幕前從轉錄結果中刪除它們(del segs[i:j])。
3. 閱讀 whisper 轉錄結果與參考腳本
逐區段列印轉錄結果(text),並與步驟 1 中輸入的 Premiere 文字進行比較。whisper 已經修正了很多,但名稱上的錯字仍然存在。閱讀參考腳本以取得專有名詞及其引用的作品名稱的規範拼寫。
4. 建立 corrections.json(智慧核心)
這是決定品質的關鍵。透過將 whisper 聽到的內容與腳本中的名稱進行比較來建立修正檔案。檢查受影響區段的逐字分割,以編寫精確的規則:
python3 scripts/words_of.py /tmp/subs_transcript.json 2 9 38 # 要檢查的區段的索引 token
輸出會索引每個字詞(9:Smyth 10:Jones):這讓你可以編寫精確的規則,而無需猜測 tokenization(名稱佔多少個 token、是否保留連字號等)。
corrections.json 的格式(所有鍵值皆為可選):
{
"quote_char": "\"",
"normalize_cotes": true,
"seq_rules": [
[["jon","smyth"], ["John","Smith"]],
[["train","park"], ["Trent","Parke"]],
[["arthus","bertrand"], ["Arthus-Bertrand"]]
],
"word_rules": {"macdum": "Magnum", "scholler": "Schoeller"},
"titles": [
{"match": ["the","decisive","moment"], "canonical": ["The","Decisive","Moment"]},
{"match": ["errance"], "canonical": ["Errance"], "sep_comma": true}
]
}
seq_rules:多字名稱,或 1 對 N / N 對 1。比對時會將字詞轉換為小寫,並去除標點。用於任何跨越 whisper 2 個以上字詞的名稱,或字詞數量發生變化的情況。大小寫:目標字詞會逐字使用:寫上你想要的最終大小寫,包含在句子中的位置(如果單字開頭句子,使用["Today","we",...],而不是["today",...])。相同長度來源/目標:標點符號(內部逗號)和時間會按索引保留;不同長度:時間會重新分配,且只有第一個/最後一個字詞的標點會保留(被取代字詞的內部逗號會遺失:請在步驟 7 中重新閱讀這些區段)。刪除:空的目標[["uh"], []]會移除該字詞(保留給 whisper 重複的真正孤立噪音;對於轉錄錯誤的字詞,請修正而不是刪除,否則你可能會遺失部分句子)。word_rules:一個字的名稱,強制大小寫(小寫鍵值對應到確切值)。titles:被引用的作品(書籍、影集、有標題的照片)會自動加上引號(開頭在第一個字,結尾在最後一個字),加上一個canonical用於標題的正確大小寫。sep_comma: true會在標題後加上逗號(當多個標題連續出現時很有用)。將作品放在引號中,而不是人名或品牌名。normalize_cotes:套用語言檔案的拼寫標準化(normalize_words),用於 whisper 不一致書寫的變體。除非你設定,否則預設關閉。french_typography:語言排版間距的開關(名稱是歷史因素;它適用於任何正在使用的語言)。預設值取自語言檔案:法文在雙標點符號和閉引號前使用無間斷空格(U+00A0),並在開引號後使用;英文則無。僅在你想使用附著標點時設定為false。當你在步驟 2b 重新加標點時,標點必須附著(Flop:);build_subs.py會自行套用間距。
5. 與使用者共同解決不確定之處(絕不自行猜測)
whisper 有時會產生一個含糊不清或難以理解的非名稱字詞。不要默默地猜測。 列出這些問題及其時間碼,並詢問使用者實際說了什麼,如果上下文或腳本有提示,可以提供一個假設。區分:
- 直接修正:由腳本確認的專有名詞;明顯且確定的錯字。
- 先詢問:含糊不清的非名稱字詞,或任何改變含義的修正(例如 whisper 聽成“who feels”而腳本是“without”:意義相反,即使腳本能解決也要標記)。
不要改寫口語風格(俚語、填充詞、重複):字幕必須跟隨音訊。
等待回答時在檔案中寫入什麼(你無需阻止生成):產生一個套用所有安全修正的第一版,加上你對常見含糊字詞的最佳假設(並標記它們),但對於腳本中未出現的不確定名稱,保留 whisper 的原始拼寫:絕不發明專有名詞。交付該版本以及需要驗證的項目列表(時間碼),然後在更新 corrections.json 後重新生成。這就是正常流程:生成、附帶問題呈現、精煉。
6. 產生修正後的檔案
python3 scripts/build_subs.py \
--transcript /tmp/subs_transcript.json \
--original "<Reel.json>" \
--corrections /tmp/corrections.json \
--output "<folder>/<name>_corrige.json" [--lang <code>]
該腳本會複製原始檔案的格式(speaker UUID、語言、排序鍵值、壓縮的 UTF-8)、恢復標點和大小寫、套用修正、加入引號、重新計算 eos,並列印一個驗證報告。
將 <name>_corrige.json 寫在原始檔案旁邊,切勿覆蓋原始匯出檔案(這是使用者的來源)。_corrige 後綴是腳本依賴的檔案名稱:請保留它。
6a. 檢查 build_subs.py 的 2 個常見陷阱(每次都檢查)
在許多影片中都見過兩個錯誤,每次建置後都必須檢查:
- 小數點重複。whisper 將
6.6拆成 2 個 token(6+.6;同樣地1,33,或4 AM拆成4+AM);標點重新注入會使它們在輸出中重複(1.4 .4、6.6. .6),並且seq_rules比對錯誤(標準化不會去除內部的./,)。偵測:使用模式\d[.,]?\s+[.,]\d在最終輸出中搜尋。修正:在建置前對轉錄結果進行手術:將 2 個 token 合併為一個({'text':'1.4','start':a.start,'end':b.end,...};whisper 單字架構 =text/start/end/confidence,而非duration),然後重新建置。 - 孤立句尾標點被刪除。存在於 whisper 區段
text中但沒有自己 token 的?/!/:會消失(How did we do it ?失去其?)。偵測:比較 whisper 文字和輸出中count('?')(以及!、:)的數量。修正:直接編輯輸出 JSON:將?(使用語言的間距)重新附加到前一個 token。
如果偵測到陷阱 1,請修正轉錄結果並重新建置(步驟 6)。如果是陷阱 2,請直接修補輸出。
6b. 將時間對齊到音訊上:強制對齊(每次都要做)
whisper 的字詞時間會漂移(在快速、多段獨白中測量到最多早 7 秒,非線性):whisper 壓縮了各段之間的靜音,因此聲音在字幕之後才出現。典型抱怨:"當『Ah』出現時,我已經聽到下一句了"。DTW (-dtw) 沒有任何改變(相同的偏移),而在稀疏錨點上進行時間扭曲會扭曲原本已經正確的區域。whisper 的文字是好的,只有其時間是錯誤的,導致字幕與音訊不同步。強制對齊(CTC Forced Aligner)解決了這個問題。
python3 scripts/realign_timings.py \
--transcript /tmp/subs_transcript.json \
--audio /tmp/subs_audio.wav \
--corrections /tmp/corrections.json \
--output /tmp/subs_aligned.json \
--language <code> # 與步驟 2 相同的語言
該腳本會執行強制對齊,並將修正後的字幕時間戳記寫入 /tmp/subs_aligned.json。這個檔案現在已經準備好,可以在下一步驟中用於建置最終的 Premiere JSON。
7. 匯入前的最終驗證
python3 scripts/validate_timings.py \
--original /tmp/subs_original_premiere.json \
--corrected "<folder>/<name>_corrige.json" \
--transcript /tmp/subs_aligned.json
此腳本會比較原始時間與修正後時間,確保所有字詞都落在影片持續時間內,並檢查是否有任何異常(例如時間倒退、重疊、大量漂移)。它也會輸出一個簡短的摘要,方便你或使用者進行視覺確認。
最後,在 Premiere Pro 中匯入 <name>_corrige.json:
- 將
<name>_corrige.json複製到 Premiere 專案資料夾中。 - 在 Premiere 中,選擇「檔案 > 匯入」並選取該 JSON 檔案。
- 它會像原始檔案一樣作為字幕軌道匯入,但現在帶有修正後的文字和對齊的時間。
- 如果出現任何錯誤,請檢查
validate_timings.py的輸出,並重新開始流程。
參考資料
- references/premiere-format.md:Premiere 原生 JSON 字幕格式的文件。
- ../rough-cut/references/languages.md:語言設定檔的運作方式。
- ../rough-cut/references/whisper-setup.md:whisper.cpp 的共享設定指引。