@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
JavaScript
"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
};