> 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/shi-jian-can-kao.md).

# 事件参考

```ts
const unsub = client.on('botReady', () => {
  console.log('机器人已准备就绪');
});

// 之后
unsub();
// 或者
client.off('botReady', handler);
```

***

### 连接事件

#### `connect`

当 WebRTC/WebSocket 传输连接时触发。机器人可能还没有准备好 —— 发送消息前请等待 `botReady` 。

```ts
client.on('connect', () => {
  console.log('传输已连接');
});
```

#### `botReady`

当角色确认已准备好接收消息时触发。这是开始交互的正确信号。

```ts
client.on('botReady', () => {
  client.sendUserTextMessage('你好！');
});
```

#### `disconnect`

会话结束时触发。接收一个 `DisconnectReason` 代码。

```ts
client.on('disconnect', (reason) => {
  // reason: number（参见 DisconnectReason）
  // 1 = CLIENT_INITIATED（主动发起），其他情况可能需要重新连接
  if (reason !== 1) {
    client.reconnect();
  }
});
```

#### `stateChange`

每当 `ConvaiClientState` 的任何部分发生变化时触发。用于 UI 更新。

```ts
client.on('stateChange', (state) => {
  // state.isConnected, state.isConnecting, state.isListening,
  // state.isThinking, state.isSpeaking, state.agentState,
  // state.emotion, state.endUserId, state.metrics, state.disconnectReason
  updateUI(state);
});
```

#### `error`

在连接错误或 bot-ready 超时时触发。

```ts
client.on('error', (error: Error) => {
  console.error(error.message);
});
```

***

### 对话事件

#### `conversationStart`

当新的对话轮次开始时触发——无论是用户发送文本消息还是开始说话。

```ts
client.on('conversationStart', ({ sessionId, userMessage, timestamp }) => {
  // sessionId：递增的轮次计数器
  // userMessage：发送的文本，或语音轮次中的 "[voice]"
  // timestamp：Date.now() 的值
  console.log(`轮次 ${sessionId} 已开始`);
});
```

#### `turnEnd`

当机器人完成某轮发言时触发。

```ts
client.on('turnEnd', ({ sessionId, duration, timestamp }) => {
  // duration：机器人发言的秒数
  console.log(`轮次 ${sessionId} 持续了 ${duration}秒`);
});
```

#### `message`

为每个新的 `ChatMessage` 添加到对话中时触发。完整历史也可在 `client.chatMessages`.

```ts
client.on('message', (msg) => {
  // msg.type, msg.content, msg.id, msg.timestamp, msg.isStreaming
  if (msg.type === 'bot-output') {
    display(msg.content);
  }
});
```

#### `messagesChange`

每当消息数组发生变化时触发（包括流式传输中的消息更新）。

```ts
client.on('messagesChange', (messages) => {
  renderHistory(messages);
});
```

#### `userTranscriptionChange`

当用户说话时反复触发，提供实时语音转文本。

```ts
client.on('userTranscriptionChange', (text) => {
  showLiveTranscript(text);
});
```

***

### 发言事件

#### `speakingChange`

当机器人开始或停止说话时触发。

```ts
client.on('speakingChange', (isSpeaking) => {
  if (isSpeaking) {
    startLipsyncAnimation();
  } else {
    stopLipsyncAnimation();
  }
});
```

#### `botOutput`

为机器人输出的每个聚合块触发。包含已说出和未说出的文本。

```ts
client.on('botOutput', ({ text, spoken, aggregatedBy }) => {
  // spoken：当 TTS 引擎会将此文本朗读出来时为 true
  // aggregatedBy："sentence" 或 "word"，表示块粒度
  if (spoken) {
    addToSubtitles(text);
  }
});
```

#### `botTtsStarted`

当 TTS 引擎开始生成音频时触发。

```ts
client.on('botTtsStarted', () => {
  showSpeakingIndicator();
});
```

#### `botTtsStopped`

当 TTS 引擎完成时触发。

```ts
client.on('botTtsStopped', () => {
  hideSpeakingIndicator();
});
```

#### `botTtsText`

随着机器人说话逐词触发，与 TTS 音频同步。

```ts
client.on('botTtsText', ({ text }) => {
  highlightWord(text); // 卡拉 OK 式逐词高亮
});
```

***

### 麦克风事件

#### `userMuteStarted`

当服务器静音用户麦克风时触发（例如，机器人开始说话以防止回声时）。

```ts
client.on('userMuteStarted', () => {
  showMicMutedIndicator();
});
```

#### `userMuteStopped`

当服务器取消静音用户麦克风时触发。

```ts
client.on('userMuteStopped', () => {
  hideMicMutedIndicator();
});
```

***

### Blendshape / lipsync 事件

这些需要 `enableLipsync: true` 在配置中。

#### `blendshapes`

为每个传入的 blendshape 块触发（默认 10 帧）。请使用 `client.blendshapeQueue` 而不是直接处理原始块。

```ts
client.on('blendshapes', (data) => {
  // 低级：队列处理前的原始块数据
});
```

#### `blendshapeStatsReceived`

当服务器发送轮次结束的 blendshape 统计信息时触发。表示此轮不会再有更多帧。

```ts
client.on('blendshapeStatsReceived', (stats) => {
  // stats.total_blendshapes, stats.total_audio_duration_ms
});
```

***

### 动作事件

需要 `actionConfig` 在配置中。

#### `actionResponse`

每个机器人轮次结束后触发，包含机器人决定执行的动作。

```ts
client.on('actionResponse', ({ actions }) => {
  for (const { name, target } of actions) {
    executeAction(name, target);
  }
});
```

完整指南请参见 Actions。

***

### 服务器响应事件

#### `serverResponse`

作为你发送到服务器的每条消息的确认而触发。

```ts
client.on('serverResponse', (response) => {
  // response.event_type：你发送的消息类型
  // response.status："success" | "error" | "processing" | "pending"
  // response.message：人类可读的结果
  // response.extras：事件特定数据（例如，context-update 的 token 计数）
  if (response.status === 'error') {
    console.error(`服务器在 ${response.event_type} 上出错：`, response.message);
  }
});
```

#### `interactionCreated`

在会话生命周期的早期触发——在 `botReady` ——当服务器分配唯一的 interaction ID 时触发。这是第一条同时携带 `interactionId` 是位于 `characterSessionId`的消息，因此是捕获用于分析、日志记录或会话恢复标识符的合适位置。

```ts
client.on('interactionCreated', ({ interactionId, characterSessionId }) => {
  console.log('交互 ID：', interactionId);       // 例如 "int_abc123def456"
  console.log('角色会话：', characterSessionId); // 例如 "cs_xyz789"

  // 用于分析 / 日志记录的存储
  analytics.track('conversation_started', {
    interactionId,
    characterSessionId,
    timestamp: Date.now(),
  });
});
```

| 字段                   | 类型       | 说明                                            |
| -------------------- | -------- | --------------------------------------------- |
| `interactionId`      | `string` | 此交互的唯一标识符。用于分析或日志关联。                          |
| `characterSessionId` | `string` | 角色会话标识符。与 `client.characterSessionId` 在连接后相同。 |

`interactionCreated` 每次 `connect()` 调用时触发一次。如果你重新连接，会发放新的 `interactionId` 。

***

### 会话事件

#### `idleWarning`

在服务器断开空闲会话之前触发。

```ts
client.on('idleWarning', ({ remainingSeconds }) => {
  if (remainingSeconds !== null) {
    showWarning(`会话将在 ${remainingSeconds}秒后关闭`);
  }
  // 在任何用户活动时重置计时器
  client.resetIdleTimer();
});
```

#### `llmNoResponse`

当 LLM 明确选择不响应时触发（例如，输入不需要回复时）。

```ts
client.on('llmNoResponse', () => {
  // 这一轮不会收到响应——请相应更新 UI
  hideThinkingIndicator();
});
```

***

#### `metrics`

每轮结束后携带性能数据触发。

```ts
client.on('metrics', (data) => {
  // 来自服务器的原始指标（延迟、token 数等）
  console.log('轮次指标：', data);
});
```

***

### 音频轨道（WebSocket 传输）

#### `botAudioTrack`

当机器人有新的音频轨道可用时触发（仅 WebSocket 传输）。附加到一个 `<audio>` 元素以播放。

```ts
client.on('botAudioTrack', (track: MediaStreamTrack) => {
  const audio = document.querySelector<HTMLAudioElement>('#bot-audio')!;
  audio.srcObject = new MediaStream([track]);
});
```

***

### 事件速查

| 事件                        | 负载                                      | 当             |
| ------------------------- | --------------------------------------- | ------------- |
| `connect`                 | —                                       | 传输已连接         |
| `botReady`                | —                                       | 机器人已确认就绪      |
| `disconnect`              | `DisconnectReason`                      | 会话已结束         |
| `stateChange`             | `ConvaiClientState`                     | 任何状态变更        |
| `error`                   | `错误`                                    | 连接或超时错误       |
| `conversationStart`       | `{ sessionId, userMessage, timestamp }` | 新轮次开始         |
| `turnEnd`                 | `{ sessionId, duration, timestamp }`    | 机器人发言结束       |
| `message`                 | `ChatMessage`                           | 新消息           |
| `messagesChange`          | `ChatMessage[]`                         | 历史已更新         |
| `userTranscriptionChange` | `string`                                | 实时 STT 更新     |
| `speakingChange`          | `布尔值`                                   | 机器人发言状态       |
| `botOutput`               | `{ text, spoken, aggregatedBy }`        | 聚合后的机器人块      |
| `botTtsStarted`           | —                                       | TTS 开始        |
| `botTtsStopped`           | —                                       | TTS 结束        |
| `botTtsText`              | `{ text }`                              | 逐词 TTS        |
| `userMuteStarted`         | —                                       | 服务器已静音用户麦克风   |
| `userMuteStopped`         | —                                       | 服务器已取消静音用户麦克风 |
| `blendshapes`             | 原始数据                                    | Blendshape 块  |
| `blendshapeStatsReceived` | 统计信息                                    | 轮次结束统计        |
| `actionResponse`          | `{ actions }`                           | 机器人动作决策       |
| `serverResponse`          | `ServerResponse`                        | 服务器确认         |
| `interactionCreated`      | `{ interactionId, characterSessionId }` | 已分配会话 ID      |
| `idleWarning`             | `{ remainingSeconds }`                  | 空闲超时警告        |
| `llmNoResponse`           | —                                       | LLM 选择不响应     |
| `metrics`                 | 数据                                      | 轮次性能数据        |
| `botAudioTrack`           | `MediaStreamTrack`                      | 新的音频轨道（WS 传输） |


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/shi-jian-can-kao.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
