---
title: "Компонент React"
description: "Встройте голосовой виджет ThunderPhone в приложение React"
---

Компонент `ThunderPhoneWidget` отображает стекломорфную панель звонка со встроенными элементами управления для отключения микрофона, завершения звонка и отображения статуса подключения. Это самый быстрый способ добавить голосовой ИИ в React-приложение.

## Установка

```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'` | Переопределение базового URL API. |
| `language` | `string` | Нет | -- | Переопределение языка для сеанса — код языка или локаль, например `en`, `es` или `fr-FR`. Если не задано, используется настроенный язык агента. Требует `language` в разделе [переопределения браузера](/ru/guides/embed-web-widget) ключа. |
| `voice` | `string` | Нет | -- | Переопределение голоса для сеанса — имя голоса, например `maria`. Если не задано, используется настроенный голос агента. Требует `voice` в разделе [переопределения браузера](/ru/guides/embed-web-widget) ключа. |
| `context` | `string` | Нет | -- | Фактический контекст страницы или сайта для сеанса, передаваемый агенту (например, сведения о странице, которую просматривает посетитель). На стороне сервера сокращается до 12 000 символов. Требует `context` в разделе [переопределения браузера](/ru/guides/embed-web-widget) ключа. |
| `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` передаются в запрос сеанса (`POST /widget/session`) при начале звонка, переопределяя настроенные по умолчанию параметры агента для этого сеанса. Включите каждое используемое свойство в разделе **Переопределения браузера** для виджета в панели управления (или в `allowed_overrides` ключа). Новые виджеты не принимают ни одного переопределения, а запрос сеанса с отключённым переопределением завершается ошибкой `400 override_not_allowed`; см. [Переопределения браузера](/ru/guides/embed-web-widget).

```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;
}
```

Все доступные CSS-классы и пользовательские свойства описаны в [руководстве по стилям](/ru/widget/styling).

### С рингтоном

Воспроизводите звук телефонного звонка во время установки соединения:

```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"
/>
```

Рингтон циклически воспроизводится, пока виджет находится в состоянии `connecting`, и плавно затихает, когда агент подключается.

### С пользовательским базовым URL API

<Tip>
  Указывать `apiBase` нужно только при использовании самостоятельного хостинга или прокси-конечной точки API. По умолчанию используется `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="Headless-хук" icon="code" href="/ru/widget/headless-hook">
    Нужен полный контроль над интерфейсом? Используйте хук `useThunderPhone`.
  </Card>
  <Card title="Стилизация" icon="palette" href="/ru/widget/styling">
    Настройте цвета, размеры и макет с помощью пользовательских свойств CSS.
  </Card>
</CardGroup>
