UNPKG

@klever-one/web-sdk

Version:

Web SDK for integrating real-time room management and streaming functionality into web applications

1,190 lines (1,162 loc) 42.3 kB
"use client"; import { useRef as z, useState as m, useEffect as R, useCallback as d, useMemo as V } from "react"; import { KleverOneClient as _ } from "../core/klever-one-core-v0.1.0-beta.15.es.js"; import { jsx as o, jsxs as a } from "react/jsx-runtime"; const ee = ` /* 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-gray-800, .klever-one-sdk .kos-bg-gray-800 { background-color: #1f2937; } .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-yellow-600, .klever-one-sdk .kos-bg-yellow-600 { background-color: #d97706; } .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); } } /* TTS (Text-to-Speech) Components */ .klever-one-sdk .kos-tts-tab { flex: 1; padding: 0.5rem 1rem; font-size: 0.875rem; font-weight: 500; color: #4b5563; background-color: #ffffff; border: 1px solid #d1d5db; border-radius: 0.375rem; cursor: pointer; transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); } .klever-one-sdk .kos-tts-tab:hover { background-color: #f9fafb; border-color: #9ca3af; } .klever-one-sdk .kos-tts-tab-active { color: #ffffff; background-color: #3b82f6; border-color: #3b82f6; } .klever-one-sdk .kos-tts-tab-active:hover { background-color: #2563eb; border-color: #2563eb; } .klever-one-sdk .kos-tts-textarea { width: 100%; padding: 0.75rem; font-size: 0.875rem; line-height: 1.5; color: #1f2937; background-color: #ffffff; border: 1px solid #d1d5db; border-radius: 0.375rem; resize: vertical; outline: none; transition: border-color 150ms cubic-bezier(0.4, 0, 0.2, 1); box-sizing: border-box; max-width: 100%; } .klever-one-sdk .kos-tts-textarea:focus { border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); } .klever-one-sdk .kos-tts-textarea:disabled { background-color: #f3f4f6; color: #9ca3af; cursor: not-allowed; } .klever-one-sdk .kos-tts-textarea::placeholder { color: #9ca3af; opacity: 1; } .klever-one-sdk .kos-tts-button { width: 100%; padding: 0.625rem 1rem; font-size: 0.875rem; font-weight: 500; color: #ffffff; background-color: #3b82f6; border: none; border-radius: 0.375rem; cursor: pointer; transition: background-color 150ms cubic-bezier(0.4, 0, 0.2, 1); } .klever-one-sdk .kos-tts-button:hover:not(:disabled) { background-color: #2563eb; } .klever-one-sdk .kos-tts-button:disabled { background-color: #9ca3af; cursor: not-allowed; opacity: 0.6; } .klever-one-sdk .kos-mb-3 { margin-bottom: 0.75rem; } .klever-one-sdk .kos-text-lg { font-size: 1.125rem; line-height: 1.75rem; } .klever-one-sdk .kos-font-semibold { font-weight: 600; } .klever-one-sdk .kos-text-gray-800 { color: #1f2937; } /* Volume Control */ .klever-one-sdk .kos-volume-control { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; background: rgba(0, 0, 0, 0.7); border-radius: 20px; backdrop-filter: blur(10px); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); transition: all 0.2s ease; border: 1px solid rgba(255, 255, 255, 0.1); } .klever-one-sdk .kos-volume-control:hover { background: rgba(0, 0, 0, 0.8); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); } .klever-one-sdk .kos-volume-slider { width: 100px; height: 4px; -webkit-appearance: none; appearance: none; background: transparent; outline: none; cursor: pointer; position: relative; } .klever-one-sdk .kos-volume-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 14px; height: 14px; border-radius: 50%; background: #ffffff; cursor: pointer; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4); transition: all 0.2s ease; border: 2px solid #3b82f6; margin-top: -5px; } .klever-one-sdk .kos-volume-slider::-webkit-slider-thumb:hover { transform: scale(1.15); box-shadow: 0 3px 10px rgba(59, 130, 246, 0.5); } .klever-one-sdk .kos-volume-slider::-webkit-slider-thumb:active { transform: scale(1.05); } .klever-one-sdk .kos-volume-slider::-webkit-slider-runnable-track { width: 100%; height: 4px; border-radius: 2px; background: linear-gradient(to right, #3b82f6 0%, #3b82f6 var(--volume-percent, 100%), rgba(255, 255, 255, 0.2) var(--volume-percent, 100%), rgba(255, 255, 255, 0.2) 100%); } .klever-one-sdk .kos-volume-slider::-moz-range-thumb { width: 14px; height: 14px; border: 2px solid #3b82f6; border-radius: 50%; background: #ffffff; cursor: pointer; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4); transition: all 0.2s ease; } .klever-one-sdk .kos-volume-slider::-moz-range-thumb:hover { transform: scale(1.15); box-shadow: 0 3px 10px rgba(59, 130, 246, 0.5); } .klever-one-sdk .kos-volume-slider::-moz-range-thumb:active { transform: scale(1.05); } .klever-one-sdk .kos-volume-slider::-moz-range-track { width: 100%; height: 4px; border-radius: 2px; background: rgba(255, 255, 255, 0.2); } .klever-one-sdk .kos-volume-slider::-moz-range-progress { height: 4px; border-radius: 2px; background: #3b82f6; } .klever-one-sdk .kos-volume-percent { font-size: 11px; font-weight: 600; color: #ffffff; width: 42px; min-width: 42px; text-align: right; user-select: none; font-variant-numeric: tabular-nums; flex-shrink: 0; } /* Control Buttons (Reset, Zoom, etc.) */ .klever-one-sdk .kos-control-btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; padding: 8px 16px; font-size: 13px; font-weight: 500; border-radius: 20px; border: none; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); backdrop-filter: blur(10px); white-space: nowrap; user-select: none; } .klever-one-sdk .kos-control-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); } .klever-one-sdk .kos-control-btn:active { transform: translateY(0); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); } .klever-one-sdk .kos-control-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none !important; } .klever-one-sdk .kos-reset-btn { background: linear-gradient(135deg, #f97316 0%, #ea580c 100%); color: #ffffff; border: 1px solid rgba(255, 255, 255, 0.2); } .klever-one-sdk .kos-reset-btn:hover:not(:disabled) { background: linear-gradient(135deg, #ea580c 0%, #c2410c 100%); } .klever-one-sdk .kos-zoom-btn { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); color: #ffffff; border: 1px solid rgba(255, 255, 255, 0.2); padding: 8px 12px; min-width: 90px; } .klever-one-sdk .kos-zoom-btn:hover:not(:disabled) { background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%); } .klever-one-sdk .kos-connection-btn { width: 44px; height: 44px; min-width: 44px; min-height: 44px; padding: 0; display: flex; align-items: center; justify-content: center; border-radius: 50%; border: none; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); flex-shrink: 0; } .klever-one-sdk .kos-connection-btn:hover { transform: scale(1.05); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); } .klever-one-sdk .kos-connection-btn:active { transform: scale(0.98); } /* 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 P = !1; function L() { if (P || typeof document > "u") return; const n = document.createElement("style"); n.id = "klever-one-sdk-styles", n.textContent = ee, document.head && (document.head.appendChild(n), P = !0); } typeof document < "u" && (document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", L) : L()), !0; let K = 0; function oe(n) { const { apiKey: k, container: c, callbacks: i, conversation: u, ...b } = n, r = z(i); r.current = i; const e = z(null), [h, p] = m({ connection: "disconnected", recording: "idle", isStreaming: !1, isStreamingReady: !1, isConversationReady: !1, lastUpdated: /* @__PURE__ */ new Date() }), [v, C] = m({ reconnectAttempts: 0, messagesSent: 0, messagesReceived: 0, recordingSessions: 0, errorCount: 0 }), [N, S] = m({ messages: [], isStreaming: !1, isCompleted: !1 }), [s, w] = m([]); R(() => { try { const t = new _({ apiKey: k, container: c, conversation: u, ...b, callbacks: { ...r.current, // 기존 콜백과 상태 업데이트를 결합 onConnectionStatusChange: (l) => { p((f) => ({ ...f, connection: l })), r.current?.onConnectionStatusChange?.(l); }, onRecordingStatusChange: (l) => { p((f) => ({ ...f, recording: l })), r.current?.onRecordingStatusChange?.(l); }, onStreamingStatusChange: (l) => { p((f) => ({ ...f, isStreaming: l })), r.current?.onStreamingStatusChange?.(l); }, onMessageReceived: (l) => { w((f) => { const $ = f.findIndex((M) => M.id === l.id); if ($ >= 0) { const M = [...f]; return M[$] = l, M; } else return [...f, l]; }), r.current?.onMessageReceived?.(l); }, onReady: () => { p((l) => ({ ...l, isStreamingReady: !0, isConversationReady: !0 })), r.current?.onReady?.(); }, onDisconnect: () => { p({ connection: "disconnected", recording: "idle", isStreaming: !1, isStreamingReady: !1, isConversationReady: !1, lastUpdated: /* @__PURE__ */ new Date() }), w([]), r.current?.onDisconnect?.(); }, onError: (l) => { C((f) => ({ ...f, errorCount: f.errorCount + 1, lastErrorTime: /* @__PURE__ */ new Date() })), r.current?.onError?.(l); }, onRoomInfoUpdated: (l) => { r.current?.onRoomInfoUpdated?.(l); }, onLog: (l) => { r.current?.onLog?.(l); }, onRoomSessionTimeout: (l) => { r.current?.onRoomSessionTimeout?.(l); }, onLipMotionStart: () => { r.current?.onLipMotionStart?.(); } } }); e.current = t, K++, p(t.getState()), C(t.getMetrics()), S(t.getConversationState()), w(t.getMessages()); } catch { } return () => { K--, K === 0 && e.current && e.current.getState().connection !== "disconnected" && e.current.disconnect(); }; }, [k, c]), R(() => { if (!e.current) return; const l = setInterval(() => { e.current && e.current.getState().connection !== "disconnected" && (p(e.current.getState()), C(e.current.getMetrics()), S(e.current.getConversationState()), w(e.current.getMessages())); }, 1e3); return () => clearInterval(l); }, []); const T = d(async () => { if (e.current) return e.current.connect(); throw new Error("KleverOneClient not initialized"); }, []), I = d(() => { e.current && e.current.disconnect(); }, []), j = d(async () => { if (e.current) return e.current.reconnect(); throw new Error("KleverOneClient not initialized"); }, []), O = d(async (t) => { if (e.current) return e.current.sendText(t); throw new Error("KleverOneClient not initialized"); }, []), A = d(async () => { if (e.current) return e.current.startRecording(); throw new Error("KleverOneClient not initialized"); }, []), E = d(async () => { if (e.current) return e.current.stopRecording(); throw new Error("KleverOneClient not initialized"); }, []), D = d(() => e.current ? e.current.isReady() : !1, []), g = d(() => e.current ? e.current.isRecording() : !1, []), x = d((t, l) => { e.current && e.current.resize(t, l); }, []), B = d((t) => { e.current && e.current.sendAvatarNum(t); }, []), U = d((t) => { e.current && e.current.sendAvatarAppearanceChange(t); }, []), Z = d((t) => { e.current && e.current.sendPlaceBackgroundChange(t); }, []), H = d((t) => { e.current && e.current.sendVoiceSetting(t); }, []), W = d( (t) => { e.current && e.current.sendMessage(t); }, [] ), F = d( async (t) => { if (e.current) return e.current.sendDataInChunks(t); throw new Error("KleverOneClient not initialized"); }, [] ), q = d( ((t) => { e.current && (Array.isArray(t), e.current.speak(t)); }), [] ), Y = d((t) => { e.current && e.current.setVolume(t); }, []), G = d(() => e.current ? e.current.getVolume() : 1, []), J = d(() => { e.current && (e.current.resetConversation(), w([]), S({ messages: [], isStreaming: !1, isCompleted: !1 })); }, []), Q = d(() => { e.current && e.current.sendZoomIn(); }, []), X = d(() => { e.current && e.current.sendZoomOut(); }, []); return { client: e.current, state: h, metrics: v, conversationState: N, messages: s, connect: T, disconnect: I, resetConversation: J, reconnect: j, sendText: O, speak: q, startRecording: A, stopRecording: E, isReady: D, isRecording: g, // 고급 기능들 resize: x, sendAvatarNum: B, sendAvatarAppearanceChange: U, sendPlaceBackgroundChange: Z, sendVoiceSetting: H, setVolume: Y, getVolume: G, sendZoomIn: Q, sendZoomOut: X, sendMessage: W, sendDataInChunks: F }; } const y = ({ size: n = 24, color: k = "currentColor", stroke: c = 2, className: i = "", style: u, children: b, name: r }) => /* @__PURE__ */ o( "svg", { width: n, height: n, viewBox: "0 0 24 24", fill: "none", stroke: k, strokeWidth: c, strokeLinecap: "round", strokeLinejoin: "round", className: i, style: { display: "block", ...u }, role: "img", "aria-label": r, children: b } ), ne = (n) => /* @__PURE__ */ a( y, { name: "Send", ...n, children: [ /* @__PURE__ */ o("path", { d: "M10 14l11 -11" }), /* @__PURE__ */ o("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" }) ] } ), re = (n) => /* @__PURE__ */ a( y, { name: "Microphone", ...n, children: [ /* @__PURE__ */ o("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__ */ o("path", { d: "M5 10a7 7 0 0 0 14 0" }), /* @__PURE__ */ o("path", { d: "M8 21l8 0" }), /* @__PURE__ */ o("path", { d: "M12 17l0 4" }) ] } ), se = (n) => /* @__PURE__ */ o( y, { name: "PlayerStop", ...n, children: /* @__PURE__ */ o("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" }) } ), te = (n) => /* @__PURE__ */ a( y, { name: "PhoneCall", ...n, children: [ /* @__PURE__ */ o("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__ */ o("path", { d: "M15 7a2 2 0 0 1 2 2" }), /* @__PURE__ */ o("path", { d: "M15 3a6 6 0 0 1 6 6" }) ] } ), le = (n) => /* @__PURE__ */ a( y, { name: "PhoneOff", ...n, children: [ /* @__PURE__ */ o("path", { d: "M3 21l18 -18" }), /* @__PURE__ */ o("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" }) ] } ), ke = (n) => /* @__PURE__ */ a( y, { name: "Wifi", ...n, children: [ /* @__PURE__ */ o("path", { d: "M12 18l.01 0" }), /* @__PURE__ */ o("path", { d: "M9.172 15.172a4 4 0 0 1 5.656 0" }), /* @__PURE__ */ o("path", { d: "M6.343 12.343a8 8 0 0 1 11.314 0" }), /* @__PURE__ */ o("path", { d: "M3.515 9.515c4.686 -4.687 12.284 -4.687 17 0" }) ] } ), ae = (n) => /* @__PURE__ */ a( y, { name: "WifiOff", ...n, children: [ /* @__PURE__ */ o("path", { d: "M12 18l.01 0" }), /* @__PURE__ */ o("path", { d: "M9.172 15.172a4 4 0 0 1 5.656 0" }), /* @__PURE__ */ o("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__ */ o("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__ */ o("path", { d: "M3 3l18 18" }) ] } ), ie = ({ state: n }) => { const k = n.connection === "connected", c = n.connection === "connecting", i = n.connection === "allocating", u = k ? "kos-text-green-400" : c || i ? "kos-text-yellow-400" : "kos-text-red-400", b = k ? "연결됨" : i ? "할당 중..." : c ? "연결 중..." : "연결 안됨", r = k || c || i ? ke : ae; return /* @__PURE__ */ a( "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 ${u}`, children: [ /* @__PURE__ */ o( r, { className: `kos-w-4 kos-h-4 ${c || i ? "kos-animate-pulse" : ""}` } ), /* @__PURE__ */ o("span", { children: b }), n.isStreaming && /* @__PURE__ */ o("span", { className: "kos-text-sm kos-text-blue-400", children: "응답 생성 중..." }) ] } ); }, de = ({ state: n, connect: k, disconnect: c }) => { const i = n.connection === "connected", u = n.connection === "connecting", b = n.connection === "allocating"; return /* @__PURE__ */ o( "button", { onClick: () => { i || u || b ? c() : k(); }, className: `klever-one-sdk kos-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" : u || b ? "kos-bg-yellow-500 kos-hover-bg-yellow-600 kos-text-white kos-animate-pulse kos-cursor-pointer" : "kos-bg-green-500 kos-hover-bg-green-600 kos-text-white kos-cursor-pointer"}`, style: { padding: "12px", margin: 0, border: "none", lineHeight: 0 }, children: i || u || b ? /* @__PURE__ */ o(le, { size: 20 }) : /* @__PURE__ */ o(te, { size: 20 }) } ); }, ce = ({ state: n, isReady: k, sendText: c, startRecording: i, stopRecording: u }) => { const b = z(null), [r, e] = m(""), h = async (v) => { v.preventDefault(), !(!r.trim() || n.isStreaming) && (await c(r), e("")); }, p = async () => { try { n.recording === "recording" ? await u() : await i(); } catch { } }; return /* @__PURE__ */ a( "form", { onSubmit: h, className: "klever-one-sdk kos-w-full kos-flex kos-items-stretch kos-gap-4", children: [ /* @__PURE__ */ o( "textarea", { ref: b, className: "kos-flex-1 kos-min-w-0 kos-h-20 kos-bg-gray-700 kos-text-white kos-p-3 kos-rounded-lg kos-resize-none kos-outline-none kos-overflow-y-auto kos-transition-all", placeholder: "메시지를 입력하세요...", value: r, onChange: (v) => e(v.target.value), disabled: n.isStreaming, onKeyDown: (v) => { v.key === "Enter" && !v.shiftKey && (v.preventDefault(), h(v)); } } ), /* @__PURE__ */ a("div", { className: "kos-flex kos-items-center kos-gap-2 kos-flex-shrink-0", children: [ /* @__PURE__ */ o( "button", { type: "button", onClick: p, disabled: n.isStreaming || !k(), className: `kos-flex kos-items-center kos-justify-center kos-rounded-full kos-transition-colors ${n.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"}`, style: { padding: "12px", margin: 0, border: "none", lineHeight: 0 }, children: n.recording === "recording" ? /* @__PURE__ */ o(se, { size: 20 }) : /* @__PURE__ */ o(re, { size: 20 }) } ), /* @__PURE__ */ o( "button", { type: "submit", disabled: !r.trim() || n.isStreaming || !k(), className: "kos-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", style: { padding: "12px", margin: 0, border: "none", lineHeight: 0 }, children: /* @__PURE__ */ o(ne, { size: 20 }) } ) ] }) ] } ); }, ue = ({ messages: n }) => { const k = z(null), [c, i] = m(!1), u = V(() => { const r = /* @__PURE__ */ new Map(); return n.forEach((e) => { e.id ? r.set(e.id, e) : r.set(Symbol("unique-msg"), e); }), Array.from(r.values()); }, [n]); return R(() => { k.current && !c && (k.current.scrollTop = k.current.scrollHeight); }, [u, c]), /* @__PURE__ */ o( "div", { ref: k, onScroll: () => { if (k.current) { const { scrollTop: r, scrollHeight: e, clientHeight: h } = k.current, p = e - r - h < 10; i(!p); } }, className: "klever-one-sdk kos-flex-1 kos-overflow-y-auto kos-space-y-4 kos-pr-2 kos-scroll-smooth", children: u.map((r, e) => /* @__PURE__ */ o( "div", { className: `kos-flex kos-items-end kos-gap-2 ${r.role === "user" ? "kos-justify-start" : "kos-justify-end"}`, children: /* @__PURE__ */ o( "div", { className: `kos-px-4 kos-py-2 kos-rounded-2xl kos-max-w-xs kos-break-words kos-whitespace-pre-wrap ${r.role === "user" ? "kos-bg-blue-600 kos-text-white kos-rounded-bl-none" : "kos-bg-gray-800 kos-text-white kos-rounded-br-none"}`, children: /* @__PURE__ */ o("span", { className: "kos-text-sm kos-break-words", children: r.fullContent || r.content }) } ) }, r.id || `msg-${e}` )) } ); }, ve = ({ apiKey: n, width: k = 800, className: c = "" }) => { const i = z(null), [u, b] = m("single"), [r, e] = m(""), [h, p] = m(""), [v, C] = m(1), N = V(() => typeof document < "u" ? document.createElement("div") : {}, []), S = V( () => ({ onReady: () => /* @__PURE__ */ console.log("디지털 휴먼 준비 완료!"), onMessageReceived: (g) => /* @__PURE__ */ console.log("받은 메시지:", g), onError: (g) => alert(g?.message || "오류가 발생했습니다."), onLipMotionStart: () => /* @__PURE__ */ console.log("아바타 발화 시작!") }), [] ), s = oe({ apiKey: n, container: i.current || N, callbacks: S }); R(() => () => { if (s.client) try { s.disconnect(); } catch { } }, [s.client]); const w = async () => { if (i.current && s.client) try { await s.connect(); } catch { } }, T = () => { s.client && s.disconnect(); }, I = () => { s.client && s.resetConversation(); }, j = () => { r.trim() && s.client && (s.speak(r.trim()), e("")); }, O = () => { if (h.trim() && s.client) { const g = h.split(` `).map((x) => x.trim()).filter((x) => x.length > 0); g.length > 0 && (s.speak(g), p("")); } }, A = (g) => { const x = parseFloat(g.target.value); C(x), s.setVolume(x); }, E = () => { s.client && s.sendZoomIn(); }, D = () => { s.client && s.sendZoomOut(); }; return /* @__PURE__ */ a("div", { className: `klever-one-sdk kos-flex kos-gap-4 ${c}`, children: [ /* @__PURE__ */ a( "div", { className: "kos-flex kos-flex-col kos-gap-4", style: { width: `${k}px` }, children: [ /* @__PURE__ */ a( "div", { className: "kos-relative kos-bg-black kos-rounded-lg", style: { height: "400px" }, children: [ /* @__PURE__ */ o( "div", { ref: i, className: "kos-w-full kos-h-full kos-rounded-lg" } ), /* @__PURE__ */ a("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__ */ o(ie, { state: s.state }), /* @__PURE__ */ a("div", { className: "kos-flex kos-flex-col kos-gap-2 kos-items-end pointer-events-auto", children: [ /* @__PURE__ */ o( de, { state: s.state, connect: w, disconnect: T } ), s.state.connection === "connected" && /* @__PURE__ */ a("div", { className: "kos-flex kos-flex-col kos-gap-2", children: [ /* @__PURE__ */ o( "button", { onClick: I, className: "kos-control-btn kos-reset-btn", title: "대화 초기화", children: "대화 초기화" } ), /* @__PURE__ */ a("div", { className: "kos-volume-control", children: [ /* @__PURE__ */ o( "input", { type: "range", min: "0", max: "1", step: "0.01", value: v, onChange: A, className: "kos-volume-slider", title: `볼륨: ${Math.round(v * 100)}%`, style: { "--volume-percent": `${v * 100}%` } } ), /* @__PURE__ */ a("span", { className: "kos-volume-percent", children: [ Math.round(v * 100), "%" ] }) ] }), /* @__PURE__ */ a("div", { className: "kos-flex kos-gap-2", children: [ /* @__PURE__ */ o( "button", { onClick: E, className: "kos-control-btn kos-zoom-btn", title: "줌 인", children: "🔍+ 줌 인" } ), /* @__PURE__ */ o( "button", { onClick: D, className: "kos-control-btn kos-zoom-btn", title: "줌 아웃", children: "🔍- 줌 아웃" } ) ] }) ] }) ] }) ] }) ] } ), /* @__PURE__ */ o( ce, { state: s.state, isReady: s.isReady, sendText: s.sendText, startRecording: s.startRecording, stopRecording: s.stopRecording } ), /* @__PURE__ */ a("div", { className: "kos-bg-gray-100 kos-rounded-lg kos-p-4", children: [ /* @__PURE__ */ o("div", { className: "kos-flex kos-items-center kos-gap-2 kos-mb-3", children: /* @__PURE__ */ o("h3", { className: "kos-text-sm kos-font-semibold kos-text-gray-800", children: "말하기" }) }), /* @__PURE__ */ a("div", { className: "kos-flex kos-gap-2 kos-mb-3", children: [ /* @__PURE__ */ o( "button", { className: `kos-tts-tab ${u === "single" ? "kos-tts-tab-active" : ""}`, onClick: () => b("single"), children: "한 문장" } ), /* @__PURE__ */ o( "button", { className: `kos-tts-tab ${u === "array" ? "kos-tts-tab-active" : ""}`, onClick: () => b("array"), children: "여러 문장" } ) ] }), u === "single" ? /* @__PURE__ */ a("div", { className: "kos-flex kos-flex-col kos-gap-2", children: [ /* @__PURE__ */ o( "textarea", { className: "kos-tts-textarea", placeholder: "아바타가 말할 내용...", rows: 2, value: r, onChange: (g) => e(g.target.value), disabled: !s.isReady() } ), /* @__PURE__ */ o( "button", { className: "kos-tts-button", onClick: j, disabled: !s.isReady() || !r.trim(), children: "한 문장 전송" } ) ] }) : /* @__PURE__ */ a("div", { className: "kos-flex kos-flex-col kos-gap-2", children: [ /* @__PURE__ */ o( "textarea", { className: "kos-tts-textarea", placeholder: "한 줄에 하나씩 입력...", rows: 3, value: h, onChange: (g) => p(g.target.value), disabled: !s.isReady() } ), /* @__PURE__ */ o( "button", { className: "kos-tts-button", onClick: O, disabled: !s.isReady() || !h.trim(), children: "여러 문장 전송" } ) ] }) ] }) ] } ), /* @__PURE__ */ o( "div", { className: "kos-flex kos-flex-col kos-bg-gray-100 kos-rounded-lg kos-p-4", style: { minWidth: "384px", height: "496px" }, children: /* @__PURE__ */ o(ue, { messages: s.messages }) } ) ] }); }, fe = ({ apiKey: n }) => { const [k, c] = m(!1); return /* @__PURE__ */ o("div", { className: "klever-one-sdk kos-p-4", children: /* @__PURE__ */ o( ve, { apiKey: n, width: 800, isFullscreen: k, onToggleFullscreen: () => c(!k), className: "kos-max-w-4xl kos-mx-auto" } ) }); }; export { ie as ConnectionStatusIndicator, de as ConnectionToggleButton, _ as KleverOneClient, ce as MessageInput, ue as MessageList, ve as UnifiedConversation, fe as UnifiedConversationExample, oe as useKleverOneClient };