Przejdź do nawigacji

Diarizacja mówców

Ten przewodnik pokazuje, jak oznaczać osoby mówiące w transkrypcjach w czasie rzeczywistym za pomocą API Realtime Speech to Text.

Przewodnik krok po kroku · Zakłada, że ukończyłeś(-aś) przewodnik o strumieniowaniu po stronie klienta lub strumieniowaniu po stronie serwera.

Omówienie

Diarizacja mówców przypisuje identyfikatory mówców do słów, dzięki czemu możesz rozróżnić, kto co powiedział. Gdy diarizacja jest włączona, częściowe transkrypcje zawierają robocze etykiety mówców, a po każdej zatwierdzonej transkrypcji wysyłane jest osobne zdarzenie diarized_transcript. Etykiety mówców mogą się zmieniać w miarę napływania kolejnych nagrań audio.

Włączanie diarizacji

Podczas otwierania połączenia WebSocket z model_id=scribe_v3_live ustaw parametr zapytania logicznego diarize=true. Domyślnie diarizacja ma wartość false.

Poniższe przykłady po stronie serwera otwierają połączenie i odbierają zdarzenia. W Pythonie zainstaluj websockets, a w TypeScript ws oraz zależność deweloperską @types/ws. Ustaw ELEVENLABS_API_KEY w środowisku serwera; przykłady wysyłają go w nagłówku xi-api-key. Przechowuj ten klucz na serwerze, a nie w kodzie przeglądarki.

Te przykłady nie wysyłają audio. Połącz je ze źródłem audio, korzystając z przewodnika o strumieniowaniu po stronie serwera: wysyłaj wiadomości input_audio_chunk przez to samo połączenie podczas odbierania zdarzeń. Przykłady wybierają pcm_16000, więc użyj pasującego audio. W Pythonie uruchom zadanie wysyłające audio równolegle z pętlą odbioru; w TypeScript wyślij audio po otwarciu połączenia.

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())

Obsługa zdarzeń

Częściowe transkrypcje

Gdy diarizacja jest włączona, każda partial_transcript zawiera robocze words w tym samym formacie słów co transkrypcja wsadowa. Po zidentyfikowaniu mówcy speaker_id każdego słowa ma wartość speaker_0, speaker_1 itd., a podczas ustalania mówcy — null.

Traktuj te słowa jako wstępne: identyfikatory mówców i znaczniki czasu mogą się zmieniać wraz z kolejnym audio. Słowa, które nie zostały jeszcze wyrównane, nie mają znaczników czasu (start i end mają wartość null lub nie występują).

Zatwierdzone i udiaryzowane transkrypcje

Diarizacja nie opóźnia committed_transcript. Gdy diarizacja jest włączona, to zdarzenie dodaje indeks całkowity od zera segment_index:

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

Po każdym zatwierdzeniu wysyłane jest osobne zdarzenie diarized_transcript z pasującymi wartościami segment_index, text i words:

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

Powyższe słowo pokazuje tylko tekst i etykietę mówcy. Pełny format słowa używa tych samych pól start, end, type, logprob i characters co transkrypcja wsadowa, wraz z speaker_id. Nierozpoznany mówca ma identyfikator mówcy null.

Udiaryzowane transkrypcje są wysyłane w kolejności zatwierdzania. Łącz je z zatwierdzonymi transkrypcjami za pomocą segment_index, a nie tekstu ani kolejnego odebranego zdarzenia. Dla każdego zatwierdzenia zawsze wysyłane jest diarized_transcript, nawet jeśli identyfikacja mówcy się nie powiedzie; w takim przypadku nierozpoznane identyfikatory mówców mają wartość null.

Łączenie mówców

Zdarzenie speakers_merged oznacza, że dwa identyfikatory mówców odnoszą się do tej samej osoby:

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

Zastąp każde wcześniejsze użycie from_speaker_id przez to_speaker_id zarówno w częściowych, jak i udiaryzowanych transkrypcjach. Identyfikatory mówców nigdy nie są używane ponownie. Łączenia mogą następować łańcuchowo, więc stosuj je w kolejności odbioru: jeśli speaker_2 zostanie połączony z speaker_1, a potem speaker_1 z speaker_0, wszystkie wcześniejsze słowa z obu identyfikatorów muszą ostatecznie mieć etykietę speaker_0.

Na przykład wywołuj ten handler dla każdego odebranego zdarzenia. Tutaj transcript_history przechowuje każdą częściową i udiaryzowaną transkrypcję zachowaną przez aplikację, w tym wcześniejsze częściowe wersje. Każde połączenie aktualizuje wszystkie zapisane słowa na miejscu, więc łańcuchowe połączenia aktualizują też wcześniej połączone słowa. Wyświetlaj etykiety mówców z tego zaktualizowanego magazynu; etykiety null pozostają 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"]

Ograniczenia

  • Diarizacja jest obsługiwana tylko przez scribe_v3_live. Inne modele zwracają błąd invalid_request z komunikatem "The 'diarize' parameter is only supported by scribe_v3_live.", a następnie zamykają połączenie.
  • Diarizacji nie można łączyć z filter_background_audio. Ta kombinacja zwraca błąd invalid_request, którego komunikat zawiera "cannot be combined with filter_background_audio", a następnie zamyka połączenie.
  • Etykiety mówców mogą pozostać nierozpoznane (null), a późniejsze zdarzenia speakers_merged mogą zmienić wcześniejsze etykiety. Te zdarzenia łączenia są wysyłane tylko wtedy, gdy diarizacja jest włączona.