> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/websocket-transport-layer.md).

# 使用 WebSocket 传输层

通过 WebSocket 而不是 WebRTC 连接 Convai 角色，注册传输，并在 React 或纯 TypeScript 中听到该角色的声音。

将 Convai Web SDK 会话从基于 LiveKit 构建的默认 WebRTC 传输切换为基于 Pipecat 构建的 WebSocket 传输。当你的部署无法使用 WebRTC，或者你正在测试 WebSocket 路径时，请使用此页面。

{% hint style="info" %}
在托管的 Convai 上请使用 1.9.2 或更高版本。托管的 Convai 的 `/connect` 返回一个 `ws://` 此传输的 URL，但端点只接受 `wss://`。1.9.1 及更早版本连接失败，浏览器报告关闭代码 `1006`。1.9.2 会升级 `ws://` 为 `wss://` 当 `/connect` URL 或页面使用 https 时；本地 http 设置会保持 `ws://`.
{% endhint %}

### 如何选择传输方式

`ConvaiConfig.transport` 接受 `"livekit"` （默认）或 `"websocket"`。两种传输方式都以相同的 `POST /connect` 请求开始向 Convai 连接。使用 `"websocket"`时，SDK 会从 `room_url` 字段读取 WebSocket URL，并通过已注册的 WebSocket 会话打开它。

WebSocket 会话并不是内置于 `ConvaiClient`中。只有 `@convai/web-sdk/vanilla/websocket` 子路径会导入 Pipecat 包，并且导入它会作为副作用将会话注册到 `ConvaiClient` 中。未导入该子路径的应用不会加载 Pipecat 代码。

### 安装 Pipecat 包

WebSocket 会话依赖两个 Pipecat 包。它们是 SDK 的可选 peer 依赖，因此你的包管理器不会为你安装它们。请将它们与 SDK 一起添加：

```bash
npm install @convai/web-sdk @pipecat-ai/client-js @pipecat-ai/websocket-transport
```

没有它们，导入 `@convai/web-sdk/vanilla/websocket` 会失败，并出现 `无法解析 "@pipecat-ai/client-js"`.

### 注册传输并连接

导入 `@convai/web-sdk/vanilla/websocket` 一次，在 `connect()` 运行之前，并设置 `transport: 'websocket'`。React 应用程序导入相同的子路径；该包没有专门针对 React 的 WebSocket 入口点。

{% tabs %}
{% tab title="React" %}
{% code title="src/App.tsx" %}

```tsx
import '@convai/web-sdk/vanilla/websocket';
import { useConvaiClient } from '@convai/web-sdk/react';
import { ConvaiWidget } from '@convai/web-widget/react';

export default function App() {
  const client = useConvaiClient({
    apiKey: 'YOUR_API_KEY',
    characterId: 'YOUR_CHARACTER_ID',
    transport: 'websocket',
  });

  return <ConvaiWidget convaiClient={client} />;
}
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="src/main.ts" %}

```typescript
import '@convai/web-sdk/vanilla/websocket';
import { ConvaiClient } from '@convai/web-sdk/vanilla';

const client = new ConvaiClient({
  apiKey: 'YOUR_API_KEY',
  characterId: 'YOUR_CHARACTER_ID',
  transport: 'websocket',
});

await client.connect();
```

{% endcode %}
{% endtab %}
{% endtabs %}

### 播放角色的声音

该传输会播放语音；无需任何接线。Pipecat 的 WebSocket 传输会通过其自己的 Web Audio 播放器将角色的音频直接播放到扬声器，无论在 React 还是纯 TypeScript 中都是如此。上面的示例是完整的：它们不需要 `AudioRenderer` 且没有 `botAudioTrack` 监听器。

这里使用的 `botAudioTrack` 事件在此传输上不会触发。Pipecat 传输只暴露本地麦克风轨道，因此没有角色轨道可供附加。任何 `botAudioTrack` 监听器或 `AudioRenderer` 你从旧代码中保留的都无害；它永远不会收到轨道。

要使角色静音，请调用 `setCharacterMuted(true)`。在 WebSocket 传输上这需要 1.9.2 或更高版本，而且静音期间说出的话会被丢弃，而不是排队。参见 [将角色的声音静音](/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/mute-the-characters-voice.md).

### 麦克风行为

不同传输方式下麦克风的默认值不同：

| Transport     | 在之后的麦克风 `connect()`                                                                  |
| ------------- | ------------------------------------------------------------------------------------ |
| `"livekit"`   | 关闭，除非 `startWithAudioOn` 是 `true`.                                                   |
| `"websocket"` | 开启，因为 Pipecat 会话在 `connect()`期间初始化音频流。SDK 在连接后立即将其静音，当 `startWithAudioOn` 是 `false`. |

在 WebSocket 传输上， `connect()` 始终会请求麦克风权限——即使使用 `startWithAudioOn: false` ——并且在用户对浏览器提示做出回应之前不会解析。Pipecat 会在初始化时打开录音器，因此没有提示就不会有 WebSocket 会话。请在连接前通过用户手势请求访问权限。如果完全不需要麦克风的文本，请使用 SSE 传输。

将 `startWithAudioOn` 仅在页面可能在连接后立即开始监听时，才在 WebSocket 传输上保持未设置。通过 `audioControls` 在此传输上静音会禁用本地音频轨道，因此 Convai 收到的是静音。

### 与 LiveKit 传输的差异

| 行为             | `"livekit"`                                        | `"websocket"`                                                                            |
| -------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `uploadFile()` | 受支持                                                | 不受支持。它需要一个 LiveKit 房间 `[ConvaiClient] uploadFile：未连接到 LiveKit 房间` 。                      |
| 就绪信号超时         | `error` 触发 `在 45000 毫秒内未收到 bot-ready` 如果角色从未发出就绪信号 | 没有超时；WebSocket 会话会自行报告就绪。                                                                |
| 机器人音频          | 通过房间播放，由 `AudioRenderer` 或 `ConvaiWidget`          | 由 Pipecat 传输自身播放； `botAudioTrack` 不会触发                                                   |
| 到 `botReady`   | 在我们的测试中约为 4 到 7 秒                                  | 在我们的测试中约为 17 到 21 秒                                                                      |
| 视觉帧            | 发布到房间的视频轨道                                         | 仅在以下情况下通过 WebSocket 发送： `enableVideo` 是 `true` 并且 `visionInputConfig.enabled` 不在 `false` |
| `client.room`  | 已连接的 LiveKit 房间                                    | 存在但从未连接                                                                                  |

### 故障排查

#### 连接失败，因为传输未注册

**症状：** `connect()` 以此错误拒绝：

```
[ConvaiClient] 未注册 WebSocket 传输。请在调用 connect() 之前添加 `import '@convai/web-sdk/vanilla/websocket'`。
```

**原因：** 配置设置了 `transport: 'websocket'`，但没有模块导入 `@convai/web-sdk/vanilla/websocket`.

**修复：** 将副作用导入添加到一个会在 `connect()` 运行之前加载的模块中。

**验证：** `connect()` 解析成功并 `botReady` 触发时。

#### 没有 WebSocket URL，连接失败

**症状：** `connect()` 拒绝并返回 `从 /connect 端点返回的 WebSocket URL 不存在（预期为 room_url）`.

**原因：** Convai 返回了一个 `/connect` 没有 `room_url`.

**修复：** 检查 `url` 选项是否指向支持 WebSocket 传输的 Convai 实时端点，或者移除 `url` 以使用默认值。

**验证：** `connect()` 解析成功。

#### 连接在连接过程中关闭

**症状：** `connect()` 拒绝并返回 `connect 完成前 WebSocket 已断开连接`.

**原因：** WebSocket 在传输报告已连接之前就已关闭。

**修复：** 重试连接，并检查阻止到 Convai 的 WebSocket 流量的网络规则。

**验证：** `connect()` 解析成功。

#### 在托管的 Convai 上，连接以代码 1006 关闭

**症状：** WebSocket 在连接过程中关闭，浏览器报告关闭代码 `1006`.

**原因：** 1.9.1 或更早版本打开了 `ws://` 托管的 Convai 返回的 URL，并且该端点只接受 `wss://`.

**修复：** 升级 `@convai/web-sdk` 到 1.9.2 或更高版本。

**验证：** `connect()` 解析成功并 `botReady` 触发时。

### 后续步骤

{% content-ref url="/pages/1ef8009eea712d4c41fd7a2a07e473a277395698" %}
[处理错误和断开连接](/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/error-handling.md)
{% endcontent-ref %}

{% content-ref url="/pages/8c6e3631e7e7da5b3c9acf5a0019d7737dc79e19" %}
[Web SDK 事件参考](/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/event-reference.md)
{% endcontent-ref %}

{% content-ref url="/pages/dff296725774f9173a7391e28344f5f94cf35b60" %}
[配置和类型参考](/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/vanilla-typescript/best-practices-and-type-definitions.md)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/websocket-transport-layer.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
