轉錄本身不是終點,整理才是
語音轉文字工具已經很多了。真正讓我卡住的,是轉錄之後的後半段:敏感音訊要不要外送、什麼時候該啟動、檔案要寫到哪裡、摘要格式誰來管。這些沒先想清楚,逐字稿只是換了一種形式堆在硬碟裡,安全邊界也跟著變模糊。
音訊不一定該上雲
會議錄音、訪談和內部討論常帶有不能外流的脈絡。本機轉錄不能保證絕對安全,但至少少了一段把原始媒體交給第三方服務的路徑。
內容難回收
轉錄結果若只出現在 console 或聊天視窗,之後很難再找。我先把逐字稿寫進 Obsidian vault,至少讓檔案有固定落點。
摘要規則容易散掉
摘要格式如果每次靠臨場指令,很快會不一致。我把摘要 prompt 獨立成檔案。之後要改摘要欄位,改檔案就好,不用翻聊天紀錄。
逐字稿不能當指令
錄音裡可能真的有人說出 prompt injection。所以規格先寫清楚:逐字稿只能當被整理的素材,不能拿來改變 Agent 行為。
讓 Agent 做判斷,讓腳本做會改檔案的事
使用者提供媒體檔路徑後,Agent 先確認檔案存在,再找本機 Vibe / Sona API,把音訊或影片送去轉錄。原始媒體不必先交給雲端服務,來源檔也不被搬移或覆寫。到這裡為止,Agent 負責判斷流程;摘要插入與 HTML 產出則交給 helper。會改檔案的步驟,最好有固定入口。
確認輸入
只讀使用者指定的媒體檔。來源檔不搬移、不刪除,也不順手整理。
呼叫本機 API
Sona 轉錄端點吃的是 multipart upload。音訊留在本機處理,不先交給第三方雲端轉錄。
寫入 Obsidian
逐字稿、metadata 與原始 JSON 寫成固定格式 Markdown,方便回頭查。
補上摘要
Agent 讀摘要 prompt 產出內容,helper 負責插入或替換 `## Summary`。
輸出 HTML
同一份筆記再渲染成閱讀頁。要分享或回看時,不必重新排版。
Markdown 筆記
逐字稿與摘要進入 Obsidian。之後可以搜尋、引用,或接到其他整理流程。
AI-Assets/Vibe_Transcripts/YYYY-MM-DD-HHMMSS-source-transcript.md
HTML 頁面
同一份內容轉成閱讀頁,不必再把逐字稿搬到另一個工具重新排版。
AI-Assets/Vibe_Pages/YYYY-MM-DD-HHMMSS-source-transcript.html
少一點臨場整理,多一點可重跑的痕跡
這個作品的重點不在「呼叫一次轉錄 API」。真正花時間的是收尾:檔案要去哪裡,摘要要長什麼樣子,HTML 怎麼產生,哪一步失敗時要怎麼重跑。這些事看起來不酷,但每天用工具時,通常就是這些細節決定它能不能留下來。
實際改變
- 轉錄結果有固定去處每次輸出都落到 Obsidian 指定資料夾,不靠人手另存。
- 摘要格式不用靠記憶摘要 prompt 獨立成檔案,格式要改時有地方改。
- 檔案操作可重跑轉錄、插入摘要、渲染 HTML 都有 CLI,可以分段驗證。
- HTML 不用手工整理Markdown 筆記能直接轉成 HTML,少掉一次人工排版。
本機轉錄把安全邊界拉回自己看得見的地方
本機轉錄不是萬靈丹,但它把最敏感的原始音訊留在自己的機器上處理,少掉一段外送路徑。媒體檔只當輸入來源,不搬移、不覆寫。逐字稿只當資料,不當指令。摘要和 HTML 產出都寫在 vault 的固定資料夾。這樣做比較保守,但我寧可一開始慢一點,也不要事後猜到底是哪一步改了檔案。
本地轉錄優先
音訊與影片先交給本機 Vibe / Sona 處理,避免把會議、訪談或內部素材先送進第三方雲端轉錄服務。
來源檔只讀
使用者提供的媒體檔即使在 vault 外,也只作為輸入來源。Skill 不會搬移、覆寫或刪除原檔。
輸出位置固定
逐字稿與 HTML 分別寫進 `AI-Assets/Vibe_Transcripts/` 與 `AI-Assets/Vibe_Pages/`。要清查時不用到處找。
Prompt injection 防線
逐字稿內容可能包含惡意語句。規格要求它只能被摘要,不得被當成系統指令或檔案操作。
每段都有驗證點
轉錄後用 Obsidian CLI 讀回筆記;摘要插入與 HTML 渲染也各有 helper 輸出 JSON 結果。
技術細節不多,但每個都會影響能不能跑完
這頁只保留幾個和成敗有關的技術細節:Sona API 怎麼收檔、Markdown 怎麼插摘要、Windows console 怎麼處理中文檔名。工具名列太多沒有幫助;真正要記得的,是哪幾個地方會讓流程中斷。
Sona API 不是 path JSON
轉錄端點使用 multipart upload。這個細節如果搞錯,就會寫成看起來合理、實際上打錯端點的請求。
摘要 prompt 獨立維護
摘要規則放在 `prompts/transcript-summary-prompt.md`。Skill 主檔只描述觸發條件、流程與安全邊界。
helper 處理 Markdown 寫入
`append_summary.py` 負責插入或替換 `## Summary`。Agent 不直接手改長 Markdown,比較不容易把段落順序弄亂。
Windows 編碼要處理
來源檔名若含特殊中文字,傳統 console 可能在最後輸出 JSON 時噴 encoding error。腳本需要明確把 stdout / stderr 設成 UTF-8。
def insert_or_replace_summary(markdown: str, summary: str) -> tuple[str, str]:
pattern = re.compile(r"(?ms)^## Summary\s.*?(?=^## |\Z)")
if pattern.search(markdown):
return pattern.sub(summary + "\n", markdown, count=1), "replaced"
transcript_match = re.search(r"(?m)^## Transcript\s*$", markdown)
if transcript_match:
insert_at = transcript_match.start()
return markdown[:insert_at].rstrip() + "\n\n" + summary + "\n" + markdown[insert_at:], "inserted_before_transcript"
return markdown.rstrip() + "\n\n" + summary, "appended"
這套做法可以搬到別的素材整理
這次接的是 Vibe / Sona 轉錄,但做法可以搬到 PDF 摘要、課程影片、客服錄音或訪談逐字稿。先把原始素材變成固定格式 Markdown,再補摘要,最後視需要輸出 HTML。形式變了,骨架不用重寫。
先定輸出格式,再接 AI
如果輸出格式沒有固定,AI 摘要很快會變成一次性文字。先定 Markdown 與 HTML 結構,後面的流程才容易檢查。
Agent 產摘要,腳本處理寫檔
摘要可以交給 Agent,但插入摘要與渲染 HTML 交給 helper。這樣比較容易重跑,也比較容易定位錯誤。
本機工具也要寫清楚邊界
local-first 不代表沒有風險。逐字稿內容、API 回應與檔名都可能帶入不該執行的文字,所以規格先定義哪些內容只能當資料。
作品頁保留設計取捨;教學頁則拆成可以照著做的步驟,從本機轉錄、Obsidian 寫入到 HTML 輸出。