@klever-one/web-sdk
Version:
Web SDK for integrating real-time room management and streaming functionality into web applications
784 lines (759 loc) • 29.1 kB
JavaScript
"use client";
import { useRef as x, useState as f, useEffect as y, useCallback as u, useMemo as M } from "react";
import { KleverOneClient as J } from "../core/klever-one-core-v0.1.0-beta.14.es.js";
import { jsx as n, jsxs as v } from "react/jsx-runtime";
const Q = `
/* Klever One SDK Styles - Scoped to prevent external interference */
/* All styles are scoped within .klever-one-sdk container */
/* This prevents SDK styles from affecting the parent application */
/* Layout utilities */
.klever-one-sdk.kos-relative, .klever-one-sdk .kos-relative { position: relative; }
.klever-one-sdk.kos-absolute, .klever-one-sdk .kos-absolute { position: absolute; }
.klever-one-sdk.kos-flex, .klever-one-sdk .kos-flex { display: flex; }
.klever-one-sdk.kos-inline-flex, .klever-one-sdk .kos-inline-flex { display: inline-flex; }
.klever-one-sdk.kos-flex-1, .klever-one-sdk .kos-flex-1 { flex: 1 1 0%; }
.klever-one-sdk.kos-flex-col, .klever-one-sdk .kos-flex-col { flex-direction: column; }
.klever-one-sdk.kos-flex-shrink-0, .klever-one-sdk .kos-flex-shrink-0 { flex-shrink: 0; }
.klever-one-sdk.kos-items-center, .klever-one-sdk .kos-items-center { align-items: center; }
.klever-one-sdk.kos-items-start, .klever-one-sdk .kos-items-start { align-items: flex-start; }
.klever-one-sdk.kos-items-end, .klever-one-sdk .kos-items-end { align-items: flex-end; }
.klever-one-sdk.kos-items-stretch, .klever-one-sdk .kos-items-stretch { align-items: stretch; }
.klever-one-sdk.kos-justify-start, .klever-one-sdk .kos-justify-start { justify-content: flex-start; }
.klever-one-sdk.kos-justify-end, .klever-one-sdk .kos-justify-end { justify-content: flex-end; }
.klever-one-sdk.kos-justify-center, .klever-one-sdk .kos-justify-center { justify-content: center; }
.klever-one-sdk.kos-justify-between, .klever-one-sdk .kos-justify-between { justify-content: space-between; }
.klever-one-sdk.kos-gap-2, .klever-one-sdk .kos-gap-2 { gap: 0.5rem; }
.klever-one-sdk.kos-gap-4, .klever-one-sdk .kos-gap-4 { gap: 1rem; }
/* Sizing */
.klever-one-sdk.kos-w-full, .klever-one-sdk .kos-w-full { width: 100%; }
.klever-one-sdk.kos-h-full, .klever-one-sdk .kos-h-full { height: 100%; }
.klever-one-sdk.kos-w-auto, .klever-one-sdk .kos-w-auto { width: auto; }
.klever-one-sdk.kos-h-auto, .klever-one-sdk .kos-h-auto { height: auto; }
.klever-one-sdk.kos-min-w-0, .klever-one-sdk .kos-min-w-0 { min-width: 0; }
.klever-one-sdk.kos-min-h-0, .klever-one-sdk .kos-min-h-0 { min-height: 0; }
.klever-one-sdk.kos-w-4, .klever-one-sdk .kos-w-4 { width: 1rem; }
.klever-one-sdk.kos-h-4, .klever-one-sdk .kos-h-4 { height: 1rem; }
.klever-one-sdk.kos-w-11, .klever-one-sdk .kos-w-11 { width: 2.75rem; }
.klever-one-sdk.kos-h-11, .klever-one-sdk .kos-h-11 { height: 2.75rem; }
.klever-one-sdk.kos-w-80, .klever-one-sdk .kos-w-80 { width: 20rem; }
.klever-one-sdk.kos-w-96, .klever-one-sdk .kos-w-96 { width: 24rem; }
.klever-one-sdk.kos-h-96, .klever-one-sdk .kos-h-96 { height: 24rem; }
.klever-one-sdk.kos-max-w-xs, .klever-one-sdk .kos-max-w-xs { max-width: 20rem; }
.klever-one-sdk.kos-max-w-md, .klever-one-sdk .kos-max-w-md { max-width: 28rem; }
.klever-one-sdk.kos-max-w-4xl, .klever-one-sdk .kos-max-w-4xl { max-width: 56rem; }
/* Spacing */
.klever-one-sdk.kos-p-3, .klever-one-sdk .kos-p-3 { padding: 0.75rem; }
.klever-one-sdk.kos-p-4, .klever-one-sdk .kos-p-4 { padding: 1rem; }
.klever-one-sdk.kos-px-3, .klever-one-sdk .kos-px-3 { padding-left: 0.75rem; padding-right: 0.75rem; }
.klever-one-sdk.kos-px-4, .klever-one-sdk .kos-px-4 { padding-left: 1rem; padding-right: 1rem; }
.klever-one-sdk.kos-py-1, .klever-one-sdk .kos-py-1 { padding-top: 0.25rem; padding-bottom: 0.25rem; }
.klever-one-sdk.kos-py-2, .klever-one-sdk .kos-py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }
.klever-one-sdk.kos-pr-2, .klever-one-sdk .kos-pr-2 { padding-right: 0.5rem; }
.klever-one-sdk.kos-mx-auto, .klever-one-sdk .kos-mx-auto { margin-left: auto; margin-right: auto; }
.klever-one-sdk.kos-space-y-4, .klever-one-sdk .kos-space-y-4 > * + * { margin-top: 1rem; }
/* Positioning */
.klever-one-sdk.kos-top-0, .klever-one-sdk .kos-top-0 { top: 0; }
.klever-one-sdk.kos-left-0, .klever-one-sdk .kos-left-0 { left: 0; }
.klever-one-sdk.kos-z-0, .klever-one-sdk .kos-z-0 { z-index: 0; }
.klever-one-sdk.kos-z-10, .klever-one-sdk .kos-z-10 { z-index: 10; }
.klever-one-sdk.kos-z-20, .klever-one-sdk .kos-z-20 { z-index: 20; }
/* Colors & Backgrounds */
.klever-one-sdk.kos-bg-black, .klever-one-sdk .kos-bg-black { background-color: #000; }
.klever-one-sdk.kos-bg-gray-100, .klever-one-sdk .kos-bg-gray-100 { background-color: #f3f4f6; }
.klever-one-sdk.kos-bg-gray-700, .klever-one-sdk .kos-bg-gray-700 { background-color: #374151; }
.klever-one-sdk.kos-bg-blue-500, .klever-one-sdk .kos-bg-blue-500 { background-color: #3b82f6; }
.klever-one-sdk.kos-bg-blue-600, .klever-one-sdk .kos-bg-blue-600 { background-color: #2563eb; }
.klever-one-sdk.kos-bg-green-500, .klever-one-sdk .kos-bg-green-500 { background-color: #10b981; }
.klever-one-sdk.kos-bg-yellow-500, .klever-one-sdk .kos-bg-yellow-500 { background-color: #f59e0b; }
.klever-one-sdk.kos-bg-red-500, .klever-one-sdk .kos-bg-red-500 { background-color: #ef4444; }
.klever-one-sdk.kos-bg-opacity-50, .klever-one-sdk .kos-bg-opacity-50 { background-color: rgba(0, 0, 0, 0.5); }
/* Text */
.klever-one-sdk.kos-text-white, .klever-one-sdk .kos-text-white { color: #fff; }
.klever-one-sdk.kos-text-xs, .klever-one-sdk .kos-text-xs { font-size: 0.75rem; line-height: 1rem; }
.klever-one-sdk.kos-text-sm, .klever-one-sdk .kos-text-sm { font-size: 0.875rem; line-height: 1.25rem; }
.klever-one-sdk.kos-text-blue-400, .klever-one-sdk .kos-text-blue-400 { color: #60a5fa; }
.klever-one-sdk.kos-text-green-400, .klever-one-sdk .kos-text-green-400 { color: #4ade80; }
.klever-one-sdk.kos-text-yellow-400, .klever-one-sdk .kos-text-yellow-400 { color: #fbbf24; }
.klever-one-sdk.kos-text-red-400, .klever-one-sdk .kos-text-red-400 { color: #f87171; }
/* Borders & Radius */
.klever-one-sdk.kos-rounded-lg, .klever-one-sdk .kos-rounded-lg { border-radius: 0.5rem; }
.klever-one-sdk.kos-rounded-2xl, .klever-one-sdk .kos-rounded-2xl { border-radius: 1rem; }
.klever-one-sdk.kos-rounded-full, .klever-one-sdk .kos-rounded-full { border-radius: 9999px; }
.klever-one-sdk.kos-rounded-bl-none, .klever-one-sdk .kos-rounded-bl-none { border-bottom-left-radius: 0; }
.klever-one-sdk.kos-rounded-br-none, .klever-one-sdk .kos-rounded-br-none { border-bottom-right-radius: 0; }
/* Overflow & Scroll */
.klever-one-sdk.kos-overflow-y-auto, .klever-one-sdk .kos-overflow-y-auto { overflow-y: auto; }
.klever-one-sdk.kos-overflow-y-hidden, .klever-one-sdk .kos-overflow-y-hidden { overflow-y: hidden; }
.klever-one-sdk.kos-scroll-smooth, .klever-one-sdk .kos-scroll-smooth { scroll-behavior: smooth; }
.klever-one-sdk.kos-resize-none, .klever-one-sdk .kos-resize-none { resize: none; }
/* Text wrapping utilities */
.klever-one-sdk.kos-break-words, .klever-one-sdk .kos-break-words {
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-word;
}
.klever-one-sdk.kos-whitespace-pre-wrap, .klever-one-sdk .kos-whitespace-pre-wrap {
white-space: pre-wrap;
}
.klever-one-sdk.kos-whitespace-normal, .klever-one-sdk .kos-whitespace-normal {
white-space: normal;
}
.klever-one-sdk.kos-hyphens-auto, .klever-one-sdk .kos-hyphens-auto {
hyphens: auto;
-webkit-hyphens: auto;
-ms-hyphens: auto;
}
/* Outline */
.klever-one-sdk.kos-outline-none, .klever-one-sdk .kos-outline-none { outline: none; }
.klever-one-sdk.kos-outline-none, .klever-one-sdk .kos-outline-none:focus { outline: none; }
/* Transitions */
.klever-one-sdk.kos-transition-colors, .klever-one-sdk .kos-transition-colors {
transition-property: color, background-color, border-color;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.klever-one-sdk.kos-transition-all, .klever-one-sdk .kos-transition-all {
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
/* Cursor */
.klever-one-sdk.kos-cursor-pointer, .klever-one-sdk .kos-cursor-pointer { cursor: pointer; }
.klever-one-sdk.kos-cursor-not-allowed, .klever-one-sdk .kos-cursor-not-allowed { cursor: not-allowed !important; }
/* Opacity */
.klever-one-sdk.kos-opacity-50, .klever-one-sdk .kos-opacity-50 { opacity: 0.5; }
/* Animations - scoped with unique prefix */
@keyframes klever-one-sdk-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.klever-one-sdk.kos-animate-pulse, .klever-one-sdk .kos-animate-pulse { animation: klever-one-sdk-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; }
/* Hover states */
@media (hover: hover) {
.klever-one-sdk.kos-hover-bg-blue-600, .klever-one-sdk .kos-hover-bg-blue-600:hover { background-color: #2563eb; }
.klever-one-sdk.kos-hover-bg-green-600, .klever-one-sdk .kos-hover-bg-green-600:hover { background-color: #059669; }
.klever-one-sdk.kos-hover-bg-red-600, .klever-one-sdk .kos-hover-bg-red-600:hover { background-color: #dc2626; }
.klever-one-sdk.kos-hover-bg-gray-600, .klever-one-sdk .kos-hover-bg-gray-600:hover { background-color: #4b5563; }
}
/* Input & Textarea base styles */
.klever-one-sdk textarea {
box-sizing: border-box;
line-height: 1.5;
font-family: inherit;
}
/* Disabled states */
.klever-one-sdk input:disabled,
.klever-one-sdk textarea:disabled,
.klever-one-sdk button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Keep disabled button colors unchanged on hover */
.klever-one-sdk button.kos-bg-blue-500:disabled:hover,
.klever-one-sdk .kos-bg-blue-500:disabled:hover {
background-color: #3b82f6 !important;
}
.klever-one-sdk button.kos-bg-green-500:disabled:hover,
.klever-one-sdk .kos-bg-green-500:disabled:hover {
background-color: #10b981 !important;
}
.klever-one-sdk button.kos-bg-red-500:disabled:hover,
.klever-one-sdk .kos-bg-red-500:disabled:hover {
background-color: #ef4444 !important;
}
.klever-one-sdk button.kos-bg-gray-700:disabled:hover,
.klever-one-sdk .kos-bg-gray-700:disabled:hover {
background-color: #374151 !important;
}
/* Focus states */
.klever-one-sdk input:focus,
.klever-one-sdk textarea:focus,
.klever-one-sdk button:focus {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
/* Placeholder */
.klever-one-sdk input::placeholder,
.klever-one-sdk textarea::placeholder {
color: #9ca3af;
opacity: 1;
}
/* Pointer events - scoped */
.klever-one-sdk .pointer-events-none { pointer-events: none; }
.klever-one-sdk .pointer-events-auto { pointer-events: auto; }
/* React resizable - scoped */
.klever-one-sdk.react-resizable, .klever-one-sdk .react-resizable {
position: relative;
}
.klever-one-sdk.react-resizable, .klever-one-sdk .react-resizable .react-resizable-handle {
position: absolute;
width: 20px;
height: 20px;
bottom: 0;
right: 0;
cursor: se-resize;
background: rgba(0, 0, 0, 0.2);
}
/* Animations - scoped with unique prefix */
@keyframes klever-one-sdk-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* Pixel Streaming specific - scoped to SDK container to prevent global conflicts */
.klever-one-sdk #connectOverlay,
.klever-one-sdk #disconnectOverlay,
.klever-one-sdk #infoOverlay,
.klever-one-sdk #afkOverlay {
display: none !important;
}
.klever-one-sdk #streamingVideo {
object-fit: cover !important;
}
`;
let I = !1;
function j() {
if (I || typeof document > "u")
return;
const s = document.createElement("style");
s.id = "klever-one-sdk-styles", s.textContent = Q, document.head && (document.head.appendChild(s), I = !0);
}
typeof document < "u" && (document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", j) : j()), !0;
let C = 0;
function X(s) {
const { apiKey: k, container: l, callbacks: i, conversation: d, ...g } = s, o = x(i);
o.current = i;
const e = x(null), [p, a] = f({
connection: "disconnected",
recording: "idle",
isStreaming: !1,
isStreamingReady: !1,
isConversationReady: !1,
lastUpdated: /* @__PURE__ */ new Date()
}), [c, b] = f({
reconnectAttempts: 0,
messagesSent: 0,
messagesReceived: 0,
recordingSessions: 0,
errorCount: 0
}), [N, z] = f({
messages: [],
isStreaming: !1,
isCompleted: !1
}), [O, w] = f([]);
y(() => {
try {
const r = new J({
apiKey: k,
container: l,
conversation: d,
...g,
callbacks: {
...o.current,
// 기존 콜백과 상태 업데이트를 결합
onConnectionStatusChange: (t) => {
a((h) => ({ ...h, connection: t })), o.current?.onConnectionStatusChange?.(t);
},
onRecordingStatusChange: (t) => {
a((h) => ({ ...h, recording: t })), o.current?.onRecordingStatusChange?.(t);
},
onStreamingStatusChange: (t) => {
a((h) => ({ ...h, isStreaming: t })), o.current?.onStreamingStatusChange?.(t);
},
onMessageReceived: (t) => {
w((h) => {
const R = h.findIndex((S) => S.id === t.id);
if (R >= 0) {
const S = [...h];
return S[R] = t, S;
} else
return [...h, t];
}), o.current?.onMessageReceived?.(t);
},
onReady: () => {
a((t) => ({
...t,
isStreamingReady: !0,
isConversationReady: !0
})), o.current?.onReady?.();
},
onDisconnect: () => {
a({
connection: "disconnected",
recording: "idle",
isStreaming: !1,
isStreamingReady: !1,
isConversationReady: !1,
lastUpdated: /* @__PURE__ */ new Date()
}), w([]), o.current?.onDisconnect?.();
},
onError: (t) => {
b((h) => ({
...h,
errorCount: h.errorCount + 1,
lastErrorTime: /* @__PURE__ */ new Date()
})), o.current?.onError?.(t);
},
onRoomInfoUpdated: (t) => {
o.current?.onRoomInfoUpdated?.(t);
},
onLog: (t) => {
o.current?.onLog?.(t);
},
onRoomSessionTimeout: (t) => {
o.current?.onRoomSessionTimeout?.(t);
}
}
});
e.current = r, C++, a(r.getState()), b(r.getMetrics()), z(r.getConversationState()), w(r.getMessages());
} catch {
}
return () => {
C--, C === 0 && e.current && e.current.getState().connection !== "disconnected" && e.current.disconnect();
};
}, [k, l]), y(() => {
if (!e.current) return;
const t = setInterval(() => {
e.current && e.current.getState().connection !== "disconnected" && (a(e.current.getState()), b(e.current.getMetrics()), z(e.current.getConversationState()), w(e.current.getMessages()));
}, 1e3);
return () => clearInterval(t);
}, []);
const T = u(async () => {
if (e.current)
return e.current.connect();
throw new Error("KleverOneClient not initialized");
}, []), E = u(() => {
e.current && e.current.disconnect();
}, []), D = u(async () => {
if (e.current)
return e.current.reconnect();
throw new Error("KleverOneClient not initialized");
}, []), K = u(async (r) => {
if (e.current)
return e.current.sendText(r);
throw new Error("KleverOneClient not initialized");
}, []), A = u(async () => {
if (e.current)
return e.current.startRecording();
throw new Error("KleverOneClient not initialized");
}, []), P = u(async () => {
if (e.current)
return e.current.stopRecording();
throw new Error("KleverOneClient not initialized");
}, []), $ = u(() => e.current ? e.current.isReady() : !1, []), U = u(() => e.current ? e.current.isRecording() : !1, []), B = u((r, t) => {
e.current && e.current.resize(r, t);
}, []), H = u((r) => {
e.current && e.current.sendAvatarNum(r);
}, []), L = u((r) => {
e.current && e.current.sendAvatarAppearanceChange(r);
}, []), W = u((r) => {
e.current && e.current.sendPlaceBackgroundChange(r);
}, []), F = u((r) => {
e.current && e.current.sendVoiceSetting(r);
}, []), V = u(
(r) => {
e.current && e.current.sendMessage(r);
},
[]
), q = u(
async (r) => {
if (e.current)
return e.current.sendDataInChunks(r);
throw new Error("KleverOneClient not initialized");
},
[]
), G = u(
((r) => {
e.current && (Array.isArray(r), e.current.speak(r));
}),
[]
);
return {
client: e.current,
state: p,
metrics: c,
conversationState: N,
messages: O,
connect: T,
disconnect: E,
reconnect: D,
sendText: K,
speak: G,
startRecording: A,
stopRecording: P,
isReady: $,
isRecording: U,
// 고급 기능들
resize: B,
sendAvatarNum: H,
sendAvatarAppearanceChange: L,
sendPlaceBackgroundChange: W,
sendVoiceSetting: F,
sendMessage: V,
sendDataInChunks: q
};
}
const m = ({
size: s = 24,
color: k = "currentColor",
stroke: l = 2,
className: i = "",
style: d,
children: g,
name: o
}) => /* @__PURE__ */ n(
"svg",
{
width: s,
height: s,
viewBox: "0 0 24 24",
fill: "none",
stroke: k,
strokeWidth: l,
strokeLinecap: "round",
strokeLinejoin: "round",
className: i,
style: d,
role: "img",
"aria-label": o,
children: g
}
), Y = (s) => /* @__PURE__ */ v(
m,
{
name: "Send",
...s,
children: [
/* @__PURE__ */ n("path", { d: "M10 14l11 -11" }),
/* @__PURE__ */ n("path", { d: "M21 3l-6.5 18a.55 .55 0 0 1 -1 0l-3.5 -7l-7 -3.5a.55 .55 0 0 1 0 -1l18 -6.5" })
]
}
), Z = (s) => /* @__PURE__ */ v(
m,
{
name: "Microphone",
...s,
children: [
/* @__PURE__ */ n("path", { d: "M9 2m0 3a3 3 0 0 1 3 -3h0a3 3 0 0 1 3 3v5a3 3 0 0 1 -3 3h0a3 3 0 0 1 -3 -3z" }),
/* @__PURE__ */ n("path", { d: "M5 10a7 7 0 0 0 14 0" }),
/* @__PURE__ */ n("path", { d: "M8 21l8 0" }),
/* @__PURE__ */ n("path", { d: "M12 17l0 4" })
]
}
), _ = (s) => /* @__PURE__ */ n(
m,
{
name: "PlayerStop",
...s,
children: /* @__PURE__ */ n("path", { d: "M5 5m0 2a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2z" })
}
), ee = (s) => /* @__PURE__ */ v(
m,
{
name: "PhoneCall",
...s,
children: [
/* @__PURE__ */ n("path", { d: "M5 4h4l2 5l-2.5 1.5a11 11 0 0 0 5 5l1.5 -2.5l5 2v4a2 2 0 0 1 -2 2a16 16 0 0 1 -15 -15a2 2 0 0 1 2 -2" }),
/* @__PURE__ */ n("path", { d: "M15 7a2 2 0 0 1 2 2" }),
/* @__PURE__ */ n("path", { d: "M15 3a6 6 0 0 1 6 6" })
]
}
), oe = (s) => /* @__PURE__ */ v(
m,
{
name: "PhoneOff",
...s,
children: [
/* @__PURE__ */ n("path", { d: "M3 21l18 -18" }),
/* @__PURE__ */ n("path", { d: "M5.831 14.161a15.946 15.946 0 0 1 -2.831 -8.161a2 2 0 0 1 2 -2h4l2 5l-2.5 1.5c.108 .22 .223 .435 .345 .645m1.751 2.277c.843 .84 1.822 1.544 2.904 2.078l1.5 -2.5l5 2v4a2 2 0 0 1 -2 2a15.963 15.963 0 0 1 -10.344 -4.657" })
]
}
), ne = (s) => /* @__PURE__ */ v(
m,
{
name: "Wifi",
...s,
children: [
/* @__PURE__ */ n("path", { d: "M12 18l.01 0" }),
/* @__PURE__ */ n("path", { d: "M9.172 15.172a4 4 0 0 1 5.656 0" }),
/* @__PURE__ */ n("path", { d: "M6.343 12.343a8 8 0 0 1 11.314 0" }),
/* @__PURE__ */ n("path", { d: "M3.515 9.515c4.686 -4.687 12.284 -4.687 17 0" })
]
}
), se = (s) => /* @__PURE__ */ v(
m,
{
name: "WifiOff",
...s,
children: [
/* @__PURE__ */ n("path", { d: "M12 18l.01 0" }),
/* @__PURE__ */ n("path", { d: "M9.172 15.172a4 4 0 0 1 5.656 0" }),
/* @__PURE__ */ n("path", { d: "M6.343 12.343a7.963 7.963 0 0 1 3.864 -2.14m4.163 .155a7.965 7.965 0 0 1 3.287 2" }),
/* @__PURE__ */ n("path", { d: "M3.515 9.515a12 12 0 0 1 3.544 -2.455m3.101 -.92a12 12 0 0 1 10.325 3.374" }),
/* @__PURE__ */ n("path", { d: "M3 3l18 18" })
]
}
), re = ({
state: s
}) => {
const k = s.connection === "connected", l = s.connection === "connecting", i = k ? "kos-text-green-400" : l ? "kos-text-yellow-400" : "kos-text-red-400", d = k ? "연결됨" : l ? "연결 중..." : "연결 안됨", g = k || l ? ne : se;
return /* @__PURE__ */ v(
"div",
{
className: `klever-one-sdk kos-flex kos-items-center kos-gap-2 kos-px-3 kos-py-1 kos-bg-black kos-bg-opacity-50 kos-rounded-full kos-text-white kos-text-xs ${i}`,
children: [
/* @__PURE__ */ n(
g,
{
className: `kos-w-4 kos-h-4 ${l ? "kos-animate-pulse" : ""}`
}
),
/* @__PURE__ */ n("span", { children: d }),
s.isStreaming && /* @__PURE__ */ n("span", { className: "kos-text-sm kos-text-blue-400", children: "응답 생성 중..." })
]
}
);
}, te = ({
state: s,
connect: k,
disconnect: l
}) => {
const i = s.connection === "connected", d = s.connection === "connecting";
return /* @__PURE__ */ n(
"button",
{
onClick: () => {
i || d ? l() : k();
},
disabled: d,
className: `klever-one-sdk kos-w-11 kos-h-11 kos-inline-flex kos-items-center kos-justify-center kos-rounded-full kos-transition-colors ${i ? "kos-bg-red-500 kos-hover-bg-red-600 kos-text-white kos-cursor-pointer" : d ? "kos-bg-yellow-500 kos-text-white kos-animate-pulse kos-cursor-not-allowed" : "kos-bg-green-500 kos-hover-bg-green-600 kos-text-white kos-cursor-pointer"}`,
children: i || d ? /* @__PURE__ */ n(oe, { size: 20 }) : /* @__PURE__ */ n(ee, { size: 20 })
}
);
}, ke = ({
state: s,
isReady: k,
sendText: l,
startRecording: i,
stopRecording: d
}) => {
const g = x(null), [o, e] = f("");
y(() => {
const c = g.current;
if (c) {
c.style.height = "44px";
const b = Math.min(Math.max(c.scrollHeight, 44), 120);
c.style.height = `${b}px`;
}
}, [o]);
const p = async (c) => {
if (c.preventDefault(), !(!o.trim() || s.isStreaming))
try {
await l(o), e("");
} catch {
}
}, a = async () => {
try {
s.recording === "recording" ? await d() : await i();
} catch {
}
};
return /* @__PURE__ */ v(
"form",
{
onSubmit: p,
className: "klever-one-sdk kos-w-full kos-flex kos-items-stretch kos-gap-4",
children: [
/* @__PURE__ */ n(
"textarea",
{
ref: g,
className: "kos-flex-1 kos-min-w-0 kos-bg-gray-700 kos-text-white kos-p-3 kos-rounded-lg kos-resize-none kos-outline-none kos-overflow-y-hidden kos-transition-all",
placeholder: "메시지를 입력하세요...",
value: o,
onChange: (c) => e(c.target.value),
disabled: s.isStreaming,
rows: 1,
style: { minHeight: "44px", maxHeight: "120px" },
onKeyDown: (c) => {
c.key === "Enter" && !c.shiftKey && (c.preventDefault(), p(c));
}
}
),
/* @__PURE__ */ v("div", { className: "kos-flex kos-items-center kos-gap-2 kos-flex-shrink-0", children: [
/* @__PURE__ */ n(
"button",
{
type: "button",
onClick: a,
disabled: s.isStreaming || !k(),
className: `kos-w-11 kos-h-11 kos-inline-flex kos-items-center kos-justify-center kos-rounded-full kos-transition-colors ${s.recording === "recording" ? "kos-bg-red-500 kos-text-white kos-animate-pulse kos-cursor-pointer" : "kos-bg-gray-700 kos-hover-bg-gray-600 kos-text-white kos-cursor-pointer"}`,
children: s.recording === "recording" ? /* @__PURE__ */ n(_, { size: 20 }) : /* @__PURE__ */ n(Z, { size: 20 })
}
),
/* @__PURE__ */ n(
"button",
{
type: "submit",
disabled: !o.trim() || s.isStreaming || !k(),
className: "kos-w-11 kos-h-11 kos-inline-flex kos-items-center kos-justify-center kos-bg-blue-500 kos-text-white kos-rounded-full kos-cursor-pointer kos-hover-bg-blue-600 kos-transition-colors",
children: /* @__PURE__ */ n(Y, { size: 20 })
}
)
] })
]
}
);
}, le = ({ messages: s }) => {
const k = x(null), [l, i] = f(!1), d = M(() => {
const o = /* @__PURE__ */ new Map();
return s.forEach((e) => {
e.id ? o.set(e.id, e) : o.set(Symbol("unique-msg"), e);
}), Array.from(o.values());
}, [s]);
return y(() => {
k.current && !l && (k.current.scrollTop = k.current.scrollHeight);
}, [d, l]), /* @__PURE__ */ n(
"div",
{
ref: k,
onScroll: () => {
if (k.current) {
const { scrollTop: o, scrollHeight: e, clientHeight: p } = k.current, a = e - o - p < 10;
i(!a);
}
},
className: "klever-one-sdk kos-flex-1 kos-overflow-y-auto kos-space-y-4 kos-pr-2 kos-scroll-smooth",
children: d.map((o, e) => /* @__PURE__ */ n(
"div",
{
className: `kos-flex kos-items-end kos-gap-2 ${o.role === "user" ? "kos-justify-end" : "kos-justify-start"}`,
children: /* @__PURE__ */ n(
"div",
{
className: `kos-px-4 kos-py-2 kos-rounded-2xl kos-max-w-xs kos-break-words kos-whitespace-pre-wrap ${o.role === "user" ? "kos-bg-blue-600 kos-text-white kos-rounded-br-none" : "kos-bg-gray-700 kos-text-white kos-rounded-bl-none"}`,
children: /* @__PURE__ */ n("span", { className: "kos-text-sm kos-break-words", children: o.fullContent || o.content })
}
)
},
o.id || `msg-${e}`
))
}
);
}, ie = ({
apiKey: s,
width: k = 800,
className: l = ""
}) => {
const i = x(null), d = M(() => typeof document < "u" ? document.createElement("div") : {}, []), g = M(
() => ({
onReady: () => /* @__PURE__ */ console.log("디지털 휴먼 준비 완료!"),
onMessageReceived: (a) => /* @__PURE__ */ console.log("받은 메시지:", a),
onError: (a) => alert(a?.message || "오류가 발생했습니다.")
}),
[]
), o = X({
apiKey: s,
container: i.current || d,
callbacks: g
});
y(() => () => {
if (o.client)
try {
o.disconnect();
} catch {
}
}, [o.client]);
const e = async () => {
if (i.current && o.client)
try {
await o.connect();
} catch {
}
}, p = () => {
o.client && o.disconnect();
};
return /* @__PURE__ */ v("div", { className: `klever-one-sdk kos-flex kos-gap-4 ${l}`, children: [
/* @__PURE__ */ v(
"div",
{
className: "kos-flex kos-flex-col kos-gap-4",
style: { width: `${k}px` },
children: [
/* @__PURE__ */ v(
"div",
{
className: "kos-relative kos-bg-black kos-rounded-lg",
style: { height: "400px" },
children: [
/* @__PURE__ */ n(
"div",
{
ref: i,
className: "kos-w-full kos-h-full kos-rounded-lg"
}
),
/* @__PURE__ */ v("div", { className: "kos-absolute kos-top-0 kos-left-0 kos-w-full kos-h-full kos-p-4 kos-flex kos-justify-between kos-items-start pointer-events-none", children: [
/* @__PURE__ */ n(re, { state: o.state }),
/* @__PURE__ */ n("div", { className: "pointer-events-auto", children: /* @__PURE__ */ n(
te,
{
state: o.state,
connect: e,
disconnect: p
}
) })
] })
]
}
),
/* @__PURE__ */ n(
ke,
{
state: o.state,
isReady: o.isReady,
sendText: o.sendText,
startRecording: o.startRecording,
stopRecording: o.stopRecording
}
)
]
}
),
/* @__PURE__ */ n(
"div",
{
className: "kos-flex kos-flex-col kos-bg-gray-100 kos-rounded-lg kos-p-4",
style: { minWidth: "384px" },
children: /* @__PURE__ */ n(le, { messages: o.messages })
}
)
] });
}, ue = ({
apiKey: s
}) => {
const [k, l] = f(!1);
return /* @__PURE__ */ n("div", { className: "klever-one-sdk kos-p-4", children: /* @__PURE__ */ n(
ie,
{
apiKey: s,
width: 800,
isFullscreen: k,
onToggleFullscreen: () => l(!k),
className: "kos-max-w-4xl kos-mx-auto"
}
) });
};
export {
re as ConnectionStatusIndicator,
te as ConnectionToggleButton,
J as KleverOneClient,
ke as MessageInput,
le as MessageList,
ie as UnifiedConversation,
ue as UnifiedConversationExample,
X as useKleverOneClient
};