ナビゲーションにスキップ

話者ダイアライゼーション

このガイドでは、リアルタイムのスピーチtoテキストAPIを使用して、リアルタイム文字起こしの発言者をラベル付けする方法を説明します。

ハウツーガイド · クライアント側または サーバー側ストリーミングのガイドを完了していることを前提としています。

概要

話者ダイアライゼーションは単語に話者IDを割り当て、誰が何を言ったかを区別できるようにします。ダイアライゼーションを有効にすると、部分的な文字起こしに暫定的な話者ラベルが含まれ、確定した各文字起こしの後に個別のdiarized_transcriptイベントが送信されます。オーディオが追加されると、話者ラベルが変わる場合があります。

ダイアライゼーションの有効化

model_id=scribe_v3_liveでWebSocket接続を開く際に、ブール値のクエリパラメーターdiarize=trueを設定します。ダイアライゼーションのデフォルト値はfalseです。

以下のサーバー側の例では、接続を開いてイベントを受信します。Pythonではwebsocketsを、TypeScriptではwsと開発依存関係の@types/wsをインストールしてください。サーバー環境でELEVENLABS_API_KEYを設定します。例では、このキーをxi-api-keyヘッダーで送信します。ブラウザーコードには含めず、サーバー上で管理してください。

これらの例ではオーディオを送信しません。サーバー側ストリーミングガイドのオーディオ生成処理と統合し、イベントを受信しながら、同じ接続でinput_audio_chunkメッセージを送信してください。例ではpcm_16000を選択しているため、それに一致するオーディオを使用します。Pythonでは、オーディオ送信タスクと受信ループを並行して実行します。TypeScriptでは、接続が開いた後にオーディオを送信します。

import asyncio
import json
import os
from websockets.asyncio.client import connect
async def main():
url = (
"wss://api.elevenlabs.io/v1/speech-to-text/realtime"
"?model_id=scribe_v3_live&audio_format=pcm_16000&diarize=true"
)
headers = {"xi-api-key": os.environ["ELEVENLABS_API_KEY"]}
async with connect(url, additional_headers=headers) as websocket:
async for message in websocket:
event = json.loads(message)
print(event)
if __name__ == "__main__":
asyncio.run(main())

イベントの処理

部分的な文字起こし

ダイアライゼーションを有効にすると、各partial_transcriptにバッチ文字起こしと同じ単語形式の暫定的なwordsが含まれます。各単語のspeaker_idは、話者が識別されるとspeaker_0、speaker_1のように設定され、未解決の間はnullになります。

これらの単語は暫定的なものとして扱ってください。オーディオが追加されると、話者IDとタイムスタンプが変わる場合があります。まだアラインメントされていない単語にはタイムスタンプがありません(startとendがnullまたは存在しません)。

確定済みおよびダイアライズ済みの文字起こし

ダイアライゼーションによってcommitted_transcriptが遅延することはありません。ダイアライゼーションを有効にすると、このイベントには0から始まる整数のsegment_indexが追加されます。

{
"message_type": "committed_transcript",
"segment_index": 0,
"text": "Hello."
}

確定するたびに、一致するsegment_index、text、wordsを含む個別のdiarized_transcriptイベントが続けて送信されます。

{
"message_type": "diarized_transcript",
"segment_index": 0,
"text": "Hello.",
"words": [
{
"text": "Hello.",
"speaker_id": "speaker_0"
}
]
}

上記の単語には、テキストと話者ラベルのみが表示されています。完全な単語形式では、バッチ文字起こしと同じstart、end、type、logprob、charactersフィールドがspeaker_idとともに使用されます。未解決の話者の話者IDはnullです。

ダイアライズ済みの文字起こしは、確定された順に送信されます。テキストや次に受信したイベントではなく、segment_indexを使用して確定済みの文字起こしと対応付けてください。話者を識別できなかった場合でも、確定ごとに必ずdiarized_transcriptが送信されます。その場合、未解決の話者IDはnullです。

話者の統合

speakers_mergedイベントは、2つの話者IDが同じ人物を指していることを意味します。

{
"message_type": "speakers_merged",
"from_speaker_id": "speaker_1",
"to_speaker_id": "speaker_0"
}

部分的な文字起こしとダイアライズ済みの文字起こしの両方で、以前に使用されたすべてのfrom_speaker_idをto_speaker_idに置き換えます。話者IDが再利用されることはありません。統合は連鎖する場合があるため、受信順に適用してください。たとえば、speaker_2がspeaker_1に統合され、その後speaker_1がspeaker_0に統合された場合、両方のIDに属する以前の単語はすべてspeaker_0とラベル付けする必要があります。

たとえば、受信したイベントごとにこのハンドラーを呼び出します。ここでは、transcript_historyに、過去の部分的なスナップショットを含め、アプリケーションが保持するすべての部分的な文字起こしとダイアライズ済みの文字起こしを保存します。統合のたびに、保存されているすべての単語をその場で更新するため、連鎖した統合でも以前に統合された単語が更新されます。この更新済みのストレージから話者ラベルを表示してください。nullラベルはnullのままです。

transcript_history = []
def handle_event(event):
if event["message_type"] in ("partial_transcript", "diarized_transcript"):
transcript_history.append(event)
elif event["message_type"] == "speakers_merged":
for transcript in transcript_history:
for word in transcript.get("words") or []:
if word.get("speaker_id") == event["from_speaker_id"]:
word["speaker_id"] = event["to_speaker_id"]

制限事項

  • ダイアライゼーションをサポートしているのはscribe_v3_liveのみです。他のモデルでは、"The 'diarize' parameter is only supported by scribe_v3_live."というメッセージを含むinvalid_requestエラーが返され、接続が閉じられます。
  • ダイアライゼーションをfilter_background_audioと組み合わせることはできません。この組み合わせでは、"cannot be combined with filter_background_audio"というメッセージを含むinvalid_requestエラーが返され、接続が閉じられます。
  • 話者ラベルが未解決(null)のままになる場合があり、後から届くspeakers_mergedイベントによって以前のラベルが変更されることもあります。これらの統合イベントは、ダイアライゼーションが有効な場合にのみ送信されます。