One-shot 本機會議轉錄與會議記錄 Instruction

2026-07-03
agent-instructionmeeting-notestranscriptionvibevoice

One-shot 本機會議轉錄與會議記錄 Instruction

這份 instruction 是給 agent 用的。目標是:使用者提供一個本機錄音或影片檔後,agent 一次完成媒體導入、Modal + VibeVoice 轉錄、品質檢查、會議記錄整理,最後在需要時請使用者確認 speaker 身份。

整個流程只根據使用者指定的本機檔案工作。不要假設有任何特定外部系統。

目標輸出

每次處理一個 media file,產出:

workdir/
├── input.meta.json
├── audio.ogg
├── transcript.vibevoice.json
├── transcript.txt
├── speaker-review.md
└── meeting-note.md

Phase 1: 導入本機錄音或影片

使用者可能提供:

處理規則:

  1. 展開路徑,確認檔案存在且是 regular file。
  2. 只處理一個檔案。若資料夾中有多個 media file,請使用者指定其中一個。
  3. 使用 ffprobe 讀取 duration、stream、codec 等基本資訊。
  4. 建立獨立 workdir,避免覆蓋先前輸出。
  5. 將原始檔案資訊寫入 input.meta.json

建議命令:

INPUT="/absolute/path/to/input.mp4"
WORKDIR="./local-meeting-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$WORKDIR"

ffprobe -v quiet -print_format json -show_format -show_streams "$INPUT" \
  > "$WORKDIR/input.ffprobe.json"

shasum -a 256 "$INPUT" > "$WORKDIR/input.sha256"

input.meta.json 至少記錄:

{
  "source_file": "/absolute/path/to/input.mp4",
  "source_sha256": "<sha256>",
  "duration_seconds": 0,
  "created_at": "YYYY-MM-DDTHH:MM:SSZ",
  "engine": "VibeVoice via Modal",
  "audio_file": "audio.ogg"
}

Phase 2: 標準化音訊

先把任何影片或錄音轉成單聲道音訊,再交給 VibeVoice。這能降低影片容器、codec、聲道數造成的不穩定。

建議使用 Opus 64kbps mono:

ffmpeg -y -i "$INPUT" \
  -vn \
  -c:a libopus \
  -b:a 64k \
  -ac 1 \
  "$WORKDIR/audio.ogg" \
  -loglevel warning

如果 VibeVoice runner 對 WAV 更穩定,也可以產出 24kHz mono WAV:

ffmpeg -y -i "$INPUT" \
  -vn \
  -ac 1 \
  -ar 24000 \
  "$WORKDIR/audio.wav" \
  -loglevel warning

轉檔後再跑一次 ffprobe,確認 duration 沒有明顯變短。若標準化音訊 duration 比原始 media 少很多,先停止並回報使用者,不要直接進轉錄。

Phase 3: 配合 Modal 與 VibeVoice 運作

前提:

典型命令:

modal run modal_vibevoice.py \
  --audio-path "$WORKDIR/audio.ogg" \
  --hotwords "$HOTWORDS"

預期輸出是一個 JSON transcript,例如:

{
  "segments": [
    {
      "Start": 0.0,
      "End": 4.2,
      "Speaker": 1,
      "Content": "..."
    }
  ],
  "text": "...",
  "model": "microsoft/VibeVoice-ASR-HF",
  "truncated": false,
  "coverage_end": 1234.5
}

將輸出固定整理成:

$WORKDIR/transcript.vibevoice.json

長音檔處理

長會議不要一次塞完整音訊給模型。建議策略:

粗略 ffmpeg 切段範例:

mkdir -p "$WORKDIR/chunks"

ffmpeg -y -i "$WORKDIR/audio.ogg" \
  -f segment \
  -segment_time 1500 \
  -c copy \
  "$WORKDIR/chunks/chunk_%03d.ogg"

若使用固定切段,請在合併時特別檢查邊界是否漏字或重複。silence-aware split 通常更好。

Phase 4: 轉錄 Best Practices

使用 hotwords

轉錄前建立 hotwords,放入:

範例:

Participants: Alice Chen, Bob Lee, Charlie Wang.
Products: Atlas, Billing API, Mobile SDK.
Terms: activation, retention, onboarding, API gateway, Q3 roadmap.

hotwords 只用來提升辨識,不可用來補寫逐字稿沒有出現的內容。

Coverage gate

每次轉錄後都要檢查 transcript 是否覆蓋完整音訊。

檢查點:

概念檢查:

coverage_ratio = transcript_last_end / audio_duration
assert not transcript.get("truncated")
assert coverage_ratio >= 0.97
assert len(transcript["segments"]) > 0

若失敗:

  1. 不要使用 partial transcript 產出正式會議記錄。
  2. 把失敗 JSON 改名保存,例如 transcript.vibevoice.truncated.json
  3. 使用更小 chunk 重新轉錄。
  4. 重新合併後再跑 coverage gate。

保留 timestamp

所有中間產物都要保留 timestamp。整理會議記錄時可以摘要,但遇到 action item、決議、關鍵數字、爭議點,最好能追溯到原始時間。

Speaker label 不等於人名

VibeVoice 的 Speaker 1Speaker 2 只是聲音分群,不是身份確認。除非使用者提供對照或 agent 取得明確確認,不要把 speaker label 直接改成人名。

不要用二手摘要當 ground truth

會議記錄只能根據逐字稿整理。檔名、行事曆標題、使用者口頭背景、模型猜測都只能作為輔助脈絡,不能拿來補出逐字稿沒有的決議或 action item。

Phase 5: 產生可讀逐字稿

將 VibeVoice JSON 轉成文字格式,方便使用者檢查,也方便後續 LLM 摘要。

格式:

[00:00:02-00:00:08] Speaker 1: 今天先討論下週上線前還缺什麼。
[00:00:09-00:00:15] Speaker 2: 我這邊主要卡在付款流程的測試資料。

轉換規則:

輸出:

$WORKDIR/transcript.txt

Phase 6: 整理成會議記錄

讀取 transcript.txt,整理成 meeting-note.md。不要逐字稿流水帳,請依議題歸納。

會議記錄模板:

# <會議標題>

## Overview

**來源檔案:** `<file name>`
**時長:** `<duration>`
**轉錄引擎:** VibeVoice via Modal
**Speaker 狀態:** 未確認 / 已確認

### Summary

用 80-150 字說明這場會議主要討論什麼、最後形成哪些方向。

## Topics

### 1. <議題標題>

- **狀態:** 已決議 / 未決議 / 討論中
- **結論:** <一句話描述目前結論>
- **討論重點:**
  - <Speaker 1> 提到...
  - <Speaker 2> 補充...
- **關鍵數字 / 日期 / 條件:**
  - <數字或日期>:<上下文>
- **相關時間:** 00:12:30-00:18:45

## Decisions

- <決議內容>(evidence: 00:23:10)

## Action Items

- [ ] <Speaker 或姓名>:<任務內容>(deadline: YYYY-MM-DD / 未指定;evidence: 00:31:22)

## Open Questions

- <問題>:<為什麼尚未解決 / 誰要跟進>

## Risks / Follow-up

- <需要後續確認的風險、缺口或低信心段落>

可直接使用的會議記錄整理 Prompt

transcript.txt 交給 LLM 時,可以使用以下 prompt。若 transcript 太長,先依時間分段使用同一個 prompt 抽出 topics / decisions / action items,再用第二輪合併成完整 meeting-note.md

你是一位專業的會議記錄整理助手。請只根據我提供的逐字稿整理會議記錄,不要使用外部資訊,不要根據檔名或背景描述補出逐字稿沒有的內容。

輸入:
- 逐字稿包含 timestamp 與 speaker label,例如 `[00:12:30-00:12:45] Speaker 1: ...`
- speaker label 可能尚未確認身分。除非我提供 speaker mapping,否則請保留 `Speaker 1`、`Speaker 2` 這種匿名標籤。
- 若我提供 speaker mapping,請使用確認後姓名,但不要猜測未確認的 speaker。

輸出語言:
- 使用使用者指定的語言。
- 若使用者沒有指定,使用會議主要語言。

任務:
1. 先判斷這場會議的主要目的與主軸。
2. 依照真實討論內容切分 topics,不要按照逐字稿時間流水帳重寫。
3. 對每個 topic,整理目前狀態、結論、討論重點、關鍵數字/日期/條件、相關 timestamp。
4. 列出所有明確 decisions。沒有明確共識的內容不要寫成決議。
5. 列出所有 action items。每個 action item 必須有 owner;若逐字稿沒有 owner,標為 `未指定`。deadline 不明時標為 `未指定`。
6. 列出會議結束時仍未解決的 open questions。
7. 標記低信心或需要使用者確認的段落,例如音訊不清、多人重疊、speaker 身分不確定。

品質規則:
- 不要虛構參與者、決議、owner、deadline、數字或理由。
- 任何數字、日期、金額、比例、版本號、承諾時程都要保留在相關 topic 中。
- action item 必須是會議中明確承諾或明確指派的事。
- 若 speaker 未確認,使用 `Speaker N`,不要自行替換成人名。
- 摘要可以改寫,但決議、任務、數字與風險必須能追溯到 timestamp。
- 如果逐字稿沒有足夠證據,請寫「逐字稿未明確說明」。

請輸出以下 Markdown 結構:

# <會議標題>

## Overview

**來源檔案:** <若有提供則填,否則寫未指定>
**時長:** <若有提供則填,否則寫未指定>
**Speaker 狀態:** 未確認 / 已確認 / 部分確認

### Summary

80-150 字說明這場會議主要討論什麼、形成哪些方向,以及還有哪些未決事項。

## Topics

### 1. <議題標題>

- **狀態:** 已決議 / 未決議 / 討論中
- **結論:** <一句話描述目前結論;沒有結論就寫未形成明確結論>
- **討論重點:**
  - <Speaker 或姓名>:<重點>
  - <Speaker 或姓名>:<重點>
- **關鍵數字 / 日期 / 條件:**
  - <數字或日期>:<上下文>
- **相關時間:** <timestamp range>

## Decisions

- <決議內容>(evidence: <timestamp>)

## Action Items

- [ ] <owner>:<任務內容>(deadline: <YYYY-MM-DD / 未指定>;evidence: <timestamp>)

## Open Questions

- <問題>:<為什麼尚未解決 / 誰可能需要跟進>

## Risks / Follow-up

- <低信心內容、需要使用者確認的 speaker、音訊品質問題或後續建議>

以下是逐字稿:

<TRANSCRIPT>
貼上 transcript.txt 全文
</TRANSCRIPT>

整理原則:

Phase 7: Speaker 確認

轉錄完成後,請產出 speaker-review.md,讓使用者可以確認 speaker 是誰。這一步可以在會議記錄前或後執行;若確認後再更新 note,品質會更好。

產生 speaker 摘要

針對每個 speaker,整理:

範例:

# Speaker Review

請回覆 mapping,例如:

```text
Speaker 1 = Alice
Speaker 2 = Bob
Speaker 3 = Unknown
```

## Speakers

### Speaker 1

- **總發言時間:** 約 18 分鐘
- **主要出現時段:** 00:00-12:30、28:10-42:05
- **代表片段:**
  - 00:02:14-00:02:32:「我們今天先把 launch blocker 收斂。」
  - 00:31:08-00:31:24:「我會在週五前補完測試資料。」
- **可能候選:** Alice / Bob / 不確定

### Speaker 2

- **總發言時間:** 約 9 分鐘
- **代表片段:**
  - 00:05:40-00:05:58:「付款流程還有一個 edge case。」
- **可能候選:** 不確定

套用使用者確認

使用者回覆 mapping 後:

  1. 建立 speaker-map.json
  2. transcript.txt 中的 speaker label 替換為確認後姓名。
  3. 重新產出 meeting-note.md
  4. 在 note 中標記 Speaker 狀態:已確認

如果使用者只確認部分 speaker,保留其他匿名 label,例如 Speaker 3。不要自行猜完。

Final Response

完成後回覆使用者:

範例:

已完成轉錄與會議記錄。

- Coverage: 98.6%,未偵測到 truncated。
- Transcript: workdir/transcript.txt
- Meeting note: workdir/meeting-note.md
- Speaker 尚未確認:請用 `Speaker 1 = ...` 格式回覆,我會再更新逐字稿與會議記錄。