> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# 화자 분리

> **Note**
>
> **사용 방법 가이드** ·
> [클라이언트 측](/docs/ko/eleven-api/guides/how-to/speech-to-text/realtime/client-side-streaming) 또는
> [서버 측 스트리밍](/docs/ko/eleven-api/guides/how-to/speech-to-text/realtime/server-side-streaming) 가이드를 완료했다고 가정합니다.

## 개요

화자 분리는 단어에 화자 ID를 할당하여 누가 무엇을 말했는지 구분할 수 있게 합니다. 화자 분리를 활성화하면 부분 트랜스크립트에 임시 화자 라벨이 포함되며, 확정된 각 트랜스크립트 뒤에는 별도의 `diarized_transcript` 이벤트가 이어집니다. 오디오가 더 수신되면 화자 라벨이 변경될 수 있습니다.

## 화자 분리 활성화

`model_id=scribe_v3_live`로 WebSocket 연결을 열 때 불리언 쿼리 파라미터 `diarize=true`를 설정하세요. 화자 분리는 기본적으로 `false`입니다.

다음 서버 측 예제에서는 연결을 열고 이벤트를 수신합니다. Python에서는 `websockets`를, TypeScript에서는 `ws`와 개발 종속성 `@types/ws`를 설치하세요. 서버 환경에 `ELEVENLABS_API_KEY`를 설정하세요. 예제에서는 이를 `xi-api-key` 헤더로 전송합니다. 이 키는 브라우저 코드가 아닌 서버에 보관하세요.

이 예제에서는 오디오를 전송하지 않습니다. [서버 측 스트리밍 가이드](/docs/ko/eleven-api/guides/how-to/speech-to-text/realtime/server-side-streaming)의 오디오 프로듀서와 통합하세요. 이벤트를 수신하는 동안 같은 연결에서 `input_audio_chunk` 메시지를 전송합니다. 예제에서는 `pcm_16000`을 선택하므로 일치하는 오디오를 사용하세요. Python에서는 오디오 전송 작업을 수신 루프와 동시에 실행하고, TypeScript에서는 연결이 열린 후 오디오를 전송하세요.

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

```typescript
import WebSocket from "ws";

const apiKey = process.env.ELEVENLABS_API_KEY;
if (!apiKey) {
  throw new Error("Set ELEVENLABS_API_KEY in your server environment.");
}

const websocket = new WebSocket(
  "wss://api.elevenlabs.io/v1/speech-to-text/realtime" +
    "?model_id=scribe_v3_live&audio_format=pcm_16000&diarize=true",
  { headers: { "xi-api-key": apiKey } }
);

websocket.on("message", (message) => {
  const event = JSON.parse(message.toString());
  console.log(event);
});

websocket.on("error", (error) => {
  console.error(error);
});
```

## 이벤트 처리

### 부분 트랜스크립트

화자 분리를 활성화하면 각 `partial_transcript`에 배치 트랜스크립션과 동일한 단어 형식의 임시 `words`가 포함됩니다. 화자가 식별되면 각 단어의 `speaker_id`는 `speaker_0`, `speaker_1` 등으로 지정되며, 아직 확인되지 않은 경우에는 `null`입니다.

이 단어들은 임시 데이터로 처리하세요. 오디오가 더 수신되면 화자 ID와 타임스탬프가 변경될 수 있습니다. 아직 정렬되지 않은 단어에는 타임스탬프가 없습니다(`start` 및 `end`가 `null`이거나 없음).

### 확정 및 화자 분리 트랜스크립트

화자 분리는 `committed_transcript`를 지연시키지 않습니다. 화자 분리를 활성화하면 이 이벤트에 0부터 시작하는 정수 `segment_index`가 추가됩니다.

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

각 확정 뒤에는 일치하는 `segment_index`, `text`, `words`를 포함하는 별도의 `diarized_transcript` 이벤트가 이어집니다.

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

위 단어에는 텍스트와 화자 라벨만 표시됩니다. 전체 단어 형식은 `speaker_id`와 함께 배치 트랜스크립션과 동일한 `start`, `end`, `type`, `logprob`, `characters` 필드를 사용합니다. 확인되지 않은 화자의 ID는 `null`입니다.

화자 분리 트랜스크립트는 확정 순서대로 전송됩니다. 텍스트나 다음에 수신한 이벤트가 아니라 `segment_index`를 사용하여 확정된 트랜스크립트와 연결하세요. 화자 식별에 실패한 경우에도 각 확정에 대해 항상 `diarized_transcript`가 전송됩니다. 이 경우 확인되지 않은 화자 ID는 `null`입니다.

### 화자 병합

`speakers_merged` 이벤트는 두 화자 ID가 동일인을 가리킨다는 의미입니다.

```json
{
  "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`로 유지됩니다.

```python
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` 이벤트가 이전 라벨을 수정할 수 있습니다. 이러한 병합 이벤트는 화자 분리가 활성화된 경우에만 전송됩니다.