概要
インストール
コンテンツ詳細
代替品
MCP話者分離とは?
これは、次のタスクを自動的に実行できる高度な音声処理システムです。 1. **話者分離**:音声データ内で何人の異なる話者がいるかを識別する。 2. **話者識別**:各話者の声の特徴を記憶し、次回聞いたときに自動的に識別する。 3. **感情検出**:話す際の感情状態(喜び、怒り、中立など)を分析する。 4. **音声文字変換**:会話内容を文字記録に変換する。 このシステムは、会議記録、カスタマーサービス分析、多輪会話などのシーンに特に適しており、AIアシスタントに完全な会話コンテキストの記憶を提供することができます。MCP話者分離をどのように使用するか?
使用方法は非常に簡単です。 1. **音声ファイルのアップロード**:MP3、WAVなどの一般的な形式に対応しています。 2. **リアルタイム録音**:ウェブページから直接録音し、リアルタイムで処理することができます。 3. **結果の確認**:システムが自動的に誰が何を話し、どのような感情で話したかを分析します。 4. **AI統合**:MCPプロトコルを介して、AIアシスタントも会話履歴にアクセスできるようにします。 専門知識は必要ありません。システムは自動的に学習し、識別精度を向上させます。適用シーン
このシステムは、次のシーンに特に適しています。 • **チーム会議記録**:異なる発言者を自動的に区別し、会議内容を記録する。 • **カスタマーサービス品質分析**:カスタマーサービス担当者と顧客の会話の感情と内容を分析する。 • **AIアシスタントの機能強化**:AIが異なるユーザーの会話履歴と身元を記憶できるようにする。 • **インタビューの文字起こし**:インタビューの録音を迅速に話者ラベル付きの文字起こしに変換する。 • **言語学習**:会話の音声パターンと感情表現を分析する。主な機能
使い方
使用例
よくある質問
関連リソース
インストール
{
"mcpServers": {
"speaker-diarization": {
"url": "http://localhost:8000/mcp",
"transport": "http"
}
}
}
{
"mcpServers": {
"speaker-diarization": {
"command": "node",
"args": ["/path/to/mcp-proxy.js", "http://localhost:8000/mcp"]
}
}
}🚀 MCP Speaker Diarization
このアプリケーションは、GPUで高速化された話者分離と認識を、ウェブインターフェースとREST APIと組み合わせたオールインワンの完全なパッケージです。pyannote.audioによる話者分離とfaster-whisperによる文字起こしを統合し、AIエージェントの統合や趣味プロジェクトに最適化されています。
✨ 主な機能
- 永続的な話者認識: 話者を一度登録すると、将来のすべての録音や会話で認識されます(単なる"SPEAKER_00", "SPEAKER_01"のラベルではなく)。
- デュアル検出器感情システム: 一般的なAI(emotion2vec+)と個人化された音声プロファイルを組み合わせることで、9つの感情(怒り、喜び、悲しみ、中立、恐怖、驚き、嫌悪、その他、不明)の検出精度を劇的に向上させます。
- 個人化学習: システムは、修正によって各話者の独特な感情音声パターンを学習します(再登録は必要ありません)。
- 遡及的な知能: あるセグメントを特定すると、同じ声の過去のすべてのセグメントが自動的に更新されます。
- 文字起こし: faster-whisper(large-v3)を使用し、単語レベルの信頼度スコアと99言語をサポートします。
- ライブストリーミング: WebSocketストリーミング、VAD(音声活動検出)、および即時処理によるリアルタイム録音をサポートします。
- AI対応アーキテクチャ: 組み込みのMCPサーバーにより、AIアシスタント(Claude Desktop、Flowise、カスタムエージェント)とのシームレスな統合が可能で、自然な多者会話に必要なコンテキストメモリを提供します。
- REST API:
/api/v1/*で完全なプログラムアクセスが可能です(詳細なドキュメントは/docsを参照)。 - バックアップ/復元: 話者プロファイルと音声設定のエクスポート/インポートが可能です。
- 本番環境対応: 数千の会話、バッチ処理、ライブストリーミング、MP3変換を処理し、効率的にスケールします。
📦 インストール
前提条件
- HuggingFaceトークンの取得
- huggingface.coでアカウントを作成します。
- huggingface.co/settings/tokensでトークンを生成します。
- 以下のモデルの利用規約に同意します。
- NVIDIA Container Toolkitのインストール(Dockerデプロイメントの場合)
# Ubuntu/Debian
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo systemctl restart docker
オプション1: Dockerデプロイメント(推奨)
# リポジトリをクローン
git clone <repository-url>
cd speaker-diarization-app
# 環境設定をコピー
cp .env.example .env
# .envを編集し、HF_TOKENを追加
# ビルドして実行
docker-compose up --build
# バックグラウンドで実行
docker-compose up -d
# ログを表示
docker-compose logs -f
アプリケーションにアクセスするには:
- APIドキュメント: http://localhost:8000/docs
- APIエンドポイント: http://localhost:8000/api/v1
- MCPサーバー: http://localhost:8000/mcp
ウェブインターフェースについては、別のNext.jsフロントエンドリポジトリを参照してください。
オプション2: ローカル開発(Python venv)
# システム依存パッケージをインストール
sudo apt-get update
sudo apt-get install -y ffmpeg git portaudio19-dev
# Python環境をセットアップ
python -m venv venv
source venv/bin/activate # Windowsの場合: venv\Scripts\activate
# Pythonパッケージをインストール
pip install -r requirements.txt
# 環境設定をコピー
cp .env.example .env
# .envを編集し、HF_TOKENを追加
# アプリケーションを実行
./run_local.sh
# または手動で実行:
# export HF_TOKEN="your_token_here"
# python -m app.main
初回実行時:
- モデルが自動でダウンロードされます(約3 - 5GB)。
- モデルの読み込みに2 - 3分かかる場合があります。
- GPUメモリが割り当てられます(
nvidia-smiで確認)。
💻 使用例
基本的な使用法
# ここにコード例を入れる予定だったが、元のREADMEに具体的な基本使用法のコード例がないため省略
高度な使用法
# ここに高度な使用法のコード例を入れる予定だったが、元のREADMEに具体的な高度使用法のコード例がないため省略
📚 ドキュメント
REST APIとMCPサーバー
API概要
ベースURL: http://localhost:8000/api/v1
インタラクティブなドキュメント: http://localhost:8000/docs(Swagger UIとテストインターフェース付き)
主要なエンドポイント:
- システム
GET /status- ヘルスチェック、GPUの状態、システム統計情報
- 設定
GET/POST /settings/voice- ランタイム設定(閾値、パディング、フィルタリング)POST /settings/voice/reset- デフォルトにリセット
- 話者
GET /speakers- 登録されたすべての話者とセグメント数をリスト表示POST /speakers/enroll- 音声サンプルで新しい話者を登録PATCH /speakers/{id}/rename- 話者の名前を変更(過去のすべてのセグメントを自動更新)DELETE /speakers/{id}- 話者プロファイルを削除DELETE /speakers/unknown/all- すべてのUnknown_*話者を削除
- 感情プロファイル
GET /speakers/{id}/emotion-profiles- 学習された感情プロファイルを表示DELETE /speakers/{id}/emotion-profiles- 感情プロファイルをリセットGET/PATCH /speakers/{id}/emotion-threshold- 話者ごとの感情閾値PATCH /speakers/{id}/emotion-profiles/{emotion}/threshold- 感情ごとの閾値
- 会話
GET /conversations- すべての会話をページング表示GET /conversations/{id}- すべてのセグメントを含む完全な文字起こしを取得PATCH /conversations/{id}- 会話のメタデータを更新DELETE /conversations/{id}- 会話と音声ファイルを削除POST /conversations/{id}/reprocess- 現在の話者で話者分離を再実行POST /conversations/{id}/recalculate-emotions- すべてのセグメントの感情を再計算POST /process- 音声ファイルをアップロードして処理
- セグメント
POST /conversations/{id}/segments/{seg_id}/identify- 話者を特定(過去のすべてのセグメントを自動更新)POST /conversations/{id}/segments/{seg_id}/correct-emotion- 感情を修正して学習PATCH /conversations/{id}/segments/{seg_id}/misidentified- 話者を誤認識としてマークPATCH /conversations/{id}/segments/{seg_id}/emotion-misidentified- 感情を誤認識としてマークGET /conversations/segments/{seg_id}/audio- セグメントの音声をダウンロード
- ストリーミング
WS /streaming/ws- ライブ録音用のWebSocket
- バックアップ/復元
POST /profiles- 新しいバックアッププロファイルを作成GET /profiles- すべてのバックアッププロファイルをリスト表示GET /profiles/{name}- 特定のプロファイルの詳細を取得PATCH /profiles/{name}- 現在の状態をプロファイルに保存DELETE /profiles/{name}- バックアッププロファイルを削除POST /profiles/{name}/checkpoints- チェックポイントを作成POST /profiles/restore- バックアップから復元GET /profiles/download/{name}- バックアップJSONをダウンロードPOST /profiles/import- バックアップJSONをインポート
📖 例付きの完全なドキュメント: http://localhost:8000/docs
MCPサーバーの統合
モデルコンテキストプロトコル(MCP) は、AIアシスタントが話者分離システムと直接やり取りできるようにします。
MCPエンドポイント: http://localhost:8000/mcp
プロトコル: サーバー送信イベント付きのHTTP上のJSON-RPC 2.0
互換性のあるツール: Claude Desktop、Flowise、カスタムMCPクライアント
利用可能なMCPツール(11個):
list_conversations- 会話IDとメタデータを取得get_conversation- 話者ラベル付きの完全な文字起こしを取得get_latest_segments- 複数の会話にまたがる最近のセグメントを取得identify_speaker_in_segment- 未知の話者をラベル付け(過去のすべてのセグメントを自動更新)rename_speaker- 既存の話者の名前を変更(過去のすべてのセグメントを自動更新)list_speakers- 登録されたすべての話者プロファイルを取得delete_speaker- 話者プロファイルを削除delete_all_unknown_speakers- Unknown_*話者をクリーンアップupdate_conversation_title- 会話のタイトルを設定reprocess_conversation- 更新された話者プロファイルで認識を再実行search_conversations_by_speaker- 特定の話者が登場するすべての会話を検索
主な機能:
- 自動遡及更新: 話者を特定または名前を変更すると、過去のすべてのセグメントが自動的に更新されます。
- 再処理不要: システムはセッション間で話者の同一性を維持します。
- 自動登録: 任意のセグメントから話者プロファイルを作成できます。
- 会話コンテキスト: AIは完全な「誰が何を言ったか」の履歴を取得できます。
例のMCPクライアント設定(Flowise/Claude Desktop):
{
"mcpServers": {
"speaker-diarization": {
"url": "http://localhost:8000/mcp",
"transport": "http"
}
}
}
使用例:
# AIアシスタントが会話を受け取る
Assistant: "複数の声が聞こえました。誰と話していたんですか?"
User: "それは私の同僚のSarahです"
# AIがMCPツールを呼び出す
# identify_speaker_in_segment(segment_id=145, speaker_name="Sarah", auto_enroll=true)
# システムが自動的に:
# 1. セグメント145からSarahの話者プロファイルを作成
# 2. すべての過去のセグメントをSarahの声で更新
# 3. 将来の録音でSarahを自動的に認識
AIアシスタントの統合例
REST APIまたはMCPサーバーを使用して、永続的な話者メモリを持つ会話型AIアシスタントを構築します。
統合アプローチ
オプション1: REST API(完全なコントロール)
- あなたのアプリが音声録音とストリーミングを管理します。
/api/v1/processに音声をPOSTするか、WebSocket/streaming/wsを使用します。- 話者ラベルと感情付きのセグメントを受け取ります。
/conversationsエンドポイントを介して会話履歴を照会します。
オプション2: MCPサーバー(AIネイティブ)
- Claude Desktop、Flowise、またはカスタムMCPクライアントを接続します。
- AIアシスタントが10個のMCPツールを直接呼び出して話者管理を行います。
- 話者を特定または名前を変更する際に自動的に遡及更新されます。
- ゼロコード - MCPエンドポイントを設定するだけです。
例のワークフロー
シナリオ: AIアシスタントが多者会話を行っている
- 未知の話者が検出される
User: "さて、元気ですか?"
Unknown: "元気です、あなたは?"
AI: "誰と話しているんですか?"
User: "それはNickです"
- AIがMCPを介して話者を特定する
# MCPツールの呼び出し(Claude/Flowiseを使用する場合は自動)
identify_speaker_in_segment(
segment_id=145,
speaker_name="Nick",
auto_enroll=true
)
- システムが過去のすべてのセグメントを自動更新する
- Nickの音声プロファイルを作成します。
- Nickの声のすべての以前のUnknownセグメントを更新します。
- 将来の録音でNickを自動的に認識します。
- AIが将来の会話でNickを覚えている
Nick: "ねえ、昨日話したことを覚えている?"
AI: "はい、Nick。あなたはプロジェクトの締め切りについて言及しました..."
REST APIのクイックスタート
import requests
# 音声ファイルを処理
with open("meeting.wav", "rb") as f:
response = requests.post(
"http://localhost:8000/api/v1/process",
files={"audio_file": f}
)
conversation = response.json()
# 話者付きの完全な文字起こしを取得
for segment in conversation["segments"]:
print(f"{segment['speaker_name']}: {segment['text']}")
print(f" 感情: {segment['emotion_category']} ({segment['emotion_confidence']})")
MCPの設定
Claude Desktop (~/.claude/claude_desktop_config.json):
{
"mcpServers": {
"speaker-diarization": {
"command": "node",
"args": ["/path/to/mcp-proxy.js", "http://localhost:8000/mcp"]
}
}
}
Flowise: MCPノードを追加し、URLをhttp://localhost:8000/mcpに設定します。
主な利点
- 永続的な同一性: すべての会話で話者が認識されます。
- 再登録不要: 一度特定すると、永遠に認識されます。
- 遡及的な知能: 誰かを特定すると、過去のセグメントが自動的に更新されます。
- 感情コンテキスト: AIは「誰」だけでなく、「どんな気持ち」で話しているかを知ります。
- 本番規模: 数千の会話をサブ秒単位のクエリで処理します。
🔧 技術詳細
感情検出
デュアル検出器システムは、一般的なAIと個人化された音声プロファイルを組み合わせることで、精度を劇的に向上させます。
仕組み
2つの補完的な検出器が連携して動作します。
- emotion2vec+検出器(1024次元の感情埋め込み)
- 大規模なデータセットで学習された一般的な感情AI
- すべての話者(既知/未知)に対応
- 9つのカテゴリ: 怒り、喜び、悲しみ、中立、恐怖、驚き、嫌悪、その他、不明
- 音声プロファイル検出器(512次元の話者埋め込み)
- 各話者の独特な感情音声パターンを学習
- 各感情に3つ以上の音声サンプルが必要で、それが活性化する
- 一般的なプロファイルとすべての感情固有のプロファイル(Andy、Andy_angry、Andy_happyなど)をチェック
最適な一致が勝ちます: Andy_angryの音声プロファイルが92%の一致率で、emotion2vecの中立が78%の場合、音声検出器が勝ちます。
閾値設定
環境変数:
EMOTION_THRESHOLD=0.6- 感情の一致感度(0.3 - 0.9、値が高いほど厳格)SPEAKER_THRESHOLD=0.30- 音声の一致感度(0.20 - 0.35、値が高いほど厳格)
両方の閾値は、APIを介して話者ごとまたは感情ごとにカスタマイズでき、詳細なコントロールが可能です。
個人化学習
任意のセグメントの感情を修正すると、システムが自動的に学習します。
- emotion2vecの一致用に感情埋め込み(1024次元)を保存します。
- 音声プロファイルの一致用に音声埋め込み(512次元)を保存します。
- 加重平均を使用してマージします(古いサンプルにはより重みがかかります)。
- 一般的な話者プロファイルも更新します。
- 各感情に3つ以上の修正があった後、音声検出器が活性化します。
手動修正は100%の信頼度を持ちます。話者を再識別する必要はありません。
パフォーマンス
- 速度: セグメントあたり約37ms(音声一致に+5ms)
- VRAM: 約2GBのemotion2vec + 約1GBの話者埋め込み(共有)
- 活性化: 各感情に3つ以上の音声サンプルが必要
システム要件
ハードウェア
- GPU: CUDA 12.xをサポートするNVIDIA GPU
- テスト済み: NVIDIA RTX 3090(24GB VRAM) - 優れたパフォーマンス
- VRAM要件(faster-whisperは非常に効率的):
- 話者分離 + 埋め込み: 約2 - 3GBの基本要件
- 感情検出: 約2GB(emotion2vec_plus_large)
- Whisperモデルによる追加: (使用可能なVRAMに基づいて選択)
tiny/base: 約400 - 500MB(感情付きで最低約5GB)small: 約1GB(感情付きで推奨約6GB)medium: 約2GB(感情付きで推奨約7GB)large-v3: 約3 - 4GB(感情付きで推奨約8 - 9GB、デフォルト)
- 動作可能: 消費者向けGPU(GTX 1060 6GB以上、1080、2060、3060、3090、4080、4090など)
- CPUフォールバック: CPUでも動作しますが、大幅に低速です(GPUを強く推奨)
- RAM: 最低8GB、推奨16GB以上
- ストレージ: モデルに約10GB、音声録音用の追加スペース
ソフトウェア
- オペレーティングシステム: Linux(Ubuntuでテスト済み)、macOS(Docker経由)、Windows(WSL2 + Docker経由)
- Python: 3.11または3.12
- CUDA: 12.4(Dockerイメージに含まれる)
- cuDNN: 9.x(自動インストール)
- Docker(オプションだが推奨): 20.10以上、NVIDIA Container Toolkit付き
システム依存関係
- ffmpeg: 音声処理とフォーマット変換
- git: HuggingFaceモデルのダウンロード
- portaudio19-dev: ライブマイク録音(オプション)
アーキテクチャの概要
┌──────────────────────────────────────────────────────────────────┐
│ ユーザー入力 │
│ (音声アップロード / ライブ録音) │
└──────────────────────────┬───────────────────────────────────────┘
│
▼
┌───────────────────────┐
│ 音声フォーマット │
│ 変換 │
│ (必要な場合) │
│ │
│ MP3/M4A → WAV │
│ ライブ: 48kHzチャンク │
└───────────┬───────────┘
│
╔══════════════╧════════════════╗
║ 並列処理 ║ ← 約50%高速化!
║ ThreadPoolExecutor ║ 両方同時に実行
║ (2つのワーカー) ║
╚══════════════╤════════════════╝
│
┌─────────────────┴─────────────────┐
│ │
▼ ▼
┌────────────────────┐ ┌───────────────────────┐
│ 文字起こし │ │ 話者分離 │
│ (faster-whisper) │ │ (pyannote.audio) │
│ │ │ │
│ "何が言われたか" │ │ "誰がいつ話したか" │
│ │ │ │
│ • 音声 → テキスト │ │ • 話者の交代を検出 │
│ • 単語のタイムスタンプ │ │ ターン │
│ • 信頼度 │ │ • ラベルを割り当てる │
│ スコア │ │ (SPEAKER_00, など) │
│ • VADフィルタリング │ │ • 時間境界 │
│ │ │ │
│ ~40-100ms │ │ ~40-100ms │
│ (ライブセグメント) │ │ (ライブセグメント) │
└─────────┬──────────┘ └───────────┬───────────┘
│ │
└──────────────┬───────────────────┘
│
▼
┌───────────────────────┐
│ セグメントアラインメント │
│ │
│ 文字起こしを話者ラベルに │
│ タイムスタンプの重複でマッチ │
└───────────┬───────────┘
│
┌───────────────┴───────────────┐
│ │
▼ ▼
┌────────────────────┐ ┌────────────────────────┐
│ 埋め込み抽出 │ │ 話者マッチング │
│ (pyannote) │ │ (コサイン類似度) │
│ │ │ │
│ • 音声の署名を抽出 │──────→ 既知の話者と比較 │
│ • 512次元のベクトル │ │ │
│ • コンテキストパディング │ │ 閾値: 0.20-0.30 │
│ (0.15s) │ │ │
│ • 0.5秒未満の場合はスキップ │ │ 一致または不明? │
└────────────────────┘ └───────────┬────────────┘
│
┌──────────────┴──────────────┐
│ │
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ 既知の話者 │ │ 未知の話者 │
│ "Alice" │ │ "Unknown_01" │
│ │ │ │
│ • IDを持つ │ │ • まだIDがない │
│ • 信頼度 │ │ • 自動登録 │
│ スコア │ │ • 埋め込みが保存される │
└────────┬────────┘ └────────┬─────────┘
│ │
└──────────┬────────────────┘
│
▼
┌───────────────────────┐
│ 感情検出 │
│ (逐次的) │
│ │
│ "どんな気持ちで話しているか" │
└───────────┬───────────┘
│
┌───────────▼───────────┐
│ ステップ1: 話者マッチング │
│ │
│ • 512次元の音声埋め込みを抽出 │
│ • すべてのプロファイルをチェック: │
│ - Andy (一般的) │
│ - Andy_angry │
│ - Andy_happy │
│ (3つ以上のサンプルの場合) │
│ │
│ 返り値: │
│ • 話者名 │
│ • 一致した感情 │
│ (またはNone) │
└───────────┬───────────┘
│
┌───────────▼───────────┐
│ ステップ2: emotion2vec+ │
│ (常に実行) │
│ │
│ • 1024次元の感情埋め込みを抽出 │
│ • 9つのカテゴリ │
│ │
│ 返り値: │
│ • 感情: "中立" │
│ • 信頼度: 0.78 │
│ │
│ セグメントあたり約30ms │
└───────────┬───────────┘
│
┌───────────▼───────────┐
│ 決定パス: ステップ1で感情プロファイルが一致したか? │
└───────┬───────────────┘
│
┌─────────┴─────────┐
YES │ │ NO
▼ ▼
┌────────────────────┐ ┌──────────────────┐
│ 高速パス │ │ プロファイルをチェック? │
│ 感情を上書き │ │ │
│ │ │ プロファイルがある場合 (3つ以上のサンプル): │
│ ステップ1の結果を使用 │ │ │
│ 感情 = "怒り" │ │ → デュアル検出器比較 │
│ 信頼度 = 0.92 │ │ │
│ │ │ それ以外: │
│ 比較をスキップ │ │ → emotion2vecを使用 │
│ │ │
│ 約0ms (即時) │ │
└────────┬───────────┘ └────────┬─────────┘
│ │
│ ┌────────────▼────────────┐
│ │ 低速パス: │
│ │ デュアル検出器比較 │
│ │ │
│ │ • emotion2vecの一致 │
│ │ (1024次元) │
│ │ • 音声プロファイルの一致 │
│ │ (512次元、3つ以上のサンプル) │
│ │ │
│ │ ルール: │
│ │ 1. 両方が一致 → 平均 │
│ │ 2. 中立 → 信頼する │
│ │ 3. 音声 >85% → 音声 │
│ │ 4. 不一致 → 中立 │
│ │ 5. それ以外 → emotion2vec │
│ │ │
│ │ 追加約5ms │
│ └────────┬────────────────┘
│ │
└───────────────────┘
│
┌──────────────▼─────────────┐
│ 最終感情 │
│ │
│ 検出器の内訳付き: │
│ • emotion2vecの結果 │
│ • 音声プロファイルの結果 │
│ • 最終決定 + 理由 │
└────────────────────────────┘
│
▼
┌───────────────────────┐
│ データベース保存 │
│ │
│ 会話セグメント: │
│ • テキスト │
│ • 話者名 │
│ • 話者ID │
│ • 信頼度 │
│ • 感情カテゴリ │
│ • 感情信頼度 │
│ • 感情修正済み │
│ • 感情誤認識 │
│ • 開始/終了時間 │
│ • 単語レベルのデータ │
└───────────┬───────────┘
│
┌───────────────┴───────────────┐
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────────┐
│ 自動クラスタリング │ │ ユーザーが未知の話者を特定 │
│ │ │ │
│ 類似した未知の話者をグループ化 │ │ "Unknown_01はBob" │
│ 埋め込みの類似度に基づいて │ │ │
│ │ │ → 埋め込みのマージ │
└──────────────────┘ │ → 遡及的な更新 (すべての過去のセグメント) │
│
└──────────────────────┘
│
▼
┌──────────────────────┐
│ ユーザーが感情を修正 │
│ │
│ "実際は怒っていて、中立ではない" │
│ │
│ → 抽出して保存: │
│ • 1024次元の感情埋め込み │
│ • 512次元の音声埋め込み │
│ → 話者感情プロファイルにマージ (加重平均) │
│ → 更新: │
│ • Andy_angry │
│ (感情プロファイル)│
│ • 一般的なAndy │
│ (話者プロファイル)│
│ → 感情を変更する場合: 古いプロファイルも再計算 │
│ → 信頼度 = 100% │
│ (手動確認) │
│ → 3つ以上のサンプル後: │
│ 音声検出器が活性化! │
└──────────────────────┘
要点:
- 並列処理: 文字起こし(Whisper)と話者分離(Pyannote)はThreadPoolExecutorを使用して同時に実行され、約50%の高速化を達成します。
- パフォーマンス(GPU上のセグメントごと):
- 文字起こし + 話者分離: 約40 - 100ms(並列)
- アラインメント + 音声埋め込み抽出: 約20 - 40ms
- 話者マッチング(すべてのプロファイルをチェック、感情固有のものも含む): 約0.5ms
- emotion2vec+抽出(常に実行): 約30ms
- 決定パス:
- 感情プロファイルが一致した場合の高速パス上書き: 約0ms即時
- プロファイルが存在する場合のデュアル検出器比較: 追加約5ms
- emotion2vecのみにフォールバック: 約0ms(すでに抽出済み)
- 音声変換: 処理前に自動的にフォーマットを変換します(MP3→WAV)。ライブ録音は48kHzのチャンクで保存されます。
- 逐次操作: アラインメント → 音声埋め込み抽出(512次元) → 話者マッチング → emotion2vec抽出(1024次元) → 決定(上書きまたはデュアル検出器またはフォールバック)
- 感情検出フロー:
- 話者マッチングですべてのプロファイル(一般的なものとAndy_angryのような感情固有のもの)をチェックします。
- emotion2vecは常に感情を抽出します(すべてのセグメントに対して実行)。
- 話者が感情プロファイルに一致した場合 → emotion2vecを上書きします(高速パス)。
- そうでなく、話者が学習したプロファイルを持っている場合(3つ以上のサンプル) → デュアル検出器比較(5つの決定ルール)。
- それ以外の場合 → emotion2vecの結果のみを使用します。
- デュアル検出器システム: 各感情に1024次元の感情埋め込み(emotion2vec)と512次元の音声埋め込み(話者認識)の両方を保存します。音声プロファイル検出器は3つ以上のサンプルが必要で活性化します。
- 個人化学習: ユーザーの修正により、両方の埋め込みタイプを抽出して保存し、加重平均を使用してマージします。感情を変更すると、古いプロファイルと新しいプロファイルの両方を再計算します。手動修正後の信頼度は100%に設定されます。
- なぜ逐次的なのか: ボトルネック(文字起こし + 話者分離)は並列化されています。ポスト処理(合計約35ms)は十分に高速で、さらなる並列化は複雑さを増すだけで、有意な高速化にはつながりません。
- サンプルレート: ブラウザ(48kHz) → Whisper/Pyannote(自動リサンプル) → Emotion2vec(16kHz) → 保存(ストリーミング用のWAV 48kHz、アップロード用のMP3 192k)
処理パイプライン
- 音声入力
- アップロード: MP3/WAVファイルは自動的に変換され、
data/recordings/に保存されます。 - ライブ: ブラウザのマイク → ストリーミングチャンクが
data/stream_segments/に保存されます。
- 並列処理(逐次処理より高速)
- 話者分離(pyannote): 話者の交代を検出し、匿名ラベル(SPEAKER_00、SPEAKER_01など)付きのセグメントを出力します。
- 文字起こし(Whisper): 音声をテキストに変換し、タイムスタンプを付けます。
- 両方がThreadPoolExecutorを使用して同時に実行されます。
- セグメントアラインメント
- 文字起こしのセグメントをタイムスタンプの重複によって話者ラベルにマッチングします。
- マッチングにはセグメントの中点
(start + end) / 2を使用します。 - 正確な重複がない場合は、最も近いセグメントにフォールバックします。
- 埋め込み抽出
- 各セグメントについて、pyannote埋め込みモデルを使用して512次元の音声署名を抽出します。
- コンテキストパディング(0.15秒)を前後に追加して、背景ノイズに対する頑健性を高めます。
- 最小セグメント時間: 0.5秒
- 話者マッチング
- セグメントの埋め込みを既知の話者の埋め込みと比較します。
- コサイン類似度を計算します(0.0 - 1.0)。
- 類似度が閾値(デフォルト0.30)を超える場合: 既知の話者として識別されます。
- 類似度が閾値以下の場合: "Unknown_XX"としてラベル付けされます。
- 未知の話者の処理
- 埋め込み検証: 複数の未知のセグメントが同じ人物であるかを確認します。
- 類似した未知の話者をグループ化します(同じ閾値)。
- 各一意の音声に一意のUnknown_XX識別子が付けられます。
- 埋め込みは将来の自動登録のために保存されます。
- 自動登録(ユーザーが未知の話者を特定した場合)
- ユーザーが任意のセグメントに話者名を提供します。
- 新しい名前の場合: 自動的に話者プロファイルが作成されます。
- 埋め込みマージ: 同じ話者のすべてのセグメントの埋め込みを平均化します。
- 遡及的な更新: 同じUnknownラベルのすべての過去のセグメントが更新されます。
- 継続的な改善: 各識別によって話者プロファイルが強化されます。
音声活動検出(VAD)
2つの独立したVADシステムが連携して動作します。
- ライブ録音VAD(エネルギーベース)
- RMSエネルギーを計算します:
sqrt(mean(audio^2)) - 閾値: 0.005(設定可能)
- 音声と無音をリアルタイムで検出します。
- UIにライブインジケーターを表示します: "🟢 音声検出"または"⚪ 待機中"
- X秒間の無音(デフォルト0.5秒)後、セグメント処理をトリガーします。
- 文字起こしVAD(Whisperの組み込み)
- Silero VADモデルを使用します。
- 文字起こし前に非音声をフィルタリングします。
- 幻聴("thank you."、"thanks for watching")を減らします。
vad_filter=Trueパラメータで有効になります。
誤認識修正
- 誤認識としてマーク: 埋め込み計算からセグメントを除外します。
- 正しい話者に再割り当て: 両方の話者の埋め込みを更新します。
- 自動再計算: 誤認識されていないすべてのセグメントから埋め込みを平均化します。
- 埋め込みの破損を防止: 話者プロファイルが正確に維持されます。
高度な機能
埋め込みマージ
未知の話者を特定するか、既存の話者を再識別する場合:
- 埋め込みを置き換えることはありません(履歴データを失うため)。
- 常に平均化を使用してマージします:
(既存の埋め込み + 新しい埋め込み) / 2。 - 継続的な改善: 各録音によって話者プロファイルが強化されます。
- 変動性に対応: 異なる音声条件、感情などを考慮して平均化します。
遡及的な識別
任意の話者の名前を変更すると、過去のすべてのセグメントが自動的に更新されます。
# ユーザーが会話5のUnknown_01を"Alice"と識別する
curl -X POST "http://localhost:8000/api/v1/conversations/5/segments/123/identify?speaker_name=Alice&enroll=true"
# システムが自動的に:
# 1. "Alice"の話者プロファイルを作成(新しい場合)
# 2. セグメント123を更新
# 3. speaker_name="Unknown_01"のすべてのセグメントを見つける
# 4. すべてをspeaker_name="Alice"に更新
# 5. すべてのセグメントの埋め込みをマージ
# 6. 更新されたセグメントの数を返す
バックアップと復元
話者プロファイルをエクスポートして復元します。 バックアップ:
- すべての話者とその埋め込みをJSONにエクスポートします。
- 完全な状態回復のためにセグメントの割り当ても含まれます。
backups/backup_YYYYMMDD_HHMMSS.jsonに保存されます。- 音声ファイルは含まれません(話者データのみ)。
復元:
- バックアップから話者データベースを再構築します。
- 埋め込みとセグメントの割り当てを復元します。
- 異なる設定をテストするのに便利です。
- デプロイメント間の移行にも便利です。
グラウンドトゥルースラベリング
認識精度をテストして最適化します。
- セグメントを手動で正しい話者の識別情報でラベル付けします。
- ラベルは別に保存されます(実際のセグメントに影響を与えません)。
- 予測とラベルを比較するテストを実行します。
- 閾値とパディングパラメータを最適化します。
- 現在の最適な設定はこのテストから導き出されています。
データの永続性
ディレクトリ構造
speaker-diarization-app/
├── data/
│ ├── recordings/ # 永続的な音声保存先
│ │ ├── conv_7_full.mp3 # ライブ録音 (MP3)
│ │ ├── uploaded_1_tommy_converted.wav # アップロード
│ │ └── 20251109_160230_meeting.wav # タイムスタンプ付きアップロード
│ │
│ ├── stream_segments/ # ライブ録音セグメント (一時的)
│ │ └── conv_7/
│ │ ├── seg_0001.wav
│ │ ├── seg_0002.wav
│ │ └── ...
│ │
│ └── temp/ # 一時的なセグメント抽出
│ └── segment_123_456.wav
│
├── volumes/
│ ├── speakers.db # SQLiteデータベース
│ └── huggingface_cache/ # ダウンロードされたモデル
│
├── backups/ # バックアップスナップショット (JSON)
│ └── backup_20251109_120000.json
│
├── scripts/ # ユーティリティスクリプト
│ ├── migrate_temp_audio.py # 音声パスを修正
│ ├── diagnose_speakers.py # 問題を診断
│ └── ...
│
└── tests/ # テストファイル
└── test_*.py
Dockerボリューム
すべてのデータはdocker-compose.ymlのボリュームマウントによって永続化されます。
volumes:
- ./volumes:/app/volumes # データベース + モデルキャッシュ
- ./data:/app/data # 音声ファイル
- ./backups:/app/backups # バックアップスナップショット
永続化されるもの:
- ✅ 話者プロファイルと埋め込み
- ✅ すべての会話とセグメント
- ✅ 音声録音
- ✅ ダウンロードされたモデル(約3 - 5GB)
- ✅ バックアップスナップショット
永続化されないもの:
- ❌ コンテナの状態(再構築時に安全)
- ❌ ログ(
docker-compose logs -fで監視)
トラブルシューティング
インストール問題
"HuggingFaceトークンが見つかりません"
.envファイルにHF_TOKENが設定されていることを確認してください。- HuggingFaceでモデルの利用規約に同意してください(前提条件のリンクを参照)。
- トークンに余分なスペースや引用符がないことを確認してください。
"Unable to load libcudnn_cnn.so.9"
- スタンドアロン:
run_local.shが自動的にLD_LIBRARY_PATHを設定します。 - Docker: Dockerfileがpipを介してcuDNNをインストールします。
- 手動:
pip install nvidia-cudnn-cu12==9.* nvidia-cublas-cu12
パーミッションエラー
sudo chown -R $USER:docker data/ volumes/ backups/
DockerでGPUが検出されない
# NVIDIA Container Toolkitがインストールされていることを確認
docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi
# 失敗した場合は、NVIDIA Container Toolkitを再インストール
処理問題
"CUDA out of memory"
- 他のGPUアプリケーションを閉じてください。
- より短い音声セグメントを処理してください。
- 文字起こしを選択的に有効にしてください(話者分離のみの場合は無効にする)。
- フォールバック: CPUで実行します(
CUDA_VISIBLE_DEVICES=""を設定 - 非常に低速)。
話者が認識されない
- 登録用の音声は最低10 - 30秒必要です。
- 背景ノイズが少ないクリアな音声を使用してください。
- 閾値を確認してください: 値が低いほど厳格になります(0.20 - 0.35の範囲を試してみてください、デフォルトは0.30)。
- より高品質の音声で再登録してください。
"Audio file not found"エラー
- 古いアップロード:
python scripts/migrate_temp_audio.pyを実行してください。 - 新しいアップロード:
data/recordings/に自動保存されるはずです。 data/ディレクトリにアクセスできることを確認してください。
Whisperの幻聴("thank you."、"thanks for watching")
- すでにエネルギー閾値とテキストフィルタリングによってフィルタリングされています。
.envでFILTER_HALLUCINATIONS=trueを設定してください。- 文字起こしで
vad_filter=Trueが有効になっていることを確認してください(デフォルト)。
パフォーマンス問題
処理が遅い
- 処理時に
nvidia-smiを確認して、GPUが使用されていることを確認してください。 - Docker:
docker-compose.ymlでruntime: nvidiaが設定されていることを確認してください。 - CUDAが利用可能か確認してください:
python -c "import torch; print(torch.cuda.is_available())" - 初回実行: モデルがダウンロードされます(約3 - 5GB)、以降の実行ははるかに高速です。
メモリ使用量が多い
- 通常: モデルが約4 - 6GBのVRAMをロードします。
- 文字起こしが約2 - 3GB追加します。
- 複数の同時プロセスがメモリ使用量を増やします。
- バッチサイズを減らすか、逐次的に処理してください。
音声問題
UIで音声が再生されない
- 音声ファイルが存在することを確認してください:
ls data/recordings/ - APIエンドポイントが音声を返すことを確認してください:
/api/v1/conversations/segments/{id}/audio - ブラウザのコンソールでエラーを確認してください
代替品













