音声文字起こしパイプライン
Whisper、Deepgram、AssemblyAI を使用して、バッチ処理とリアルタイム文字起こしに対応した本番環境向け音声認識パイプラインを構築します。話者ダイアライゼーション機能も含みます。
意思決定ポイント
エンジン選択 決定木
要件に応じて:
├─ リアルタイムストリーミングが必要か?
│ ├─ はい: Deepgram Nova-3 WebSocket を使用(最速)
│ └─ いいえ: 次の精度要件へ
├─ 最高精度が必要で、GPUがあるか?
│ ├─ はい: faster-whisper で Whisper large-v3 を使用
│ └─ いいえ: 次のコスト分析へ
├─ 予算 < $0.0059/分 でコンピュートリソースがあるか?
│ ├─ はい: ローカル Whisper を使用
│ └─ いいえ: AssemblyAI Universal-2 を使用(最良のAPIダイアライゼーション)
バッチ vs ストリーム処理
音声の特性に応じて:
├─ 再生時間 > 30分?
│ ├─ はい: バッチ処理(無音部分でチャンク分割)
│ └─ いいえ: 次のレイテンシチェックへ
├─ 結果を10秒未満で得る必要があるか?
│ ├─ はい: ストリーミングを使用(Deepgram/Whisper.cpp)
│ └─ いいえ: バッチ処理を使用(精度向上のため)
VAD(音声区間検出)の使用
コンテンツの種類に応じて:
├─ ライブ会話/会議?
│ ├─ はい: VADを有効にする(無音部分で40-60%の計算量削減)
│ └─ いいえ: 次のコンテンツチェックへ
├─ 講義/プレゼンテーションで間がある場合?
│ ├─ はい: 保守的なVADを使用(min_silence_duration_ms: 1000)
│ └─ いいえ: 密な音声の場合はVADをスキップ(オーディオブックなど)
ドメイン別モデル選択
言語/アクセントに応じて:
├─ 非英語または強いアクセント?
│ ├─ はい: Whisper large-v3 を使用(最良の多言語対応)
│ └─ いいえ: 次の速度チェックへ
├─ レイテンシ < 1秒が必要?
│ ├─ はい: Deepgram Nova-3 ストリーミングを使用
│ └─ いいえ: ビジネス/医療用語には AssemblyAI を使用
障害モード
無音時の幻覚出力
検出: 無音区間中に繰り返しフレーズや幻の音楽説明が表示される
診断: VADが無効またはしきい値が低すぎ、モデルが背景ノイズからテキストを生成している
修正: VADを有効にして min_silence_duration_ms: 500 を設定、Whisperで --no_speech_threshold 0.6 を使用
10人超の話者でのダイアライゼーション崩壊
検出: 10~15分後に全話者が「話者1」とラベル付けされる、または文の途中でランダムに話者が切り替わる
診断: 話者埋め込みモデルが飽和、混雑した音声内での重なり混乱
修正: 無音部分で事前にセグメント分割、ステレオの場合は AssemblyAI の dual_channel を使用、最大アクティブ話者を8人に制限
ビデオとのタイムスタンプ同期ずれ
検出: 字幕が対応するビデオフレームより2~5秒前後に表示される
診断: 音声前処理で再生時間が変更された、または VAD がタイムスタンプ調整なしでセグメントを削除した
修正: 前処理で --preserve_timing を使用、元の音声タイムコードと同期、既知の音声イベントに対して検証
言語自動検出の失敗
検出: アクセントのある話者の英語単語が意味不明な文字列として書き起こされる、またはコードスイッチングが無視される
診断: 最初の30秒でモデルが誤った言語に固定された、または多言語コンテンツが分類器を混乱させた
修正: アクセントのある英語には language="en" で言語を強制、非英語から英語への変換には task="translate" を使用
長尺ファイルでのメモリオーバーフロー
検出: 45分超のファイルでOOMクラッシュ、または30分後に突然の品質低下
診断: モデルがコンテキストウィンドウを保持し続け、GPU VRAMが枯渇
修正: 25分境界で30秒のオーバーラップを持たせてチャンク分割、RAM効率化のために --without_timestamps を使用
作業例
完全な会議文字起こしウォークスルー
シナリオ: 90分の取締役会議、6人の話者、議事録用に正確な話者識別とタイムスタンプが必要
入力分析:
- 90分 → チャンク分割が必要
- 6人の話者 → ダイアライゼーションの制限内
- ビジネスコンテキスト → 用語のために AssemblyAI を使用
決定パス:
- 再生時間 > 30分 → バッチ処理が必要
- 話者数 = 6人 → ダイアライゼーションが可能
- ビジネス領域 → AssemblyAI Universal-2 を選択
- 高精度が必要 → 話者ラベル + スマートフォーマットを有効化
実装:
# ステップ1: 前処理(上級者の注意点: 音声レベルを正規化)
ffmpeg -i meeting.mp4 -ar 16000 -ac 1 -filter:a "volume=0.8" meeting_clean.wav
# ステップ2: オーバーラップ付きチャンク分割(初心者はファイル全体を処理する)
from pydub import AudioSegment
audio = AudioSegment.from_wav("meeting_clean.wav")
chunks = []
for i in range(0, len(audio), 25*60*1000): # 25分チャンク
chunk = audio[i:i+27*60*1000] # 2分のオーバーラップで27分
chunks.append(chunk)
# ステップ3: ダイアライゼーション付き文字起こし
results = []
for chunk in chunks:
response = assemblyai_client.transcribe(
chunk, speaker_labels=True, auto_punctuation=True,
dual_channel=False, speaker_labels_max=8
)
results.append(response.get_paragraphs())
# ステップ4: オーバーラップセグメントをマージ(初心者が見逃す上級者ステップ)
merged = merge_overlapping_transcripts(results, overlap_seconds=120)
上級者 vs 初心者:
- 初心者: 90分のファイルを直接処理 → OOMクラッシュまたは精度低下
- 上級者: オーバーラップ付きチャンク分割、チャンク間の話者一貫性を検証、最初に音声を正規化
品質ゲート
- 既知の正解データを用いたテストサンプルで WER(単語誤り率)< 5%
- 話者精度 > 90%(正解データがある場合、各発話の話者IDが正しいこと)
- ストリーミング実装のエンドツーエンドリアルタイムレイテンシ < 2秒
- SRT/VTT ファイルが検証を通過(適切なタイムスタンプ、重複セグメントなし)
- 音声前処理完了: 16kHz モノラル WAV/FLAC フォーマットであることを確認
- VAD パラメータ調整済み: サンプルで無音検出の偽陽性 < 10%
- 2時間までのファイルでメモリ使用量 < 8GB(チャンク分割が適切に機能していること)
- API エラーハンドリングテスト済み: タイムアウト、リトライ、クォータ超過に対応
- ダイアライゼーションの話者数が期待値と一致(±1話者の許容範囲)
- 出力タイムスタンプが元の音声と100ms以内の精度で一致
適用外の境界
このスキルは以下には使用しないでください:
- テキスト読み上げ合成 → 代わりに
voice-audio-engineerを使用 - 音楽文字起こしまたは歌詞抽出 → 音楽AIモデルには
ai-engineerを使用 - 文字起こしなしの音声分類 → 音声分類には
ai-engineerを使用 - リアルタイム翻訳(文字起こし+翻訳) →
language-translatorスキルと組み合わせる - 音声生体認証または話者識別 → 話者認識モデルには
ai-engineerを使用 - 音声品質向上またはノイズ低減 → 音声処理には
voice-audio-engineerを使用
委任する場合:
- カスタムウェイクワード検出が必要 →
voice-audio-engineer - 音声フィンガープリンティングが必要 →
data-pipeline-engineer - 音声アシスタントの構築 →
voice-audio-engineer+conversation-designer - 10,000時間超の処理 → オーケストレーションには
data-pipeline-engineer