> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thunderphone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# React 组件

> 在 React 应用中嵌入 ThunderPhone 语音小组件

`ThunderPhoneWidget` 组件会渲染一个具有玻璃拟态风格的通话栏，内置静音、结束通话和显示连接状态的控件。这是在 React 应用中添加语音 AI 的最快方式。

## 安装

```bash theme={null}
npm install @thunderphone/widget
```

## 基本用法

```tsx theme={null}
import { ThunderPhoneWidget } from '@thunderphone/widget'
import '@thunderphone/widget/style.css'

function App() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
    />
  )
}
```

<Warning>
  您**必须**导入该小组件的 CSS 文件，才能正确渲染。否则，小组件将不会应用样式。
</Warning>

***

## 属性

该组件通过 `ThunderPhoneWidgetProps` 接受以下属性：

| 属性               | 类型                                                             | 必填 | 默认值                                 | 说明                                                            |
| ---------------- | -------------------------------------------------------------- | -- | ----------------------------------- | ------------------------------------------------------------- |
| `publishableKey` | `string`                                                       | 是  | --                                  | 开发者设置中的可发布 API 密钥（`pk_live_...`）。系统会根据该密钥的小组件配置自动解析智能体。       |
| `theme`          | `'light' \| 'dark'`                                            | 否  | `'light'`                           | 配色方案。将 `tp--light` 或 `tp--dark` 类应用于小组件根元素。                   |
| `primaryColor`   | `string`                                                       | 否  | `'#000000'`（浅色）/ `'#ffffff'`（深色）    | 用作强调色的 CSS 颜色字符串（通话按钮、波形图、活动指示器）。                             |
| `title`          | `string`                                                       | 否  | `'Voice assistant'`                 | 显示在小组件栏中的文本。                                                  |
| `position`       | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | 否  | `'bottom-right'`                    | 小组件在视口中的固定位置。                                                 |
| `apiBase`        | `string`                                                       | 否  | `'https://api.thunderphone.com/v1'` | API 基础 URL 覆盖值。                                               |
| `language`       | `string`                                                       | 否  | --                                  | 按会话覆盖语言设置——语言代码或区域设置，例如 `en`、`es` 或 `fr-FR`。未设置时，将使用智能体配置的语言。 |
| `voice`          | `string`                                                       | 否  | --                                  | 按会话覆盖语音设置——语音名称，例如 `maria`。未设置时，将使用智能体配置的语音。                  |
| `context`        | `string`                                                       | 否  | --                                  | 按会话传递给智能体的事实性页面或网站上下文（例如，访客正在查看的页面详情）。服务器端会截断至 12,000 个字符。    |
| `onConnect`      | `() => void`                                                   | 否  | --                                  | 语音会话成功连接时调用。                                                  |
| `onDisconnect`   | `() => void`                                                   | 否  | --                                  | 会话结束时调用。                                                      |
| `onError`        | `(error) => void`                                              | 否  | --                                  | 发生错误时调用。`error` 对象包含 `error`（代码）和 `message` 字段。               |
| `className`      | `string`                                                       | 否  | --                                  | 应用于小组件容器的额外 CSS 类名。                                           |
| `ringtone`       | `boolean \| string`                                            | 否  | `false`                             | 连接期间播放铃声。`true` 使用默认铃声，或使用 URL 字符串指定自定义音频。                    |

***

## 示例

### 深色主题与自定义颜色

```tsx theme={null}
import { ThunderPhoneWidget } from '@thunderphone/widget'
import '@thunderphone/widget/style.css'

function App() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      theme="dark"
      primaryColor="#8b5cf6"
      title="Talk to our AI"
    />
  )
}
```

### 自定义位置

```tsx theme={null}
import { ThunderPhoneWidget } from '@thunderphone/widget'
import '@thunderphone/widget/style.css'

function App() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      position="bottom-left"
    />
  )
}
```

### 按会话设置语言、语音和上下文

通话开始时，`language`、`voice` 和 `context` 属性会转发到会话请求（`POST /widget/session`），覆盖该会话中智能体已配置的默认值：

```tsx theme={null}
import { ThunderPhoneWidget } from '@thunderphone/widget'
import '@thunderphone/widget/style.css'

function PricingPageWidget() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      language="es"
      voice="maria"
      context="Page: Pricing. Plans: Starter $29/mo, Pro $99/mo. Annual billing saves 20%."
    />
  )
}
```

使用 `context` 向智能体提供访客当前页面的事实性知识——产品详情、定价或页面专属常见问题。服务端会将其截断为最多 12,000 个字符。

### 使用事件回调

```tsx theme={null}
import { ThunderPhoneWidget } from '@thunderphone/widget'
import '@thunderphone/widget/style.css'

function SupportWidget() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      onConnect={() => {
        console.log('Voice session connected')
        analytics.track('widget_call_started')
      }}
      onDisconnect={() => {
        console.log('Voice session ended')
        analytics.track('widget_call_ended')
      }}
      onError={(error) => {
        console.error(`Widget error: ${error.error} - ${error.message}`)
      }}
    />
  )
}
```

### 使用自定义样式

```tsx theme={null}
import { ThunderPhoneWidget } from '@thunderphone/widget'
import '@thunderphone/widget/style.css'

function BrandedWidget() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      primaryColor="#4a90d9"
      className="my-custom-widget"
    />
  )
}
```

```css theme={null}
.my-custom-widget .tp-button--end {
  background-color: #e74c3c;
}
```

有关所有可用 CSS 类和自定义属性，请参阅[样式指南](/zh/widget/styling)。

### 使用铃声

在建立连接期间播放电话铃声：

```tsx theme={null}
import { ThunderPhoneWidget } from '@thunderphone/widget'
import '@thunderphone/widget/style.css'

function PhoneWidget() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      ringtone={true}
    />
  )
}
```

传入音频文件 URL 以使用自定义铃声：

```tsx theme={null}
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  ringtone="https://example.com/my-ringtone.mp3"
/>
```

当组件处于 `connecting` 状态时，铃声会循环播放；智能体接通后会平滑淡出。

### 使用自定义 API 基础地址

<Tip>
  仅当您使用自行托管或代理 API 端点时，才需要设置 `apiBase`。默认值指向 `https://api.thunderphone.com/v1`。
</Tip>

```tsx theme={null}
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  apiBase="https://your-proxy.example.com/v1"
/>
```

***

## 错误处理

触发 `onError` 回调时，它会接收一个包含两个字段的错误对象：

| 字段        | 类型       | 描述        |
| --------- | -------- | --------- |
| `error`   | `string` | 机器可读的错误代码 |
| `message` | `string` | 人类可读的错误描述 |

常见错误代码包括不允许的域名、未找到智能体以及无效的 API 密钥。

***

## 后续步骤

<CardGroup cols={2}>
  <Card title="无头 Hook" icon="code" href="/zh/widget/headless-hook">
    需要完全掌控 UI？请改用 `useThunderPhone` Hook。
  </Card>

  <Card title="样式设置" icon="palette" href="/zh/widget/styling">
    使用 CSS 自定义属性自定义颜色、尺寸和布局。
  </Card>
</CardGroup>
