> 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/zh/eleven-api/guides/how-to/speech-to-text/realtime/client-side-streaming)或
> [服务端 流式处理](/docs/zh/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/zh/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."
}
```

每次提交后都会跟随一个单独的 `diarized_transcript` 事件，其中包含对应的 `segment_index`、`text` 和 `words`：

```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`。其他模型会返回 `invalid_request` 错误，消息为 `"The 'diarize' parameter is only supported by scribe_v3_live."`，随后关闭连接。
* 说话人分离不能与 `filter_background_audio` 结合使用。这种组合会返回 `invalid_request` 错误，其消息包含 `"cannot be combined with filter_background_audio"`，随后关闭连接。
* 说话人标签可能始终无法确定（`null`），后续的 `speakers_merged` 事件也可能修订先前的标签。仅在启用说话人分离时才会发送这些合并事件。