이벤트
이벤트 등록 타이밍
콜백은 init() 전후 언제든 등록할 수 있습니다. 단, onStatus는 init() 중 상태 변경(CONNECTING, SOCKET_CONNECTED 등)을 수신하려면 init() 호출 전에 등록하세요.
- 각 타입당 콜백 1개만 등록 가능하며, 마지막 등록이 이전을 덮어씁니다.
destroy()후에도 콜백은 유지되므로 재초기화 시 다시 등록할 필요 없습니다.
onSignal(callback)
서버로부터 수신한 시그널을 받습니다.
js
SDK.onSignal((data) => {
console.log(data.signal, data.payload);
});jsx
useEffect(() => {
window.KlleonSDK.onSignal((data) => {
console.log(data.signal, data.payload);
});
}, []);콜백 파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
signal | IncomingSignal | O | 시그널 종류 (enum, 런타임에는 문자열) |
payload | object | X | 시그널별 추가 데이터 |
id | string | O | 시그널 UUID |
type | string | O | "SESSION" | "INPUT" | "OUTPUT" |
주요 시그널
대화 흐름
| 시그널 | 설명 | payload |
|---|---|---|
RESPONSE_TEXT | 아바타 응답 텍스트 | { text: string, language: string } |
STT_RESULT | 음성 인식 결과 | { text: string } |
RESPONSE_PREPARING | 응답 준비 중 (LLM 요청 직전) | - |
RESPONSE_STARTED | 응답 시작 | - |
RESPONSE_ENDED | 응답 완료 | - |
USER_SPEECH_STARTED | STT 세션 내 발화 구간 시작 (마이크는 이미 켜져 있음) | - |
USER_SPEECH_STOPPED | STT 세션 내 발화 구간 종료 (마이크는 여전히 켜져 있음) | - |
ERROR | 서버 에러 (세션 유지) | { type: "STT_ERROR" | "LLM_ERROR" | ... } |
REJECTED | 입력 거절 (세션 유지) | { type: "STT_EMPTY" | "MODERATION" | ... } |
세션 관리
| 시그널 | 설명 | payload |
|---|---|---|
MATCH_WAITING | 매칭 대기 중 (로딩 UI 표시용) | - |
WAIT | 서버 준비 중 (계속 대기) | - |
SESSION_ENDED | 세션 정상 종료 | - |
SESSION_TIMED_OUT | 세션 타임아웃 | - |
TIME_EXHAUSTED | 사용 시간 소진 | - |
QUOTA_EXCEEDED | 동접 quota 초과 | - |
SUSPEND_WARNED | 오랜 대기 경고 | - |
onStatus(callback)
SDK 연결 상태 변경을 받습니다.
js
SDK.onStatus((status) => {
console.log('상태:', status);
if (status === 'CONNECTED_FINISH') {
console.log('아바타 준비 완료');
}
});jsx
const [status, setStatus] = useState('IDLE');
useEffect(() => {
window.KlleonSDK.onStatus((s) => setStatus(s));
}, []);onError(callback)
SDK 내부 에러 + 서버 에러를 받습니다.
js
SDK.onError((error) => {
console.error(error.code, error.message);
});jsx
useEffect(() => {
window.KlleonSDK.onError((error) => {
console.error(error.code, error.message);
});
}, []);콜백 파라미터
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
code | string | O | 에러 코드 |
message | string | X | 상세 메시지 |
에러 코드 상세
초기화 에러 (init 실패 시)
| 코드 | 발생 시점 | message 예시 |
|---|---|---|
SOCKET_FAILED | SDK 키 검증 실패 또는 WebSocket 연결 실패 | "Failed to connect: ..." |
STREAMING_FAILED | 스트리밍 연결 실패 | "Failed to connect streaming: ..." |
init 실패 시
onError는 호출되지 않습니다.init()이Error를 throw하므로try/catch로 처리하세요.
런타임 에러 (연결 중 발생)
| 코드 | 발생 시점 | message 예시 |
|---|---|---|
SOCKET_DISCONNECTED_UNEXPECTEDLY | WebSocket 에러 발생 | "WebSocket disconnected unexpectedly" |
STREAMING_FAILED | 원격 트랙 구독 실패 | "Failed to subscribe to remote track" |
STREAMING_DISCONNECTED_UNEXPECTEDLY | 스트리밍 비정상 종료 | "Streaming disconnected: NETWORK_ERROR" |
서버 에러
| 코드 | 발생 시점 | message 예시 |
|---|---|---|
SERVER_ERROR | 서버에서 SERVER_ERROR 시그널 수신 | 서버가 보낸 메시지 또는 "SERVER_ERROR" |
WORKER_DISCONNECTED | 서버 연결 종료 시그널 수신 | "WORKER_DISCONNECTED" |
이벤트 등록 예제
js
const SDK = window.KlleonSDK;
SDK.onStatus((status) => console.log('상태:', status));
SDK.onSignal((data) => {
if (data.signal === 'RESPONSE_TEXT') {
console.log('아바타:', data.payload.text);
}
});
SDK.onError((error) => {
console.error(`[${error.code}] ${error.message}`);
});
SDK.init({
sdk_key: 'YOUR_SDK_KEY',
avatar_id: 'YOUR_AVATAR_ID',
}).catch((e) => console.error(e.message));jsx
import { useEffect, useRef } from 'react';
function App() {
const initialized = useRef(false);
useEffect(() => {
const SDK = window.KlleonSDK;
SDK.onStatus((status) => console.log('상태:', status));
SDK.onSignal((data) => {
if (data.signal === 'RESPONSE_TEXT') {
console.log('아바타:', data.payload.text);
}
});
SDK.onError((error) => {
console.error(`[${error.code}] ${error.message}`);
});
SDK.init({
sdk_key: 'YOUR_SDK_KEY',
avatar_id: 'YOUR_AVATAR_ID',
})
.then(() => { initialized.current = true; })
.catch((e) => console.error(e.message));
return () => {
if (initialized.current) SDK.destroy();
};
}, []);
return <avatar-container style={{ width: 400, height: 600 }} />;
}