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

# React

## 설치

프로젝트에 패키지를 설치하세요.

```shell theme={null}
npm install @vox-ai/react
# or
yarn add @vox-ai/react
# or
pnpm add @vox-ai/react
```

## 사용법

### useConversation

vox.ai 에이전트 연결과 오디오 상태를 관리하는 React 훅입니다.

#### 세션 초기화

`useConversation`으로 Conversation 인스턴스를 만듭니다.

```tsx theme={null}
import { useConversation } from "@vox-ai/react";

const conversation = useConversation();
```

음성 세션에는 마이크 권한이 필요합니다. 세션 시작 전에 UI에서 안내하고 요청해 주세요.

```js theme={null}
// 마이크 권한이 필요한 이유를 UI에서 안내한 후 호출
await navigator.mediaDevices.getUserMedia({ audio: true });
```

#### 옵션

훅 초기화 시 콜백과 옵션을 넘길 수 있습니다.

```tsx theme={null}
const conversation = useConversation({
  /* options */
});
```

옵션:

* **textOnly** — Text Only 모드 기본값. [아래](#text-only-모드)를 참고하세요.

#### 콜백

* **onConnect** — 세션이 연결되면 불립니다.
* **onDisconnect** — 연결이 끊기면 불립니다.
* **onMessage** — 메시지가 들어올 때 불립니다. 사용자 음성의 텍스트 변환이나 에이전트 응답이 여기로 옵니다.
* **onError** — 에러 발생 시 불립니다.
* **onStatusChange** — 연결 상태가 바뀔 때 불립니다.
* **onAgentStateChange** — 에이전트 상태가 `"initializing"`, `"idle"`, `"listening"`, `"thinking"`, `"speaking"` 중 하나로 바뀔 때 불립니다.

```tsx theme={null}
const conversation = useConversation({
  onConnect: () => console.log("Connected"),
  onDisconnect: () => console.log("Disconnected"),
  onMessage: (message) => console.log(`${message.source}: ${message.text}`),
  onError: (error) => console.error("Error:", error),
  onStatusChange: (status) => console.log("Status:", status),
  onAgentStateChange: (agentState) => console.log("Agent state:", agentState),
});
```

#### 메서드

##### startSession

세션을 시작합니다. Agent ID는 [vox.ai 대시보드](https://www.tryvox.co/dashboard/)에서 확인하세요.

세션 고유 ID를 resolve하는 Promise를 돌려줍니다.

```tsx theme={null}
const conversation = useConversation();

const conversationId = await conversation.startSession({
  agentId: "<your-agent-id>",
  apiKey: "<your-api-key>",
});
```

`startSession` 옵션:

| 옵션                 | 타입                                            | 필수 | 설명                                                         |
| ------------------ | --------------------------------------------- | -- | ---------------------------------------------------------- |
| `agentId`          | `string`                                      | O  | Agent ID                                                   |
| `apiKey`           | `string`                                      | O  | API Key                                                    |
| `agentVersion`     | `string`                                      |    | 에이전트 버전. 기본값 `"current"`                                   |
| `textOnly`         | `boolean`                                     |    | 세션 단위 Text Only override                                   |
| `dynamicVariables` | `Record<string, string \| number \| boolean>` |    | 프롬프트에 주입할 [동적 변수](/docs/build/variables/dynamic-variables) |
| `metadata`         | `Record<string, unknown>`                     |    | 콜 메타데이터 (웹훅, 통화 기록에 포함)                                    |

##### endSession

세션을 종료합니다. `Promise<void>`를 반환합니다.

```tsx theme={null}
await conversation.endSession();
```

##### setVolume

출력 볼륨을 조절합니다. 0\~1 사이 값을 넣으세요.

```tsx theme={null}
conversation.setVolume({ volume: 0.5 });
```

##### sendUserMessage

에이전트에게 텍스트 메시지를 보냅니다. 마이크 대신 텍스트로 입력할 때 쓰세요.
`Promise<void>`를 반환합니다.

```tsx theme={null}
const [value, setValue] = useState("");

return (
  <>
    <input value={value} onChange={(e) => setValue(e.target.value)} />
    <button
      onClick={async () => {
        await conversation.sendUserMessage(value);
        setValue("");
      }}
    >
      전송
    </button>
  </>
);
```

##### setMicMuted

마이크를 음소거하거나 해제합니다. `Promise<void>`를 반환합니다.

```tsx theme={null}
// 음소거
await conversation.setMicMuted(true);

// 해제
await conversation.setMicMuted(false);
```

##### getId

현재 세션 ID를 돌려줍니다. 세션 ID가 없으면 `undefined`를 반환합니다.

```tsx theme={null}
const conversationId = conversation.getId();
```

##### getMessages

세션의 메시지 배열 snapshot을 돌려줍니다.

```tsx theme={null}
const messages = conversation.getMessages();
```

##### getAgentState

현재 에이전트 상태 snapshot을 돌려줍니다.

```tsx theme={null}
const agentState = conversation.getAgentState();
// "initializing" | "idle" | "listening" | "thinking" | "speaking" | undefined
```

##### getInputVolume / getOutputVolume

현재 입출력 볼륨을 0\~1 스케일로 돌려줍니다.

```tsx theme={null}
const inputLevel = conversation.getInputVolume();
const outputLevel = conversation.getOutputVolume();
```

##### getInputByteFrequencyData / getOutputByteFrequencyData

입출력 주파수 데이터를 `Uint8Array`로 돌려줍니다. 세션이 없으면 `undefined`를 반환합니다.
오디오 시각화에 쓸 수 있습니다.

```tsx theme={null}
const inputFrequency = conversation.getInputByteFrequencyData();
const outputFrequency = conversation.getOutputByteFrequencyData();
```

<Note>
  오디오 모니터링 메서드는 음성 세션에서만 동작합니다.
</Note>

##### changeInputDevice

세션 중에 오디오 입력 디바이스를 바꿉니다.
전환 성공 여부를 담은 `Promise<boolean>`을 반환합니다.

```tsx theme={null}
const changed = await conversation.changeInputDevice({
  inputDeviceId: "your-device-id",
});
```

##### changeOutputDevice

세션 중에 오디오 출력 디바이스를 바꿉니다.
전환 성공 여부를 담은 `Promise<boolean>`을 반환합니다.

```tsx theme={null}
const changed = await conversation.changeOutputDevice({
  outputDeviceId: "your-device-id",
});
```

<Note>
  디바이스 전환은 음성 세션에서만 동작합니다. `deviceId`를 지정하지 않으면 브라우저 기본 디바이스가 쓰입니다.
  사용 가능한 디바이스 목록은 [MediaDevices.enumerateDevices()](https://developer.mozilla.org/docs/Web/API/MediaDevices/enumerateDevices) API로 조회하세요.
</Note>

#### React State

| State        | 타입                        | 설명                                                                                           |
| ------------ | ------------------------- | -------------------------------------------------------------------------------------------- |
| `status`     | `ConversationStatus`      | `"disconnected"` \| `"connecting"` \| `"connected"`                                          |
| `agentState` | `AgentState \| undefined` | `"initializing"` \| `"idle"` \| `"listening"` \| `"thinking"` \| `"speaking"` \| `undefined` |
| `isSpeaking` | `boolean`                 | `agentState === "speaking"` 기반 편의 값                                                          |
| `micMuted`   | `boolean`                 | 마이크 음소거 상태                                                                                   |
| `messages`   | `ConversationMessage[]`   | 세션에서 주고받은 메시지 배열                                                                             |

```tsx theme={null}
const { status, agentState, isSpeaking, micMuted, messages } = useConversation();
```

> JavaScript SDK의 `getStatus()`, `getAgentState()`, `getMicMuted()`에 대응합니다. React에서는 state로 제공되어 값이 바뀌면 자동으로 re-render됩니다.

### Text Only 모드

마이크 없이 텍스트만으로 에이전트와 대화할 수 있습니다. 마이크 권한을 요청하지 않고 오디오 컨텍스트도 만들지 않습니다.

```tsx theme={null}
const conversation = useConversation({
  textOnly: true,
});

await conversation.startSession({
  agentId: "<your-agent-id>",
  apiKey: "<your-api-key>",
});

await conversation.sendUserMessage("안녕하세요");
```

### Dynamic Variables와 Metadata

```tsx theme={null}
const conversationId = await conversation.startSession({
  agentId: "<your-agent-id>",
  apiKey: "<your-api-key>",
  dynamicVariables: {
    userName: "홍길동",
    userType: "premium",
    accountBalance: 50000,
  },
  metadata: {
    sessionId: "sess_abc123",
    source: "web-app",
  },
});
```

* `dynamicVariables` — 에이전트 프롬프트에서 `{{userName}}` 형식으로 참조됩니다. [동적 변수](/docs/build/variables/dynamic-variables)에서 자세히 알아보세요.
* `metadata` — 웹훅과 통화 기록에 포함됩니다.

### 전체 예제

```tsx theme={null}
import { useConversation } from "@vox-ai/react";
import { useState } from "react";

function VoiceWidget() {
  const conversation = useConversation({
    onConnect: () => console.log("Connected"),
    onDisconnect: () => console.log("Disconnected"),
    onAgentStateChange: (agentState) => console.log("Agent state:", agentState),
    onMessage: (msg) => console.log(`${msg.source}: ${msg.text}`),
    onError: (err) => console.error("Error:", err),
  });

  const start = async () => {
    await navigator.mediaDevices.getUserMedia({ audio: true });
    await conversation.startSession({
      agentId: "your-agent-id",
      apiKey: "your-api-key",
    });
  };

  return (
    <div>
      <p>Status: {conversation.status}</p>
      <p>Agent State: {conversation.agentState ?? "unknown"}</p>
      <p>Speaking: {conversation.isSpeaking ? "Yes" : "No"}</p>

      <button
        onClick={start}
        disabled={conversation.status !== "disconnected"}
      >
        시작
      </button>
      <button
        onClick={async () => {
          await conversation.endSession();
        }}
      >
        종료
      </button>
    </div>
  );
}
```

***

<Accordion title="연관 검색어">
  React SDK, 리액트 SDK, useConversation, @vox-ai/react, 훅, hook, 웹 연동
</Accordion>
