open-dictate 按住、說話、放開,字就出現在游標。
Apple Silicon Mac 上的繁體中文語音輸入,本地優先。MLX Whisper 在你自己的電腦上把聲音轉成字,你自己的詞庫校正它認得的詞,整句話直接打進游標所在的位置。系統可以標記、可以建議,但不能靜默改寫你的意思。
早期公開版 · daemon 0.6.1 · MIT 授權 · macOS 14 以上 · Apple Silicon
01 · 示範 一次語音輸入,一步一步看
週會筆記
幫我把 TouchDesigner 的檔案放上 GitHub 的專案頁,明天下午三點前寄給大家。
Whisper 把兩個專有名詞聽成小寫、拆開的英文,你教過的兩組詞庫對照把它們改回來。「三點」照你說的留著。
按住 fn,輸入下一句。
用滑鼠、手指或空白鍵按住上面的 fn,再放開。句子是事先寫好的,這一頁不會聽你說話。
這是示範動畫。句子事先寫好,這一頁不會碰你的麥克風。真正在做事的,是你 Mac 上的選單列 app 和 daemon。 讀介面契約 →
02 · 運作方式
五個步驟,一條規則
你按住快捷鍵時,Swift 寫的選單列 app 開始錄音,放開後把 WAV 檔交給一直保持載入的 Python daemon。daemon 轉錄、校正、加標點,回傳文字,app 再把字打進游標所在的位置。轉錄之後,能改動你字詞的只有你放進詞庫的那些對照。
-
01 錄音
按住鍵的時候
按住 fn 或右側 Option,app 錄下 16 kHz 單聲道音訊。不到半秒的按壓直接丟掉,另有一道語音形狀檢查,擋下只錄到環境噪音的誤觸。
rec = 3.4 s數值來自上面的示範 -
02 轉錄
說了什麼
MLX Whisper 在 Apple Silicon 上執行,模型一直載入在 daemon 裡。進下一步之前,先濾掉已知的字幕署名幻覺,截斷失控的重複迴圈。
model = large-v3-turbo數值來自上面的示範 -
03 校正
你的意思
詞庫是一張誤聽 → 正確的對照表,只有命中的詞會被替換,整句話不會被改寫。寧可漏改,不可錯改。
changes = 2數值來自上面的示範 -
04 標點
讀起來的樣子
預設的
smart_zh規則只在中文語境把標點轉成全形,英文、數字、網址都不動。可以另外開本機 LLM 補完整標點,它只要動到標點以外的任何一個字,整段結果就作廢。punct = "smart_zh"數值來自上面的示範 -
05 插入
字落在哪裡
文字透過輔助使用(Accessibility)API 直接插入,不行再改用貼上。app 不會把焦點從你正在打字的輸入框搶走。
insert → AX · paste數值來自上面的示範
快捷鍵之外
- 會議模式 Meeting Mode
- 本機錄音檔,或已經轉好的 JSON/JSONL 分段,整理成可審核的逐字稿包:Markdown、JSONL、SRT、VTT。用的是同一個 Whisper、同一份詞庫。
- 審核佇列 Review queue
- 掃描器把疑似誤聽和數字標成候選。你決定接受、修改或拒絕,只有接受的才進詞庫,每個決定都能復原。
- 說話者標籤 Speaker labels
- 逐字稿使用匿名標籤
SPEAKER_00、SPEAKER_01。辨識是誰在說話,規劃成另一層選用、只在本機的功能。 - 選單列 Menu bar
- 從上一句或選取的文字教詞庫、回報誤聽,也在這裡切換快捷鍵、麥克風和標點模式。
七條規則
- 只換詞,不改句。 詞庫對照可以修正一個詞,系統不能改寫整句話。
- 寧可漏改,不可錯改。 一組錯的對照會污染之後每一次轉錄,所以有風險的對照要等上下文或你的審核。
- 可以統一字形,不能改變意思。 繁體中文字形可以正規化,數字不會被自動改動。
- 音檔留在本機。 錄音、轉錄、校正,全部在你的 Mac 上執行。
- 不搶焦點。 介面不會把焦點從你正在使用的輸入框拿走。
- 聲音屬於生物特徵資料。 說話者資料和聲紋 embedding 只放本機,永遠不進 Git。
- 靠審核成長。 詞庫從你接受的建議慢慢變好,不會自己偷偷改。
這一頁用到的詞
- 按住說話 Push-to-talk
- 說話時按住一個鍵,放開就結束。Open Dictate 用 fn 或右側 Option。
- 常駐程式 Daemon
dictated.py,在背景一直把模型載入著的程式,短句不用等冷啟動。app 透過 Unix socket 跟它溝通。- MLX Whisper
- 在 Apple 的 MLX 框架上執行的 Whisper 語音辨識模型。預設是
whisper-large-v3-turbo。 - 詞庫對照 Glossary pair
- 一筆
誤聽 → 正確,例如git hub → GitHub。只要誤聽那一邊出現,就照寫好的字替換。 - 語境對照 Contextual pair
- 只在某些句子裡才安全的對照。它不會被盲目套用,要等上下文或你來判斷。
- 審核佇列 Review queue
- 等你接受、修改或拒絕的候選對照。每個決定都留在歷史紀錄裡,可以復原。
- smart_zh
- 預設的規則式標點:中文後面的半形標點轉成全形。結果固定,重跑幾次都一樣。
- 不改寫閘門 No-rewrite gate
- 選用 LLM 的輸出必須通過的檢查:拿掉標點之後,除了授權過的詞庫對照,必須和輸入一字不差。
- SPEAKER_00
- 會議逐字稿裡的匿名說話者標籤。系統不確定是誰時寫
unknown,不硬猜人名。
03 · 現況
現在能用的
Open Dictate 是早期公開版(public seed),從一套每天在用的私人工具抽出來。語音輸入這條路已經能在 Apple Silicon Mac 上使用,會議、審核、說話者這幾層刻意保守。下面每一項的狀態都照抄 README。
功能
- 按住說話輸入公開版
- 本地 MLX Whisper daemon公開版
- 確定性詞庫校正公開版
- 繁中全形標點公開版
- 選單列教詞庫公開版
- 會議逐字稿包公開版音檔,或 JSON/JSONL 分段
- 會議模式的本機音檔轉錄公開版MLX Whisper adapter
- 轉錄後誤聽偵測MVP審核標記
- 審核優先的詞庫成長MVP命令列佇列
- 匿名說話者標籤MVP
- 本機說話者身分規劃中敏感、選用的一層
安裝前先知道
- 只支援 Apple Silicon、macOS 14 以上。Intel Mac 不支援。
- 目前從原始碼安裝。需要 Git、Xcode Command Line Tools 和 Python 3.11 以上,還沒有 DMG。
- 裝好的 app 依賴你 clone 下來的資料夾。搬動資料夾之後,跑一次 doctor,再重新安裝。
- app 目前是 ad-hoc 簽章。重新建置後,macOS 可能要你把權限關掉再打開。
- 第一次執行會下載模型,載入可能要兩分鐘左右。
變成一般 Mac app 的路
- 階段 0發布架構。 產品設定集中成一份,資料搬到 Application Support,執行時不再依賴 clone。
- 階段 1自帶執行環境的 beta。 Python 包進 app,首次啟動引導權限與模型下載,產出測試用 DMG。目標:在乾淨的 Mac 上只靠 Finder,十分鐘內完成第一次語音輸入。
- 階段 2簽章與公證。 Developer ID 簽章、Apple 公證,打開時不跳 Gatekeeper 警告,附 checksum。
- 階段 3更新與回滾。 簽章過的 app 內更新,Stable 與 Beta 兩個頻道,更新失敗自動退回,不碰你的資料。
- 階段 4更多管道。 Homebrew Cask。Mac App Store 要等 sandbox 的問題確認之後再評估。
04 · 隱私
聲音留在你的 Mac
音檔、逐字稿、日誌、審核佇列和說話者資料都留在你的電腦,除非你自己匯出。語音輸入不需要伺服器,也不需要帳號。
資料放在哪裡
| 資料 | 位置 | 可以進公開 repo 嗎 |
|---|---|---|
| 語音輸入日誌 | ~/.open-dictate/dictation-log/ | 不行 |
| 會議逐字稿 | ~/.open-dictate/meetings/ | 不行 |
| 審核佇列 | ~/.open-dictate/review-queue/ | 不行 |
| 個人詞庫 | ~/.open-dictate/glossaries/ | 預設不行 |
| 說話者資料 | ~/.open-dictate/speakers/ | 永遠不行 |
| 公開測試資料 | fixtures/ · examples/ | 可以,只限虛構內容 |
什麼時候會用到網路
- 安裝時。Python 套件從 PyPI 下載。
- 模型。第一次執行會從 Hugging Face 下載
mlx-community/whisper-large-v3-turbo。daemon 載入模型時,下載用的函式庫可能會檢查有沒有新版。這個請求只帶模型名稱,不含你的音檔或文字。 - LLM 標點,如果你打開它。它連到
127.0.0.1上的 Ollama,也就是你自己 Mac 上的伺服器。如果你把OPEN_DICTATE_PUNCT_LLM_URL指到別台機器,文字就會送到那裡。 - 會議模式加上
--model。你指定的模型第一次使用時會下載。
就這些。模型下載到本機之後,沒有網路也能繼續語音輸入。
說話者 embedding 和聲紋屬於生物特徵資料。
05 · 安裝
裝起來
Open Dictate 目前用一支腳本從原始碼安裝。需要 macOS 14 以上的 Apple Silicon Mac、Xcode Command Line Tools,以及 Python 3.11 以上。
git clone https://github.com/frank890417/open-dictate.git
cd open-dictate
./install.sh # venv, app, LaunchAgents, model warm-up
安裝程式會建立虛擬環境、把 OpenDictate.app 建置到「應用程式」資料夾、依你的 clone 路徑寫好兩個 LaunchAgent,然後載入模型。要等 daemon 真的回應 ping 才算成功,只有 socket 檔案不算。
第一次會下載模型,可能要兩分鐘左右。網路慢的話:OPEN_DICTATE_WARM_TIMEOUT=300 ./install.sh。
接著開三個權限,設定一個鍵
- 系統設定 → 隱私權與安全性:在麥克風、輔助使用、輸入監控裡允許 OpenDictate。
- 系統設定 → 鍵盤:把按下 fn(地球)鍵的動作設成不執行任何動作。關掉 Apple 聽寫的 fn 快捷鍵,也關掉其他會搶同一個鍵的語音輸入 app。
- 點進任何輸入框,按住 fn,說話,放開。想改用右側 Option,從選單列切換快捷鍵。
出狀況的時候
./scripts/doctor.sh # read-only checks, then a real ping
./uninstall.sh # removes the app and LaunchAgents, keeps ~/.open-dictate
./uninstall.sh --purge-data # shows where your data is; never deletes it
doctor 會檢查 app、簽章、LaunchAgent、clone 路徑、socket,最後實際 ping 一次,什麼都不改。權限的部分它只能提醒,因為它不讀 macOS 受保護的權限資料庫。
會議和詞庫,從終端機操作
# Meeting Mode: a local recording in, a reviewable package out
python3 daemon/meeting_cli.py transcribe ~/Desktop/meeting.m4a --out /tmp/od-meeting --language zh
# the review queue: look, then decide
python3 daemon/glossary/cli.py candidates
python3 daemon/glossary/cli.py accept cand_xxxxx
中英混雜的會議用 --language auto。輸出 Markdown、JSONL、SRT、VTT,外加一份 JSON 摘要。
06 · 開發
一起開發
兩支程式,一份契約。Swift app 負責快捷鍵、麥克風和插入文字,Python daemon 負責轉錄和校正。兩邊透過 Unix socket 傳換行分隔的 JSON,IO-CONTRACT.md 是雙方共同的依據。
兩條路線
hold fn
|
OpenDictate.app (Swift) records 16 kHz mono PCM16 WAV
| {"cmd": "transcribe", "wav": "/tmp/...wav", "punct": "smart_zh"}
v
/tmp/open-dictate.sock newline-delimited JSON
|
dictated.py (Python, warm)
|-- MLX Whisper audio -> raw text
|-- glossary pairs raw -> corrected (muse_lexicon)
|-- punctuation smart_zh | llm_zh (gated) | raw
|-- log ~/.open-dictate/dictation-log/
v
{"ok": true, "text": "...", "raw": "...", "changes": [...]}
|
OpenDictate.app -> Accessibility insert (paste fallback) -> cursor
meeting.m4a or segments.json / .jsonl
|
meeting_cli.py transcribe
|-- MLX Whisper audio files only
|-- glossary pairs the same deterministic table
|-- speaker labels SPEAKER_00, SPEAKER_01 (anonymous)
|-- QA flags possible mishearings, numbers
v
transcript.md .jsonl .srt .vtt meeting-result.json
socket 協定
五個指令。讀取端會忽略不認得的欄位,所以 daemon 加診斷資訊不會弄壞 app。no_speech 是正常結果,不算錯誤。
# requests: one JSON object per line on /tmp/open-dictate.sock
{"cmd": "transcribe", "wav": "/tmp/open-dictate-rec-....wav", "punct": "smart_zh"}
{"cmd": "ping"}
{"cmd": "reload_lexicon"}
{"cmd": "add_pair", "wrong": "誤聽", "right": "正確", "source": "dictate-ui"}
{"cmd": "stats"}
# responses
{"ok": true, "text": "校正後文字", "raw": "whisper 原始輸出", "changes": [["誤聽", "正確"]], "punct": "smart_zh"}
{"ok": false, "error": "no_speech"}
app 的轉錄逾時和 daemon 的標點預算,這兩個常數本身就是一組契約。只調其中一個,app 會以為 daemon 離線,daemon 其實在背景把事情做完。公式寫在契約裡。
東西在哪裡
| 元件 | 路徑 |
|---|---|
| Swift 選單列 app | OpenDictate/ |
| 語音輸入 daemon | daemon/dictated.py |
| 會議 CLI | daemon/meeting_cli.py |
| 誤聽掃描器 | daemon/qa/mishear_detector.py |
| 審核佇列 | daemon/glossary/ |
| 說話者層 | daemon/speaker/ |
| 內建詞庫 | vendor/tools/td-subtitle/glossaries/ |
| 詞庫引擎 | vendor/tools/muse-lexicon/muse_lexicon.py |
| 語音輸入日誌(本機) | ~/.open-dictate/dictation-log/ |
建置與測試
./build.sh
python3 -m unittest discover tests
python3 scripts/golden-bench.py --skip-daemon
python3 scripts/public-safety-scan.py
./scripts/smoke-test.sh # builds, tests, exports a meeting demo, checks the signed app
發 pull request 之前
- 範例只用虛構或公有領域的內容。
- 不要 commit 真實音檔、逐字稿、語音輸入日誌、私人路徑、個人詞庫或說話者資料。
- 優先用確定性校正和審核佇列,不要靜默改寫。
- 跑安全掃描和測試,有動到 Swift 就再跑
./build.sh。
文件
文件中英混合,有幾份只有單一語言。
07 · 給 AI 代理
給 AI 代理
程式代理(coding agent)可以在終端機裡安裝、診斷、擴充 Open Dictate,需要的東西都是純文字:這一頁、/llms.txt 和介面契約。它做不到的是開 macOS 權限,這一步留給你。
在這台 Mac 安裝:貼給 Claude Code
Clone https://github.com/frank890417/open-dictate,先讀 README.md、docs/SETUP.md 和 docs/PRIVACY.md。
確認這台 Mac 是 Apple Silicon、macOS 14 以上(uname -m、sw_vers)。不符合就停下來告訴我。
執行 ./install.sh。完成後跑 ./scripts/doctor.sh 和 python3 daemon/dictate_cli.py ping,把結果告訴我。
告訴我要在系統設定開哪三個權限、fn 鍵要怎麼設。這些你沒辦法幫我開。
不要刪除 ~/.open-dictate 底下任何東西,裡面是我的詞庫和日誌。
改程式:貼給 Claude Code
Clone https://github.com/frank890417/open-dictate。動 daemon/ 或 OpenDictate/ 之前先讀 IO-CONTRACT.md,那是兩邊之間的契約。
任務:<描述要改的東西,例如「在 stats 回應裡加一個欄位」>
repo 的規則:校正只用詞庫對照,不改寫句子,寧可漏改,不可錯改。socket 協定要向下相容。fixture 和測試只用虛構資料。
完成的條件:python3 -m unittest discover tests、python3 scripts/golden-bench.py --skip-daemon、python3 scripts/public-safety-scan.py 都通過,有改 Swift 的話 ./build.sh 也要成功。
給機器讀的
- /llms.txt這是什麼、處理流程、規則、所有文件,llmstxt.org 格式
- /llms-full.txtREADME、IO-CONTRACT.md 和所有文件合成一個檔
- IO-CONTRACT.mdapp、daemon、詞庫引擎之間的共同依據
application/ld+json這一頁帶有 SoftwareApplication 的 JSON-LD- /這一頁的英文版
MCP:規劃中,還沒做
目前還沒有 MCP 伺服器。路線圖的第一步是本機、唯讀、走 stdio 的伺服器,提供狀態、功能清單和詞庫數量。之後每個會動手的工具,都要在使用當下取得你的同意。用麥克風錄音仍然只能在 app 裡進行,沒有背景錄音,也沒有一次給到底的同意。
08 · 來歷
從哪裡來
Open Dictate 從一套每天在用的私人語音輸入工具抽出來,再重新整理成公開安全、沒有歷史包袱的 repo:沒有錄音、沒有逐字稿、沒有個人詞庫,只留下引擎、介面契約和虛構的範例。
現在公開 repo 是唯一的依據。作者自己的私人版本,只在同一套核心與打包流程上保留個人設定和 adapter。姊妹專案 open-audiovisual 也是這樣公開的:先在真實的工作裡用過,再拿出來。
系統可以標記、可以建議,但不能靜默改寫意思。
接下來,摘自路線圖
- 本機的說話者資料,取得同意才建檔,只存在你的 Mac
- 在選單列審核詞庫候選
- 匯入、匯出屬於你自己的詞庫包
- 不依賴 clone、開發用 Python 或 Xcode 工具就能執行的 app
- Developer ID 簽章、經過公證、在乾淨 Mac 上測過的 DMG
- 簽章過的 app 內更新、回滾、Stable 與 Beta 頻道