---
title: "React 元件"
description: "在 React 應用程式中嵌入 ThunderPhone 語音小工具"
---

`ThunderPhoneWidget` 元件會呈現具玻璃擬態風格的通話列，內建靜音、結束通話及顯示連線狀態的控制項。這是為 React 應用程式加入語音 AI 的最快方式。

## 安裝

```bash
npm install @thunderphone/widget
```

## 基本用法

```tsx
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
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
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` props 會轉送至工作階段請求（`POST /widget/session`），並覆寫該工作階段中智能體已設定的預設值：

```tsx
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
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
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
.my-custom-widget .tp-button--end {
  background-color: #e74c3c;
}
```

請參閱[樣式指南](/yue/widget/styling)，了解所有可用的 CSS 類別及自訂屬性。

### 使用鈴聲

建立連線期間播放電話鈴聲：

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

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

傳入音訊檔案 URL 以使用自訂鈴聲：

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

當 Widget 處於 `connecting` 狀態時，鈴聲會循環播放；智能體連線後，鈴聲會平順淡出。

### 使用自訂 API 基礎網址

<Tip>
  只有在使用自行託管或代理 API 端點時，才需要設定 `apiBase`。預設值為 `https://api.thunderphone.com/v1`。
</Tip>

```tsx
<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="/yue/widget/headless-hook">
    需要完全掌控 UI？改用 `useThunderPhone` Hook。
  </Card>
  <Card title="樣式設定" icon="palette" href="/yue/widget/styling">
    使用 CSS 自訂屬性自訂顏色、尺寸及版面配置。
  </Card>
</CardGroup>
