會議逐字稿
本使用情境以 examples/meeting_transcriber.py 為主軸,這是一支約 280 行完整腳本,可加入 Discord 伺服器語音頻道,逐字辨識並即時標示發言者名稱,寫入本機 Markdown 檔,離開時再透過 Claude 產生「摘要 / 決議事項 / 行動項目 / 未解決問題」。
這個功能存在的核心原因是,最常見的語音需求不是「讓機器人發聲」,而是「要可搜尋的逐字紀錄」。本文件示範的就是這一點。
功能說明
- 以伺服器中的語音頻道 ID 連線。
- 串流音訊到 Deepgram(或 OpenAI Whisper),將每位發言者的最終結果即時輸出到主控台。
- 每一列都會附加到
~/.discli/transcripts/meeting-<YYYYMMDD-HHMMSS>.md。 - 按下 Ctrl+C 時,將完整逐字稿送入 Claude,並把結構化摘要附加到同一個檔案。
不包含的內容
- 無法在 DM 或群組 DM 語音使用:機器人權杖無法加入這類語音。
- 會議中不會即時總結:只在離開時一次輸出。
- 不支援跨會議辨識同一位說話者:顯示名稱取自當前伺服器成員資料。
安裝設定
pip install 'discord-cli-agent[voice,deepgram]' claude-agent-sdkdiscli config set token YOUR_BOT_TOKENexport DEEPGRAM_API_KEY=...先檢查:
discli doctor你應該看到 CORE、VOICE 都為綠色,且 DEEPGRAM_API_KEY 在 STT 欄位有設定。
Claude 總結使用你既有的 Claude Code 驗證,不需再額外配置 Anthropic API Key。
執行方式
先取得語音頻道 ID(Discord 開啟開發者模式,對目標語音頻道按右鍵複製 ID,或用 discli channel list --type voice):
python examples/meeting_transcriber.py 1016638171854938152若要改用 OpenAI Whisper:
export OPENAI_API_KEY=...python examples/meeting_transcriber.py 1016638171854938152 --stt openai會議過程中,主控台會出現逐字紀錄:
Connected as MyBot#1234 (12345)Listening to #standup。逐字稿:/home/me/.discli/transcripts/meeting-20260514-103000.md按 Ctrl+C 停止後會自動產生摘要。
- **[10:30:14] Roy:** 好,大家先依序報告——昨天大家做了什麼?- **[10:30:22] Sara:** 完成了 auth 轉移,並開始進行速率限制器- **[10:30:35] Roy:** 很好,現在有誰卡住了嗎?按 Ctrl+C 結束:
停止監聽…共處理 47 行文字…摘要成本:$0.0084
=== 會議摘要 ===
## 摘要團隊回顧昨日工作並規劃今日任務。Sara 已完成 auth移轉,接著進行 rate limiter。
## 關鍵決策- 本次移轉先採用 read-path-first 流程。
## 行動項目- Sara:今天完成 rate limiter。- Roy:在週五前完成移轉 runbook 文件。
## 未解決問題- 舊的會議會話要補回填,還是直接過期?
完整逐字稿與摘要已儲存到: /home/me/.discli/transcripts/meeting-20260514-103000.md輸出檔案
輸出的逐字稿是一般 Markdown,方便閱讀、可用 grep,也可提交到內部 repo 或轉貼到文件:
# 會議逐字稿 — 2026-05-14 10:30:00
- **頻道:** #standup(Engineering)- **機器人:** MyBot#1234
## 逐字稿
- **[10:30:14] Roy:** 好,大家先依序報告——昨天大家做了什麼?- **[10:30:22] Sara:** 完成了 auth 轉移,並開始進行速率限制器- **[10:30:35] Roy:** 很好,現在有誰卡住了嗎?
---
## 摘要...運作原理(約 280 行)
腳本刻意維持精簡,直接重用 discli 的 VoiceEngine,而非重建整套語音堆疊:
from discli.voice_engine import VoiceEngine
engine = VoiceEngine(config={"stt_provider": stt_provider})engine.set_event_handler(on_event)await engine.connect(channel)await engine.listen_start(channel.guild.id)on_event 會接收每一筆 voice_speech_detected 事件,根據伺服器成員查出顯示名稱,組成 markdown 行寫入檔案,也同步輸出到主控台:
def on_event(event: dict) -> None: if event.get("event") != "voice_speech_detected" or not event.get("is_final"): return uid = int(event.get("user_id") or 0) if uid == client.user.id: return name = resolve_name(uid) ts = datetime.now().strftime("%H:%M:%S") line = f"- **[{ts}] {name}:** {event['text']}" transcript_lines.append(line) print(line, flush=True) with path.open("a", encoding="utf-8") as f: f.write(line + "\n")按下 Ctrl+C 後,finally 會停止監聽、斷線,並將完整逐字稿透過 Claude 彙總:
async with sdk.ClaudeSDKClient(options) as claude: await claude.query(prompt) async for msg in claude.receive_response(): ...SUMMARY_SYSTEM_PROMPT 會要求 Claude 只輸出四個欄位:Summary(摘要)、Key decisions(關鍵決策)、Action items(行動項目)、Open questions(未解決問題),並使用逐字稿中的顯示名稱。
客製化
常見調整:
| 調整項目 | 說明 |
|---|---|
| 切換 STT 提供者 | 使用 --stt openai,或修改預設 stt_provider 設定 |
| 修改總結提示詞 | 編輯檔案上方的 SUMMARY_SYSTEM_PROMPT |
| 完全略過總結 | 在 finally 區塊註解 _write_summary(...) 呼叫 |
| 回傳總結到 Discord | 在寫入檔案後呼叫 client.get_channel(channel_id).send(summary) |
| 自訂逐字稿檔名 | 修改 path = transcript_dir / f"meeting-{stamp}.md" |
隱私
逐字稿會以顯示名稱紀錄每位參與者,因此應視為錄音紀錄來處理:
- 提前告知參與者正在轉錄;許多司法管轄區對錄音有同意義務
- 將檔案保存在私有目錄(預設
~/.discli/transcripts/位在使用者家目錄) - 若要將摘要張貼到公開頻道,先清除可能敏感內容
下一步
- 參考 Voice 了解完整語音堆疊
- 若要建立可同時處理其他任務的常駐型機器人,參考 建構代理
- 完整腳本請見
examples/meeting_transcriber.py