之前寫過一篇〈jt-vc-portal:替 Jitsi Meet 補上會議管理入口〉,介紹我替 Jitsi Meet 做的會議管理入口:建立會議室、邀請來賓、帳號權限、稽核記錄,以及搭配自建 Jibri 的錄影調閱。
這幾個月 jt-vc-portal 最大的進展,是和我另一個專案 jt-live-whisper(以下簡稱 JTLW)整合:會議錄影完成後,自動產生含發言者的逐字稿與會議摘要,決議、待辦、風險每一條都附錄影時間點,點一下就跳到錄影的那個位置播放。整個流程都在自己的主機上完成,錄影與逐字稿不會送到任何雲端服務。
整合緣由
視訊會議開完,最花時間的往往是會後整理:誰說了什麼、決議了哪些事、誰負責哪個待辦、期限是什麼時候。有錄影當然可以回頭看,但一場一小時的會議,要從錄影裡找出某個決議是在哪裡講的,並不容易。
市面上的雲端會議服務大多已經有 AI 會議記錄,但對很多企業與公部門來說,會議錄影與內容不能離開自己的環境,這也是當初選擇自建 Jitsi Meet 的原因之一。
JTLW 本來就是全地端的 AI 語音工具箱,語音辨識、發言者分離、逐字稿校正與摘要都在自有設備上推論。把兩者接起來,就能在不送出任何資料的前提下,讓自建的視訊會議也有會後自動整理的能力。
運作流程
整個流程分成三段:
- 錄影:Jitsi Meet 會議由 Jibri 錄影,錄影檔存在 Jibri 主機上,由
jibri-recordings-api提供調閱 - 送件:jt-vc-portal 以 token 向 Jibri 主機取得錄影檔,以串流方式上傳給 JTLW
- 處理與取回:JTLW 依序完成語音辨識、發言者分離、逐字稿校正與摘要,完成後以 webhook 通知 portal;portal 取回結果寫入磁碟後,再通知 JTLW 刪除它那邊的副本
幾個設計重點:
- portal 本身不連任何語言模型:辨識與摘要都在 JTLW 完成,用哪個模型由 JTLW 端設定
- 背景排程每分鐘執行一次:負責送件、追蹤進度、取回結果;一次上傳一筆錄影,大檔上傳中下一輪會自動跳過
- webhook 是選用的:JTLW 連不到 portal 時也能運作,排程每分鐘會主動查詢一次進度
- 結果跟著錄影走:刪除錄影,或 Jibri 的保留政策清掉錄影時,逐字稿與摘要也一併刪除
注意:只支援自建 Jitsi Meet + Jibri。8x8 JaaS 模式的錄影存在 8x8 雲端,portal 拿不到檔案,無法產生逐字稿。
建立會議室時決定是否產生逐字稿
有逐字稿權限的主持人,建立會議室時會多一個「錄影完成後產生逐字稿與摘要」選項,預設勾選;不需要的場次取消勾選即可。
勾選時必須選擇會議主要語言,語音服務會依這個選擇挑選辨識模型:
- 中文、英文、日文、韓文為主:一般辨識模式,並做發言者分離。會議摘要支援中文與英文,日文、韓文只產生逐字稿
- 台語(閩南語)為主:改用台語專用的 MediaTek Breeze-ASR-26 模型,直接輸出華語漢字;這個模式不做發言者分離,摘要僅供參考
夾雜多種語言時,選講最多的那一種。會議中有台語就選台語,只偶爾一兩句台語的會議選「中文為主」,才能分出發言者。語音服務不會自動判斷台語,所以一定要在這裡指定。

錄影記錄與處理狀態
錄影記錄頁多了「主要語言」與「逐字稿」兩欄,每一場會議的處理狀態一目了然:
- 查看逐字稿與摘要(綠色):已完成,點進去檢視
- 處理中:排隊或處理中,可以取消
- 產生失敗 / 等待重試:滑過或展開可以看到原因
- 產生逐字稿(虛線框):尚未產生,按下即排入處理
辨識暫時失敗時(例如語音服務的 GPU 伺服器暫時不能用),會在 10、30、60 分鐘後自動重試,不需要重新上傳錄影;摘要因語言模型暫時故障而失敗時,也會自動重做摘要、保留已完成的逐字稿。

會議摘要
逐字稿檢視頁最上方是會議摘要,內容包含:
- 重點摘要:整場會議的重點整理
- 決議與待辦:待辦會列出負責人與期限
- 事件與影響、風險、未決問題
- 議題時間軸:會議依序討論了哪些議題
- 發言統計:每個人講了多久
每一條都附錄影時間點與發言者,點一下就跳到錄影該處播放,並標亮對應的逐字稿段落。要確認某個決議當時是怎麼說的,不必再拖著進度條找。

逐字稿與發言者對應
逐字稿依發言者分色顯示,上方是整段錄影的波形播放器,播放時逐字稿會跟著自動捲動,點任一段的時間也能跳到該處播放。
發言者改名
語音服務分出來的發言者代號(S1、S2…)是依聲音分群,不是人名。點名字就能改名,預設同一個代號全部一起改,也可以只改單一段落。改好的名字會套用到摘要內文、負責人與所有匯出檔。
發言者對應建議
這是我覺得最實用的一個功能。主持人開著會議頁時,portal 會記錄 Jitsi 本身偵測到的「目前發言者」時間軸,逐字稿頁會拿這條時間軸跟 S1、S2 的發言時間比對,列出建議的參與者與重疊比例,例如「S1 → 王經理 91%」,按一下「全部套用最可能的人」就完成改名。
注意:主持人的會議頁要全程開著,發言者時間軸才完整;中途關閉的場次仍可手動改名。

發言者辨識方式
v1.17.0 起,portal 送件時會要求 JTLW 使用較新的發言者辨識(NVIDIA Nemotron 3 Diarization)。依 JTLW 的實測,7 人座談從原本「分成 3 位」改善為「分成 7 位」,段落發言者錯誤率由 28% 降到 3%,摘要裡的發言統計與引用也跟著變準。發言者超過 8 位時,JTLW 會自動改用舊方法,逐字稿頁也會提醒分組可能較不準。
會議記錄匯出
整份會議記錄(會議資訊、摘要、議題、發言統計、逐字稿)可以匯出成:
| 格式 | 說明 |
|---|---|
| 內嵌 Noto Sans TC 字型,中日文正常顯示,可選取與搜尋 | |
| DOCX / ODT | 可以用 Microsoft Word 或 LibreOffice 繼續編輯 |
| HTML | 單一檔案、樣式內嵌、不含 script,手機閱讀與列印都正常 |
| 其他 | 純文字、SRT 字幕、JSON、摘要 Markdown |
所有格式都會套用改好的發言者名稱。這些檔案全部由 portal 自己產生,主機上不需要安裝 LibreOffice 或瀏覽器引擎。

權限控管
逐字稿牽涉會議內容,權限分成三層:
| 層級 | 設定位置 | 說明 |
|---|---|---|
| 帳號 | 帳號管理的「逐字稿權限」 | 不可使用(預設)、手動、自動 |
| 單場 | 建立會議室時的選項 | 有權限的主持人才看得到,不能超過帳號權限 |
| 管理員 | 不需另外設定 | 可以對任何場次產生、取消、重新產生或刪除逐字稿 |
主持人只看得到自己主持場次的錄影與逐字稿。稽核記錄會記下誰產生、檢視、下載、改名或刪除逐字稿,但不會記錄逐字稿內容。
另外,第一次啟用這個功能的時間會被記下,自動產生只處理啟用之後錄的會議,不會把舊錄影一次全部送出去處理。舊錄影要產生逐字稿,在錄影記錄頁手動按「產生逐字稿」即可。
設定步驟
完整步驟請參考專案的 TRANSCRIPTS-SETUP_zh-TW.md,以下整理重點。
需求
- 自建 Jitsi Meet + Jibri,Jibri 主機上已安裝
jibri-recordings-api,並已在 portal 的「系統設定 → 錄製設定」接上 - jt-live-whisper 的 REST API
api_revision2.4 以上,一般部署在有 GPU 的主機,一次處理一件,其餘排隊 - portal 主機要能連到 JTLW 的 API 連接埠(預設 HTTPS 8790);選用:JTLW 能連回 portal 的
/jtlw-webhook
JTLW 端:建立 API 金鑰
在 JTLW 主機上,替 portal 建立一把專用的 API 金鑰,權限範圍只給需要的四項:
cd <jt-live-whisper 安裝目錄>
venv/bin/python -m jtlw_api.keys add jtvc jobs:write jobs:read jobs:cancel profiles:read
金鑰只會顯示這一次,請妥善保存。請勿給 admin 權限,每個系統各用一把,金鑰只看得到自己送出的作業。
接著把 portal 主機的 IP 加進 JTLW config.json 的 api.allowed_hosts,然後重新啟動 API 服務:
sudo systemctl restart jtlw-api
JTLW 預設使用自簽憑證,取得憑證後先核對 SHA-256 指紋:
openssl x509 -in jtlw-api.crt -noout -fingerprint -sha256
portal 端:系統設定
在「系統設定 → 逐字稿與摘要」填入:
- 語音服務(JTLW)網址:例如
https://192.168.1.30:8790,不用加/api/v1 - API 金鑰:上一步建立的金鑰
- 語音服務的憑證:自簽憑證請貼上 PEM。portal 一律驗證憑證,不提供關閉檢查的選項,畫面上會顯示 SHA-256 指紋供核對
- 預設會議語言、辨識模式、發言者辨識方式(建議選「自動」)、是否同時產生會議摘要
填好後依序按「儲存並測試連線」與「註冊 webhook」。webhook 的簽章密鑰由 JTLW 產生並自動存起來,之後每則通知都以 HMAC 驗證簽章。

背景排程
送件、查詢進度、取回結果都由每分鐘執行一次的排程完成。Docker 部署時在主機上加入:
# /etc/cron.d/jtvc-transcribe
* * * * * root docker exec -u www-data jt-vc-portal php /var/www/html/transcribe-worker.php >/dev/null 2>&1
直接安裝時:
# /etc/cron.d/jtvc-transcribe
* * * * * www-data php /var/www/jt-vc-portal/transcribe-worker.php >/dev/null 2>&1
要看詳細的處理過程,可以手動加上 -v 執行一次。排程超過 10 分鐘沒有執行時,系統設定頁的「逐字稿與摘要」卡片會顯示警示,不會默默停擺。
資料安全
這個整合從一開始就以「資料不離開自己環境」為前提設計:
- 錄影以串流上傳到 JTLW,JTLW 處理完即刪除上傳檔;portal 取回結果並寫入磁碟後,才通知 JTLW 刪除作業記錄
- portal 連 JTLW 一律驗證 TLS 憑證,自簽憑證以貼上的 PEM 信任,不會關閉驗證
- webhook 以 HMAC 簽章並驗證時間窗,依事件 ID 去除重複
- 送件帶 Idempotency-Key,網路中斷重送也不會重複處理
- API 金鑰與 webhook 密鑰不會回填到頁面上
結論
jt-vc-portal 一開始只是想替 Jitsi Meet 補上會議管理的入口,加上 jt-live-whisper 之後,自建的視訊會議也有了會後自動整理的能力:開完會,逐字稿、摘要、決議與待辦就整理好了,每一條都能點回錄影確認。
對不能把會議內容交給雲端服務的單位來說,這應該是很實用的組合。兩個專案都是開源的,有自建 Jitsi Meet 的朋友可以參考看看。
參考資料
- jt-vc-portal:專案網站
https://jasoncheng7115.github.io/jt-vc-portal/ - jt-vc-portal:原始碼庫(GitHub)
https://github.com/jasoncheng7115/jt-vc-portal - jt-vc-portal:會議逐字稿與摘要設定指南
https://github.com/jasoncheng7115/jt-vc-portal/blob/main/TRANSCRIPTS-SETUP_zh-TW.md - jt-live-whisper:專案網站
https://jasoncheng7115.github.io/jt-live-whisper/ - jt-vc-portal:替 Jitsi Meet 補上會議管理入口
https://blog.jason.tools/2026/07/jt-vc-portal-1.html - jt-doc-tools 會議摘要:錄音轉逐字稿與決議待辦整理,全程地端處理
https://blog.jason.tools/2026/09/jt-meeting-summary.html



