vibrium-speak-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/FloatingMic.tsx","../src/components/VoicePannel.tsx","../src/providers/LiveKitProvider.tsx","../src/services/auth.service.ts","../src/services/token.service.ts","../src/services/livekit.service.ts","../src/utils/audio.ts","../src/services/action-registry.ts","../src/hooks/useTranscriptSync.ts","../src/index.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport {\r\n useEffect,\r\n useState,\r\n useMemo,\r\n} from \"react\";\r\nimport { Mic } from \"lucide-react\";\r\nimport VoicePanel from \"./VoicePannel\";\r\nimport {\r\n LiveKitProvider,\r\n useVoiceAssistant,\r\n} from \"../providers/LiveKitProvider\";\r\nimport { FloatingMicProps } from \"../types/sdk.types\";\r\n\r\n/* =============================================================================\r\n * INTERNAL COMPONENT\r\n * =============================================================================\r\n */\r\n\r\nfunction FloatingMicInner({\r\n textEnabled = false,\r\n}: {\r\n textEnabled?: boolean;\r\n}) {\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Voice SDK\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const {\r\n connected,\r\n connecting,\r\n reconnecting,\r\n micEnabled,\r\n messages,\r\n agentState,\r\n connect,\r\n disconnect,\r\n toggleMic,\r\n setSpeakerMuted: setLiveKitSpeakerMuted,\r\n sendText,\r\n connectionState,\r\n } = useVoiceAssistant();\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * UI state\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const [showVoicePanel, setShowVoicePanel] = useState(false);\r\n const [micMuted, setMicMuted] = useState(false);\r\n const [speakerMuted, setSpeakerMuted] = useState(true);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Sync mic state\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n useEffect(() => {\r\n const desired =\r\n !micMuted;\r\n\r\n if (\r\n desired !== micEnabled\r\n ) {\r\n toggleMic();\r\n }\r\n }, [micMuted]);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Speaker mute\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n useEffect(() => {\r\n setLiveKitSpeakerMuted(speakerMuted);\r\n }, [\r\n speakerMuted,\r\n setLiveKitSpeakerMuted,\r\n ]);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Enable voice\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const enableVoice =\r\n async () => {\r\n if (\r\n connecting ||\r\n connected\r\n ) {\r\n return;\r\n }\r\n\r\n try {\r\n await connect();\r\n setShowVoicePanel(\r\n true\r\n );\r\n } catch (err) {\r\n console.error(err);\r\n }\r\n };\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Disable voice\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const disableVoice =\r\n async () => {\r\n await disconnect();\r\n\r\n setShowVoicePanel(\r\n false\r\n );\r\n\r\n setMicMuted(false);\r\n\r\n setSpeakerMuted(true);\r\n };\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Toggle panel\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const toggleVoicePanel =\r\n () => {\r\n if (!connected) {\r\n enableVoice();\r\n\r\n return;\r\n }\r\n\r\n setShowVoicePanel(\r\n (prev) => !prev\r\n );\r\n };\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Floating button state\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const buttonState =\r\n useMemo(() => {\r\n if (reconnecting) {\r\n return \"reconnecting\";\r\n }\r\n\r\n if (connecting) {\r\n return \"connecting\";\r\n }\r\n\r\n if (connected) {\r\n return \"connected\";\r\n }\r\n\r\n return \"idle\";\r\n }, [\r\n connected,\r\n connecting,\r\n reconnecting,\r\n ]);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Tooltip\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const tooltip =\r\n (() => {\r\n switch (\r\n buttonState\r\n ) {\r\n case \"connecting\":\r\n return \"Connecting...\";\r\n\r\n case \"reconnecting\":\r\n return \"Reconnecting...\";\r\n\r\n case \"connected\":\r\n return \"Voice connected\";\r\n\r\n default:\r\n return \"Click to enable voice\";\r\n }\r\n })();\r\n\r\n return (\r\n <>\r\n {/* =====================================================================\r\n * Floating Mic\r\n * ===================================================================== */}\r\n\r\n <button\r\n onClick={\r\n toggleVoicePanel\r\n }\r\n disabled={\r\n connecting\r\n }\r\n className=\"fixed bottom-6 right-6 z-[1000] w-14 h-14 rounded-full bg-gradient-to-br from-blue-500 to-blue-700 text-white flex items-center justify-center shadow-lg transition-all duration-300 hover:scale-110 disabled:opacity-50 disabled:cursor-not-allowed\"\r\n title={tooltip}\r\n >\r\n {/* Glow/Pulse rings depending on status */}\r\n {connected && agentState === \"listening\" && (\r\n <span className=\"absolute -inset-2 rounded-full bg-green-500/25 animate-ping pointer-events-none\" />\r\n )}\r\n {connected && agentState === \"speaking\" && (\r\n <span className=\"absolute -inset-2 rounded-full bg-blue-500/25 animate-ping pointer-events-none\" />\r\n )}\r\n {connected && agentState === \"thinking\" && (\r\n <span className=\"absolute -inset-1 rounded-full bg-yellow-500/20 animate-pulse pointer-events-none\" />\r\n )}\r\n\r\n {/* If panel is open, show an active ring border */}\r\n {showVoicePanel && (\r\n <span className=\"absolute inset-0 rounded-full ring-4 ring-blue-500/35 transition-all duration-300 pointer-events-none\" />\r\n )}\r\n\r\n <Mic className={`w-5 h-5 transition-transform duration-300 ${connected ? \"scale-110\" : \"\"}`} />\r\n </button>\r\n\r\n {/* =====================================================================\r\n * Voice Panel\r\n * ===================================================================== */}\r\n\r\n {showVoicePanel && (\r\n <VoicePanel\r\n enabled={connected}\r\n connectionState={\r\n connectionState as any\r\n }\r\n agentState={\r\n agentState\r\n }\r\n messages={\r\n messages\r\n }\r\n participants={\r\n []\r\n }\r\n onDisable={\r\n disableVoice\r\n }\r\n textEnabled={\r\n textEnabled\r\n }\r\n micMuted={\r\n micMuted\r\n }\r\n speakerMuted={\r\n speakerMuted\r\n }\r\n onMicMutedChange={\r\n setMicMuted\r\n }\r\n onSpeakerMutedChange={\r\n setSpeakerMuted\r\n }\r\n onSendText={\r\n sendText\r\n }\r\n />\r\n )}\r\n </>\r\n );\r\n}\r\n\r\n/* =============================================================================\r\n * PROVIDER WRAPPER\r\n * =============================================================================\r\n */\r\n\r\nexport default function FloatingMic({\r\n config,\r\n textEnabled = false,\r\n}: FloatingMicProps) {\r\n console.log(\"FloatingMic Config\", config);\r\n return (\r\n <LiveKitProvider\r\n config={{\r\n ...config,\r\n }}\r\n >\r\n <FloatingMicInner\r\n textEnabled={\r\n textEnabled\r\n }\r\n />\r\n </LiveKitProvider>\r\n );\r\n}","\"use client\";\r\n\r\nimport {\r\n useState,\r\n useRef,\r\n useEffect,\r\n memo,\r\n useMemo,\r\n} from \"react\";\r\n\r\nimport {\r\n Mic,\r\n X,\r\n ChevronRight,\r\n SendHorizontal,\r\n Volume2,\r\n VolumeX,\r\n MicOff,\r\n} from \"lucide-react\";\r\n\r\nimport React from \"react\";\r\n\r\nimport {\r\n ConversationMessage,\r\n} from \"../types/sdk.types\";\r\n\r\n/* =============================================================================\r\n * MARKDOWN RENDERING\r\n * =============================================================================\r\n */\r\n\r\nfunction renderInline(text: string) {\r\n const nodes: (\r\n | string\r\n | React.ReactNode\r\n )[] = [];\r\n\r\n let lastIndex = 0;\r\n\r\n const boldRe =\r\n /\\*\\*(.+?)\\*\\*/g;\r\n\r\n let m: RegExpExecArray | null;\r\n\r\n while (\r\n (m = boldRe.exec(text)) !== null\r\n ) {\r\n const idx = m.index;\r\n\r\n if (idx > lastIndex) {\r\n nodes.push(\r\n text.slice(lastIndex, idx)\r\n );\r\n }\r\n\r\n nodes.push(\r\n <strong key={idx}>\r\n {m[1]}\r\n </strong>\r\n );\r\n\r\n lastIndex =\r\n idx + m[0].length;\r\n }\r\n\r\n if (lastIndex < text.length) {\r\n nodes.push(\r\n text.slice(lastIndex)\r\n );\r\n }\r\n\r\n return nodes;\r\n}\r\n\r\nfunction formatMessage(\r\n text: string\r\n) {\r\n try {\r\n const lines = text.split(\"\\n\");\r\n\r\n const out: React.ReactNode[] =\r\n [];\r\n\r\n let inList: React.ReactElement[] =\r\n [];\r\n\r\n const flushList = (\r\n keyBase: string\r\n ) => {\r\n if (inList.length) {\r\n out.push(\r\n <ul\r\n key={keyBase + \"-ul\"}\r\n className=\"list-disc pl-5 ml-2 space-y-1\"\r\n >\r\n {inList.map(\r\n (li, idx) => (\r\n <li\r\n key={\r\n keyBase +\r\n \"-li-\" +\r\n idx\r\n }\r\n className=\"text-sm\"\r\n >\r\n {li}\r\n </li>\r\n )\r\n )}\r\n </ul>\r\n );\r\n }\r\n\r\n inList = [];\r\n };\r\n\r\n lines.forEach(\r\n (rawLine, idx) => {\r\n const line =\r\n rawLine\r\n .replace(/\\r/g, \"\")\r\n .trimEnd();\r\n\r\n /**\r\n * --------------------------------------------------------------\r\n * Headings\r\n * --------------------------------------------------------------\r\n */\r\n\r\n const hMatch =\r\n line.match(\r\n /^\\s*(#{1,3})\\s*(.*)$/\r\n );\r\n\r\n if (hMatch) {\r\n flushList(\"h\" + idx);\r\n\r\n const level =\r\n hMatch[1].length;\r\n\r\n const content =\r\n hMatch[2];\r\n\r\n const cls =\r\n \"font-semibold\";\r\n\r\n if (level === 1) {\r\n out.push(\r\n <h1\r\n key={\"h1-\" + idx}\r\n className={\r\n \"text-xl \" + cls\r\n }\r\n >\r\n {renderInline(\r\n content\r\n )}\r\n </h1>\r\n );\r\n } else if (\r\n level === 2\r\n ) {\r\n out.push(\r\n <h2\r\n key={\"h2-\" + idx}\r\n className={\r\n \"text-lg \" + cls\r\n }\r\n >\r\n {renderInline(\r\n content\r\n )}\r\n </h2>\r\n );\r\n } else {\r\n out.push(\r\n <h3\r\n key={\"h3-\" + idx}\r\n className={\r\n \"text-base \" + cls\r\n }\r\n >\r\n {renderInline(\r\n content\r\n )}\r\n </h3>\r\n );\r\n }\r\n\r\n return;\r\n }\r\n\r\n /**\r\n * --------------------------------------------------------------\r\n * Bullets\r\n * --------------------------------------------------------------\r\n */\r\n\r\n const bMatch =\r\n line.match(\r\n /^\\s*([-\\*\\.]|\\u2022)\\s+(.*)$/\r\n );\r\n\r\n if (bMatch) {\r\n inList.push(\r\n <>\r\n {renderInline(\r\n bMatch[2]\r\n )}\r\n </>\r\n );\r\n\r\n return;\r\n }\r\n\r\n /**\r\n * --------------------------------------------------------------\r\n * Empty line\r\n * --------------------------------------------------------------\r\n */\r\n\r\n if (\r\n line.trim() === \"\"\r\n ) {\r\n flushList(\r\n \"empty-\" + idx\r\n );\r\n\r\n out.push(\r\n <div\r\n key={\"br-\" + idx}\r\n className=\"my-2\"\r\n />\r\n );\r\n\r\n return;\r\n }\r\n\r\n /**\r\n * --------------------------------------------------------------\r\n * Paragraph\r\n * --------------------------------------------------------------\r\n */\r\n\r\n flushList(\"p-\" + idx);\r\n\r\n out.push(\r\n <div\r\n key={\"p-\" + idx}\r\n className=\"text-sm leading-snug\"\r\n >\r\n {renderInline(line)}\r\n </div>\r\n );\r\n }\r\n );\r\n\r\n if (inList.length) {\r\n out.push(\r\n <ul\r\n key=\"last-ul\"\r\n className=\"list-disc pl-5 ml-2 space-y-1\"\r\n >\r\n {inList.map(\r\n (li, idx) => (\r\n <li\r\n key={\r\n \"last-li-\" +\r\n idx\r\n }\r\n className=\"text-sm\"\r\n >\r\n {li}\r\n </li>\r\n )\r\n )}\r\n </ul>\r\n );\r\n }\r\n\r\n return out;\r\n } catch {\r\n return text;\r\n }\r\n}\r\n\r\n/* =============================================================================\r\n * TYPES\r\n * =============================================================================\r\n */\r\n\r\ninterface Props {\r\n enabled: boolean;\r\n\r\n connectionState:\r\n | \"connected\"\r\n | \"connecting\"\r\n | \"reconnecting\"\r\n | \"disconnected\"\r\n | \"error\";\r\n\r\n agentState?:\r\n | \"idle\"\r\n | \"listening\"\r\n | \"thinking\"\r\n | \"speaking\";\r\n\r\n messages: ConversationMessage[];\r\n\r\n participants?: string[];\r\n\r\n onDisable: () => void;\r\n\r\n textEnabled?: boolean;\r\n\r\n micMuted?: boolean;\r\n\r\n speakerMuted?: boolean;\r\n\r\n onMicMutedChange?: (\r\n muted: boolean\r\n ) => void;\r\n\r\n onSpeakerMutedChange?: (\r\n muted: boolean\r\n ) => void;\r\n\r\n onSendText?: (\r\n text: string\r\n ) => void;\r\n}\r\n\r\n/* =============================================================================\r\n * MESSAGE BUBBLE\r\n * =============================================================================\r\n */\r\n\r\nconst MessageBubble = memo(\r\n ({\r\n message,\r\n }: {\r\n message: ConversationMessage;\r\n }) => {\r\n const isUser =\r\n message.type ===\r\n \"user_voice\" ||\r\n message.type ===\r\n \"user_text\";\r\n\r\n return (\r\n <div\r\n className={`p-3 rounded-[16px] max-w-[85%] text-xs leading-relaxed ${isUser\r\n ? \"bg-[#1a73e8] text-white self-end rounded-tr-sm shadow-md shadow-blue-500/10 border border-blue-500/10\"\r\n : \"bg-white text-gray-800 self-start rounded-tl-sm shadow-md shadow-slate-100 border border-slate-100\"\r\n }`}\r\n >\r\n {formatMessage(\r\n String(\r\n message.text || \"\"\r\n )\r\n )}\r\n </div>\r\n );\r\n }\r\n);\r\n\r\nMessageBubble.displayName =\r\n \"MessageBubble\";\r\n\r\n/* =============================================================================\r\n * COMPONENT\r\n * =============================================================================\r\n */\r\n\r\nexport default function VoicePanel({\r\n enabled,\r\n\r\n connectionState,\r\n\r\n agentState = \"idle\",\r\n\r\n messages,\r\n\r\n participants = [],\r\n\r\n onDisable,\r\n\r\n textEnabled,\r\n\r\n micMuted = false,\r\n\r\n speakerMuted = false,\r\n\r\n onMicMutedChange,\r\n\r\n onSpeakerMutedChange,\r\n\r\n onSendText,\r\n}: Props) {\r\n const [input, setInput] =\r\n useState(\"\");\r\n\r\n const [minimized, setMinimized] =\r\n useState(false);\r\n\r\n const containerRef =\r\n useRef<HTMLDivElement | null>(\r\n null\r\n );\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Sort messages\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const orderedMessages =\r\n useMemo(() => {\r\n return [...messages].sort(\r\n (a, b) =>\r\n a.timestamp -\r\n b.timestamp\r\n );\r\n }, [messages]);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Smart autoscroll\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n useEffect(() => {\r\n const el =\r\n containerRef.current;\r\n\r\n if (!el) return;\r\n\r\n requestAnimationFrame(() => {\r\n el.scrollTo({\r\n top: el.scrollHeight,\r\n behavior: \"smooth\",\r\n });\r\n });\r\n }, [orderedMessages, minimized]);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Send message\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const sendMessage = () => {\r\n const text =\r\n input.trim();\r\n\r\n if (\r\n !text ||\r\n !onSendText\r\n ) {\r\n return;\r\n }\r\n console.log(\"[VoicePanel] sendMessage\", text);\r\n onSendText(text);\r\n\r\n setInput(\"\");\r\n };\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Mic toggle\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const handleMicClick = () => {\r\n onMicMutedChange?.(\r\n !micMuted\r\n );\r\n };\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Speaker toggle\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const handleSpeakerClick =\r\n () => {\r\n onSpeakerMutedChange?.(\r\n !speakerMuted\r\n );\r\n };\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Enter send\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const handleKey = (\r\n e: React.KeyboardEvent\r\n ) => {\r\n if (e.key === \"Enter\") {\r\n e.preventDefault();\r\n\r\n sendMessage();\r\n }\r\n };\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Status text\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const statusText =\r\n (() => {\r\n if (\r\n micMuted &&\r\n speakerMuted\r\n ) {\r\n return \"Mic & Speaker muted\";\r\n }\r\n\r\n if (micMuted) {\r\n return \"Mic muted\";\r\n }\r\n\r\n if (speakerMuted) {\r\n return \"Speaker muted\";\r\n }\r\n\r\n if (\r\n connectionState ===\r\n \"reconnecting\"\r\n ) {\r\n return \"Reconnecting...\";\r\n }\r\n\r\n if (\r\n connectionState ===\r\n \"connecting\"\r\n ) {\r\n return \"Connecting...\";\r\n }\r\n\r\n if (\r\n connectionState ===\r\n \"error\"\r\n ) {\r\n return \"Connection error\";\r\n }\r\n\r\n if (\r\n connectionState ===\r\n \"connected\"\r\n ) {\r\n switch (\r\n agentState\r\n ) {\r\n case \"listening\":\r\n return \"Listening...\";\r\n\r\n case \"thinking\":\r\n return \"Thinking...\";\r\n\r\n case \"speaking\":\r\n return \"Speaking...\";\r\n\r\n default:\r\n return \"Ready to help\";\r\n }\r\n }\r\n\r\n return \"Disconnected\";\r\n })();\r\n\r\n /* =============================================================================\r\n * MINIMIZED\r\n * =============================================================================\r\n */\r\n\r\n if (\r\n enabled &&\r\n minimized\r\n ) {\r\n return (\r\n <div\r\n onClick={() =>\r\n setMinimized(\r\n false\r\n )\r\n }\r\n className=\"fixed right-6 bottom-6 z-[1100] cursor-pointer\"\r\n >\r\n <div\r\n className={`w-14 h-14 rounded-full flex items-center justify-center shadow-lg text-white ${connectionState ===\r\n \"connected\"\r\n ? \"bg-green-500 animate-pulse\"\r\n : connectionState ===\r\n \"connecting\"\r\n ? \"bg-blue-500\"\r\n : connectionState ===\r\n \"error\"\r\n ? \"bg-red-500\"\r\n : \"bg-blue-600\"\r\n }`}\r\n >\r\n <Mic className=\"h-4 w-4\" />\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n /* =============================================================================\r\n * FULL PANEL\r\n * =============================================================================\r\n */\r\n\r\n return (\r\n <div className=\"fixed bottom-24 right-6 w-80 bg-white shadow-xl rounded-[20px] flex flex-col z-[1100] border border-gray-100/80 overflow-hidden font-sans\">\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between p-4 bg-[#1a73e8] text-white\">\r\n <div className=\"flex items-center gap-3\">\r\n {/* Status Indicator circle */}\r\n <div className=\"w-9 h-9 rounded-full bg-white/15 flex items-center justify-center relative shrink-0\">\r\n <div className=\"relative flex items-center justify-center w-2.5 h-2.5\">\r\n <span\r\n className={`w-2.5 h-2.5 rounded-full transition-colors duration-300 ${connectionState === \"connected\"\r\n ? \"bg-[#fbbc05]\"\r\n : connectionState === \"connecting\" || connectionState === \"reconnecting\"\r\n ? \"bg-yellow-400 animate-pulse\"\r\n : connectionState === \"error\"\r\n ? \"bg-red-500\"\r\n : \"bg-gray-400\"\r\n }`}\r\n />\r\n {connectionState === \"connected\" && (agentState === \"speaking\" || agentState === \"listening\" || agentState === \"thinking\") && (\r\n <span className=\"absolute inline-flex h-4 w-4 rounded-full bg-[#fbbc05]/50 animate-ping\" />\r\n )}\r\n </div>\r\n </div>\r\n\r\n <div className=\"flex flex-col\">\r\n <span className=\"text-base font-semibold leading-tight\">\r\n Voice Assistant\r\n </span>\r\n <p className=\"text-[11px] text-white/80 mt-0.5 font-normal\">\r\n {statusText}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n {/* Actions */}\r\n <div className=\"flex gap-1.5\">\r\n {enabled && (\r\n <button\r\n onClick={() => setMinimized(true)}\r\n className=\"bg-white/10 w-8 h-8 rounded-lg flex items-center justify-center hover:bg-white/20 transition-all duration-200 active:scale-95 cursor-pointer\"\r\n title=\"Minimize\"\r\n >\r\n <ChevronRight className=\"rotate-90 h-4.5 w-4.5\" />\r\n </button>\r\n )}\r\n\r\n <button\r\n onClick={onDisable}\r\n className=\"bg-white/10 w-8 h-8 rounded-lg flex items-center justify-center hover:bg-white/20 transition-all duration-200 active:scale-95 cursor-pointer\"\r\n title=\"Close\"\r\n >\r\n <X className=\"h-4.5 w-4.5\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Speaker & Mic Controls Grid */}\r\n <div className=\"grid grid-cols-2 gap-2.5 p-3.5 bg-white border-b border-gray-100\">\r\n {/* Speaker Card */}\r\n <div\r\n onClick={handleSpeakerClick}\r\n className={`flex items-center gap-2.5 p-3 rounded-xl cursor-pointer transition-all duration-200 active:scale-[0.98] ${speakerMuted\r\n ? \"bg-[#f1f3f4] hover:bg-[#e8eaed]\"\r\n : \"bg-[#e8f0fe] hover:bg-[#d2e3fc]\"\r\n }`}\r\n >\r\n <div\r\n className={`w-10 h-10 rounded-lg flex items-center justify-center transition-colors shrink-0 ${speakerMuted\r\n ? \"bg-[#e8eaed] text-gray-500\"\r\n : \"bg-[#1a73e8] text-white\"\r\n }`}\r\n >\r\n {speakerMuted ? (\r\n <VolumeX className=\"h-4.5 w-4.5\" />\r\n ) : (\r\n <Volume2 className=\"h-4.5 w-4.5\" />\r\n )}\r\n </div>\r\n <div className=\"min-w-0\">\r\n <p className=\"text-xs font-semibold text-gray-800 truncate\">Speaker</p>\r\n <p className=\"text-[10px] text-gray-500 mt-0.5 truncate\">\r\n {speakerMuted ? \"Disabled\" : \"Active\"}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n {/* Mic Card */}\r\n <div\r\n onClick={handleMicClick}\r\n className={`flex items-center gap-2.5 p-3 rounded-xl cursor-pointer transition-all duration-200 active:scale-[0.98] ${micMuted\r\n ? \"bg-[#f1f3f4] hover:bg-[#e8eaed]\"\r\n : \"bg-[#e8f0fe] hover:bg-[#d2e3fc]\"\r\n }`}\r\n >\r\n <div\r\n className={`w-10 h-10 rounded-lg flex items-center justify-center transition-colors shrink-0 ${micMuted\r\n ? \"bg-[#e8eaed] text-gray-500\"\r\n : \"bg-[#1a73e8] text-white\"\r\n }`}\r\n >\r\n {micMuted ? (\r\n <MicOff className=\"h-4.5 w-4.5\" />\r\n ) : (\r\n <Mic className=\"h-4.5 w-4.5\" />\r\n )}\r\n </div>\r\n <div className=\"min-w-0\">\r\n <p className=\"text-xs font-semibold text-gray-800 truncate\">Mic</p>\r\n <p className=\"text-[10px] text-gray-500 mt-0.5 truncate\">\r\n {micMuted ? \"Disabled\" : \"Active\"}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Messages */}\r\n <div\r\n ref={containerRef}\r\n className=\"flex-1 p-3.5 overflow-y-auto max-h-[300px] min-h-[240px] bg-[#f8f9fa] flex flex-col gap-3 scroll-smooth\"\r\n >\r\n {/* Voice enabled pill badge */}\r\n <div className=\"flex justify-start\">\r\n <div className=\"inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-white border border-gray-200/80 shadow-sm text-[10px] font-semibold text-slate-700\">\r\n <span>🎤</span> Voice enabled\r\n </div>\r\n </div>\r\n\r\n {/* Participants */}\r\n {participants && participants.length > 0 && (\r\n <div className=\"p-2.5 rounded-lg bg-blue-50/50 border border-blue-100/50 mb-2\">\r\n <p className=\"text-[10px] font-semibold text-blue-900 mb-0.5\">\r\n Participants:\r\n </p>\r\n {participants.map((p, i) => (\r\n <p key={i} className=\"text-[10px] text-blue-800\">\r\n • {p}\r\n </p>\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Messages */}\r\n {orderedMessages.map((m) => {\r\n if (m.text === \"__SESSION_END__\") {\r\n return (\r\n <div\r\n key={m.id}\r\n className=\"p-3.5 rounded-xl max-w-[85%] text-xs text-amber-800 bg-amber-50 border border-amber-100 self-center text-center shadow-sm\"\r\n >\r\n Session ended.\r\n <br />\r\n <button\r\n style={{\r\n color: \"#1a73e8\",\r\n textDecoration: \"underline\",\r\n cursor: \"pointer\",\r\n background: \"none\",\r\n border: \"none\",\r\n padding: 0,\r\n fontWeight: 600,\r\n }}\r\n className=\"hover:text-blue-700 transition-colors mt-1\"\r\n onClick={() => window.location.reload()}\r\n >\r\n Click here\r\n </button>{\" \"}\r\n to start session again\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <MessageBubble\r\n key={m.id}\r\n message={m}\r\n />\r\n );\r\n })}\r\n </div>\r\n\r\n {/* Footer */}\r\n {textEnabled && (\r\n <div className=\"p-3 bg-white flex gap-2.5 items-center border-t border-gray-100\">\r\n <input\r\n value={input}\r\n onChange={(e) => setInput(e.target.value)}\r\n onKeyDown={handleKey}\r\n placeholder=\"Type your message...\"\r\n className=\"flex-1 px-3.5 py-2.5 text-xs bg-[#f1f3f4] border border-transparent rounded-full focus:outline-none focus:bg-white focus:border-gray-200 focus:ring-2 focus:ring-blue-100 text-gray-900 placeholder-gray-500 transition-all duration-200\"\r\n />\r\n\r\n <button\r\n onClick={sendMessage}\r\n className=\"w-10 h-10 rounded-xl bg-[#1a73e8] text-white flex items-center justify-center hover:bg-[#1557b0] transition-colors shadow-md shadow-blue-500/20 active:scale-95 shrink-0 cursor-pointer\"\r\n title=\"Send message\"\r\n >\r\n <SendHorizontal className=\"h-4.5 w-4.5\" />\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}","\"use client\";\r\n\r\nimport React, {\r\n createContext,\r\n useCallback,\r\n useContext,\r\n useEffect,\r\n useMemo,\r\n useRef,\r\n useState,\r\n} from \"react\";\r\n\r\nimport {\r\n ConnectionQuality,\r\n ConnectionState,\r\n} from \"livekit-client\";\r\n\r\nimport { fetchSession } from \"../services/token.service\";\r\nimport { LiveKitService } from \"../services/livekit.service\";\r\n\r\nimport { useTranscriptSync } from \"../hooks/useTranscriptSync\";\r\n\r\nimport {\r\n AgentState,\r\n ConversationMessage,\r\n FloatingMicConfig,\r\n VoiceActionEvent,\r\n VoiceActionHandler,\r\n VoiceActionResult,\r\n VoiceAssistantContextType,\r\n} from \"../types/sdk.types\";\r\n\r\n/**\r\n * ----------------------------------------------------------------------------\r\n * Context\r\n * ----------------------------------------------------------------------------\r\n */\r\n\r\nconst VoiceAssistantContext =\r\n createContext<VoiceAssistantContextType | null>(\r\n null\r\n );\r\n\r\n/**\r\n * ----------------------------------------------------------------------------\r\n * Provider\r\n * ----------------------------------------------------------------------------\r\n */\r\n\r\ninterface LiveKitProviderProps {\r\n children: React.ReactNode;\r\n config: FloatingMicConfig;\r\n}\r\n\r\nexport function LiveKitProvider({\r\n children,\r\n config,\r\n}: LiveKitProviderProps) {\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Refs\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const audioContainerRef = useRef<HTMLDivElement | null>(null);\r\n const serviceRef = useRef<LiveKitService | null>(null);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Connection state\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const [connectionState, setConnectionState] = useState<ConnectionState>(\r\n ConnectionState.Disconnected\r\n );\r\n\r\n const [connected, setConnected] = useState(false);\r\n const [connecting, setConnecting] = useState(false);\r\n const [reconnecting, setReconnecting] = useState(false);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Device state\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const [micEnabled, setMicEnabled] =\r\n useState(false);\r\n\r\n const [speakerEnabled, setSpeakerEnabled] = useState(false);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Agent state\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const [agentState, setAgentState] =\r\n useState<AgentState>(\"idle\");\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Network quality\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const [quality, setQuality] =\r\n useState<ConnectionQuality | null>(\r\n null\r\n );\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Error state\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const [error, setError] = useState<\r\n string | null\r\n >(null);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Transcript sync engine\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const {\r\n messages,\r\n addTranscriptSegment,\r\n addTextMessage,\r\n clearMessages,\r\n } = useTranscriptSync({\r\n maxMessages: 1000,\r\n enableGrouping: true,\r\n });\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Initialize service\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n useEffect(() => {\r\n if (!audioContainerRef.current) return;\r\n\r\n const service = new LiveKitService(\r\n audioContainerRef.current,\r\n config?.customParameters?.user,\r\n config?.customParameters?.context,\r\n config.mode\r\n );\r\n\r\n serviceRef.current = service;\r\n\r\n const registerConfiguredHandlers = () => {\r\n const handlers = config.actionHandlers;\r\n\r\n if (!handlers) return;\r\n\r\n Object.entries(handlers).forEach(\r\n ([eventId, handler]) => {\r\n service.registerEventHandler(\r\n eventId,\r\n handler\r\n );\r\n }\r\n );\r\n };\r\n\r\n registerConfiguredHandlers();\r\n\r\n /**\r\n * ----------------------------------------------------------------------\r\n * Connected\r\n * ----------------------------------------------------------------------\r\n */\r\n\r\n service.onConnected = () => {\r\n setConnected(true);\r\n setConnecting(false);\r\n setReconnecting(false);\r\n setConnectionState(\r\n ConnectionState.Connected\r\n );\r\n setSpeakerEnabled(false);\r\n setError(null);\r\n };\r\n\r\n /**\r\n * ----------------------------------------------------------------------\r\n * Disconnected\r\n * ----------------------------------------------------------------------\r\n */\r\n\r\n service.onDisconnected = () => {\r\n setConnected(false);\r\n\r\n setConnecting(false);\r\n\r\n setReconnecting(false);\r\n\r\n setMicEnabled(false);\r\n\r\n setAgentState(\"idle\");\r\n\r\n setConnectionState(\r\n ConnectionState.Disconnected\r\n );\r\n };\r\n\r\n /**\r\n * ----------------------------------------------------------------------\r\n * Reconnecting\r\n * ----------------------------------------------------------------------\r\n */\r\n\r\n service.onReconnecting = () => {\r\n setReconnecting(true);\r\n\r\n setConnectionState(\r\n ConnectionState.Reconnecting\r\n );\r\n };\r\n\r\n /**\r\n * ----------------------------------------------------------------------\r\n * Reconnected\r\n * ----------------------------------------------------------------------\r\n */\r\n\r\n service.onReconnected = () => {\r\n setReconnecting(false);\r\n\r\n setConnectionState(\r\n ConnectionState.Connected\r\n );\r\n };\r\n\r\n /**\r\n * ----------------------------------------------------------------------\r\n * Mic state\r\n * ----------------------------------------------------------------------\r\n */\r\n\r\n service.onMicState = (enabled) => {\r\n setMicEnabled(enabled);\r\n };\r\n\r\n /**\r\n * ----------------------------------------------------------------------\r\n * Agent state\r\n * ----------------------------------------------------------------------\r\n */\r\n\r\n service.onAgentState = (state) => {\r\n setAgentState(state);\r\n };\r\n\r\n /**\r\n * ----------------------------------------------------------------------\r\n * Quality updates\r\n * ----------------------------------------------------------------------\r\n */\r\n\r\n service.onQuality = (q) => {\r\n setQuality(q);\r\n };\r\n\r\n /**\r\n * ----------------------------------------------------------------------\r\n * Error handling\r\n * ----------------------------------------------------------------------\r\n */\r\n\r\n service.onError = (err) => {\r\n console.error(\"LiveKit Error:\", err);\r\n\r\n setError(err);\r\n\r\n setConnecting(false);\r\n\r\n setConnected(false);\r\n };\r\n\r\n /**\r\n * ----------------------------------------------------------------------\r\n * Transcript synchronization\r\n * ----------------------------------------------------------------------\r\n */\r\n\r\n service.onMessage = (message) => {\r\n /**\r\n * --------------------------------------------------------------\r\n * Voice transcripts\r\n * --------------------------------------------------------------\r\n */\r\n\r\n if (\r\n message.type === \"user_voice\" ||\r\n message.type === \"assistant_voice\"\r\n ) {\r\n addTranscriptSegment(\r\n {\r\n id: message.id,\r\n text: message.text,\r\n final: message.final ?? false,\r\n timestamp: message.timestamp,\r\n },\r\n message.type\r\n );\r\n\r\n return;\r\n }\r\n\r\n /**\r\n * --------------------------------------------------------------\r\n * Text messages\r\n * --------------------------------------------------------------\r\n */\r\n\r\n addTextMessage(\r\n message.text,\r\n message.type\r\n );\r\n };\r\n\r\n return () => {\r\n void service.disconnect();\r\n serviceRef.current = null;\r\n };\r\n }, [\r\n addTranscriptSegment,\r\n addTextMessage,\r\n config.actionHandlers,\r\n ]);\r\n\r\n useEffect(() => {\r\n const container = audioContainerRef.current;\r\n\r\n if (!container) return;\r\n\r\n const audioElements =\r\n container.querySelectorAll(\"audio\");\r\n\r\n audioElements.forEach((audio) => {\r\n const element =\r\n audio as HTMLAudioElement;\r\n\r\n element.muted = !speakerEnabled;\r\n element.volume = speakerEnabled ? 1 : 0;\r\n });\r\n }, [speakerEnabled]);\r\n\r\n /**\r\n * ----------------------------------------------------------------------------\r\n * Connect\r\n * ----------------------------------------------------------------------------\r\n */\r\n\r\n const connect = useCallback(async () => {\r\n if (!serviceRef.current) return;\r\n\r\n if (\r\n connected ||\r\n connecting ||\r\n reconnecting\r\n ) {\r\n return;\r\n }\r\n\r\n try {\r\n setConnecting(true);\r\n\r\n setError(null);\r\n\r\n const session = await fetchSession(config);\r\n\r\n await serviceRef.current.connect(\r\n session.url,\r\n session.token\r\n );\r\n } catch (err: any) {\r\n console.error(err);\r\n\r\n let userMessage =\r\n err?.message || \"Failed to connect\";\r\n\r\n /**\r\n * ----------------------------------------------------------------------\r\n * User-friendly errors\r\n * ----------------------------------------------------------------------\r\n */\r\n\r\n if (\r\n /permission|microphone|notallowed/i.test(\r\n userMessage\r\n )\r\n ) {\r\n userMessage =\r\n \"Microphone access denied.\";\r\n }\r\n\r\n if (\r\n /jwt|token|expired/i.test(userMessage)\r\n ) {\r\n userMessage =\r\n \"Session expired. Please refresh.\";\r\n }\r\n\r\n if (/network/i.test(userMessage)) {\r\n userMessage =\r\n \"Network connection failed.\";\r\n }\r\n\r\n setError(userMessage);\r\n\r\n setConnecting(false);\r\n\r\n setConnected(false);\r\n }\r\n }, [\r\n connected,\r\n connecting,\r\n reconnecting,\r\n config,\r\n ]);\r\n\r\n /**\r\n * ----------------------------------------------------------------------------\r\n * Disconnect\r\n * ----------------------------------------------------------------------------\r\n */\r\n\r\n const disconnect = useCallback(async () => {\r\n try {\r\n await serviceRef.current?.disconnect();\r\n\r\n setConnected(false);\r\n\r\n setConnecting(false);\r\n\r\n setReconnecting(false);\r\n\r\n setMicEnabled(false);\r\n\r\n setAgentState(\"idle\");\r\n\r\n setConnectionState(\r\n ConnectionState.Disconnected\r\n );\r\n } catch (err) {\r\n console.error(err);\r\n }\r\n }, []);\r\n\r\n\r\n\r\n /**\r\n * ----------------------------------------------------------------------------\r\n * Toggle microphone\r\n * ----------------------------------------------------------------------------\r\n */\r\n\r\n const toggleMic = useCallback(async () => {\r\n try {\r\n const next = !micEnabled;\r\n\r\n await serviceRef.current?.toggleMic(\r\n next\r\n );\r\n\r\n console.log(\"LIVEKIT MIC ENABLED:\", next);\r\n setMicEnabled(next);\r\n } catch (err: any) {\r\n console.error(err);\r\n\r\n setError(\r\n err?.message ||\r\n \"Failed to toggle microphone\"\r\n );\r\n }\r\n }, [micEnabled]);\r\n\r\n /**\r\n * ----------------------------------------------------------------------------\r\n * Toggle speaker\r\n * ----------------------------------------------------------------------------\r\n */\r\n\r\n // const setSpeakerMuted = useCallback(\r\n // (muted: boolean) => {\r\n // console.log(\"LIVEKIT SPEAKER MUTED:\", muted);\r\n // const container =\r\n // audioContainerRef.current;\r\n\r\n // if (container) {\r\n // const audioEls =\r\n // container.querySelectorAll(\"audio\");\r\n\r\n // audioEls.forEach((audio) => {\r\n // const el = audio as HTMLAudioElement;\r\n // console.log(\"LIVEKIT APPLYING MUTE:\", muted, el.id);\r\n\r\n // el.muted = muted;\r\n // el.volume = muted ? 0 : 1;\r\n // });\r\n // }\r\n\r\n // setSpeakerEnabled(!muted);\r\n // },\r\n // []\r\n // );\r\n\r\n const setSpeakerMuted = useCallback(\r\n (muted: boolean) => {\r\n console.log(\"LIVEKIT SPEAKER MUTED:\", muted);\r\n serviceRef.current?.setSpeakerMuted(\r\n muted\r\n );\r\n\r\n setSpeakerEnabled(!muted);\r\n },\r\n []\r\n );\r\n\r\n /**\r\n * ----------------------------------------------------------------------------\r\n * Send text\r\n * ----------------------------------------------------------------------------\r\n */\r\n\r\n const sendText = useCallback(\r\n async (text: string) => {\r\n if (!text.trim()) return;\r\n\r\n /**\r\n * ----------------------------------------------------------------------\r\n * Optimistic message\r\n * ----------------------------------------------------------------------\r\n */\r\n\r\n try {\r\n await serviceRef.current?.sendText(\r\n text\r\n );\r\n } catch (err: any) {\r\n console.error(err);\r\n\r\n setError(\r\n err?.message ||\r\n \"Failed to send message\"\r\n );\r\n }\r\n },\r\n []\r\n );\r\n\r\n /**\r\n * ----------------------------------------------------------------------------\r\n * Reset conversation\r\n * ----------------------------------------------------------------------------\r\n */\r\n\r\n const resetConversation =\r\n useCallback(() => {\r\n clearMessages();\r\n }, [clearMessages]);\r\n\r\n const registerEventHandler =\r\n useCallback(\r\n (\r\n eventId: string,\r\n handler: VoiceActionHandler\r\n ) => {\r\n serviceRef.current?.registerEventHandler(\r\n eventId,\r\n handler\r\n );\r\n },\r\n []\r\n );\r\n\r\n const onVoiceAction = useCallback(\r\n (\r\n callback: (\r\n event: VoiceActionEvent\r\n ) => void\r\n ) => {\r\n return (\r\n serviceRef.current?.addVoiceActionListener(\r\n callback\r\n ) || (() => {})\r\n );\r\n },\r\n []\r\n );\r\n\r\n const onVoiceActionResult = useCallback(\r\n (\r\n callback: (\r\n result: VoiceActionResult\r\n ) => void\r\n ) => {\r\n if (!serviceRef.current) {\r\n return () => {};\r\n }\r\n\r\n serviceRef.current.onVoiceActionResult =\r\n callback;\r\n\r\n return () => {\r\n if (\r\n serviceRef.current\r\n ?.onVoiceActionResult === callback\r\n ) {\r\n serviceRef.current.onVoiceActionResult =\r\n undefined;\r\n }\r\n };\r\n },\r\n []\r\n );\r\n /**\r\n * ----------------------------------------------------------------------------\r\n * Context value\r\n * ----------------------------------------------------------------------------\r\n */\r\n\r\n const value =\r\n useMemo<VoiceAssistantContextType>(\r\n () => ({\r\n connected,\r\n connecting,\r\n reconnecting,\r\n micEnabled,\r\n speakerEnabled,\r\n messages,\r\n agentState,\r\n quality,\r\n error,\r\n connect,\r\n disconnect,\r\n toggleMic,\r\n setSpeakerMuted,\r\n sendText,\r\n registerEventHandler,\r\n onVoiceAction,\r\n onVoiceActionResult,\r\n connectionState,\r\n clearConversation: resetConversation,\r\n }),\r\n [\r\n connected,\r\n connecting,\r\n reconnecting,\r\n micEnabled,\r\n speakerEnabled,\r\n messages,\r\n agentState,\r\n quality,\r\n error,\r\n connect,\r\n disconnect,\r\n toggleMic,\r\n setSpeakerMuted,\r\n sendText,\r\n registerEventHandler,\r\n onVoiceAction,\r\n onVoiceActionResult,\r\n connectionState,\r\n resetConversation,\r\n ]\r\n );\r\n\r\n return (\r\n <VoiceAssistantContext.Provider\r\n value={value}\r\n >\r\n {children}\r\n\r\n <div\r\n ref={audioContainerRef}\r\n // style={{ display: \"none\" }}\r\n style={{\r\n position: \"absolute\",\r\n width: 1,\r\n height: 1,\r\n overflow: \"hidden\",\r\n opacity: 0,\r\n pointerEvents: \"none\",\r\n }}\r\n />\r\n </VoiceAssistantContext.Provider>\r\n );\r\n}\r\n\r\n/**\r\n * ----------------------------------------------------------------------------\r\n * Hook\r\n * ----------------------------------------------------------------------------\r\n */\r\n\r\nexport function useVoiceAssistant() {\r\n const context = useContext(\r\n VoiceAssistantContext\r\n );\r\n\r\n if (!context) {\r\n throw new Error(\r\n \"useVoiceAssistant must be used inside LiveKitProvider\"\r\n );\r\n }\r\n\r\n return context;\r\n}","export interface VibriumAuthResponse {\r\n token: string;\r\n}\r\n\r\nexport async function getBearerToken({\r\n customerId,\r\n apiKey,\r\n}: {\r\n customerId: string;\r\n\r\n apiKey: string;\r\n}): Promise<string> {\r\n const response = await fetch(\r\n `https://api.vibrium.ai/v1/customers/${customerId}/auth/token`,\r\n {\r\n method: \"POST\",\r\n\r\n headers: {\r\n \"Content-Type\":\r\n \"application/json\",\r\n\r\n Authorization: `Basic ${apiKey}`,\r\n },\r\n }\r\n );\r\n\r\n if (!response.ok) {\r\n const text =\r\n await response.text();\r\n\r\n throw new Error(\r\n `Auth failed: ${text}`\r\n );\r\n }\r\n\r\n const json =\r\n await response.json();\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Flexible response handling\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const token =\r\n json?.token ||\r\n json?.data?.token ||\r\n json?.access_token;\r\n\r\n if (!token) {\r\n throw new Error(\r\n \"Missing bearer token\"\r\n );\r\n }\r\n\r\n return token;\r\n}","import { getBearerToken } from \"./auth.service\";\r\nimport {\r\n FloatingMicConfig,\r\n SessionResponse,\r\n} from \"../types/sdk.types\";\r\n\r\nexport async function fetchSession(\r\n config: FloatingMicConfig\r\n): Promise<SessionResponse> {\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Step 1: Get bearer token\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n console.log(\"customerId\", config.customerId);\r\n console.log(\"apiKey\", config.apiKey);\r\n const bearerToken =\r\n await getBearerToken({\r\n customerId: config.customerId,\r\n apiKey: config.apiKey,\r\n });\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Step 2: Call lambda\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const response = await fetch(\r\n config.lambdaUrl,\r\n {\r\n method: \"POST\",\r\n\r\n headers: {\r\n \"Content-Type\":\r\n \"application/json\",\r\n\r\n Authorization: `Bearer ${bearerToken}`,\r\n },\r\n\r\n body: JSON.stringify({\r\n customer_id: config.customerId,\r\n bot_id: config.botId,\r\n\r\n mode: config.mode ?? \"hybrid\",\r\n\r\n ...(config.customParameters && {\r\n user: config.customParameters.user,\r\n }),\r\n\r\n ...(config.customParameters && {\r\n context: config.customParameters.context,\r\n }),\r\n })\r\n }\r\n );\r\n\r\n if (!response.ok) {\r\n const text =\r\n await response.text();\r\n\r\n throw new Error(\r\n `Lambda failed: ${text}`\r\n );\r\n }\r\n\r\n const json =\r\n await response.json();\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Normalize response\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n return {\r\n token:\r\n json.token ||\r\n json.data?.token,\r\n\r\n url:\r\n json.url ||\r\n json.data?.url,\r\n\r\n roomName:\r\n json.roomName ||\r\n json.data?.room_name,\r\n\r\n participantIdentity:\r\n json.participantIdentity ||\r\n json.data\r\n ?.participant_identity,\r\n };\r\n}","import {\r\n ConnectionQuality,\r\n DataPacket_Kind,\r\n LocalParticipant,\r\n ParticipantKind,\r\n RemoteParticipant,\r\n Room,\r\n RoomEvent,\r\n Track,\r\n} from \"livekit-client\";\r\n\r\nimport {\r\n AgentState,\r\n ConversationMessage,\r\n VoiceActionEvent,\r\n VoiceActionResult,\r\n VoiceActionHandler,\r\n} from \"../types/sdk.types\";\r\n\r\nimport {\r\n attachAudioTrack,\r\n detachAudioTrack,\r\n} from \"../utils/audio\";\r\nimport { ActionRegistry } from \"./action-registry\";\r\n\r\nexport class LiveKitService {\r\n room: Room | null = null;\r\n audioContainer: HTMLDivElement;\r\n private speakerMuted = true;\r\n private user?: Record<string, any>;\r\n private context?: Record<string, any>;\r\n private mode?: \"hybrid\" | \"voice\" | \"chat\";\r\n\r\n private readonly VOICE_ACTION_TOPIC = \"vibrium.voice.action\";\r\n private readonly VOICE_ACTION_RESULT_TOPIC = \"vibrium.voice.action.result\";\r\n private readonly VOICE_ACTION_TIMEOUT_MS = 30000;\r\n\r\n private actionRegistry = new ActionRegistry();\r\n\r\n private actionListeners = new Set<\r\n (event: VoiceActionEvent) => void\r\n >();\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Event handlers\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n onConnected?: () => void;\r\n\r\n onDisconnected?: () => void;\r\n\r\n onReconnecting?: () => void;\r\n\r\n onReconnected?: () => void;\r\n\r\n onMessage?: (\r\n message: ConversationMessage\r\n ) => void;\r\n\r\n onAgentState?: (\r\n state: AgentState\r\n ) => void;\r\n\r\n onError?: (error: string) => void;\r\n\r\n onMicState?: (\r\n enabled: boolean\r\n ) => void;\r\n\r\n onQuality?: (\r\n quality: ConnectionQuality\r\n ) => void;\r\n\r\n onVoiceAction?: (\r\n event: VoiceActionEvent\r\n ) => void;\r\n\r\n onVoiceActionResult?: (\r\n result: VoiceActionResult\r\n ) => void;\r\n\r\n registerEventHandler(\r\n eventId: string,\r\n handler: VoiceActionHandler\r\n ) {\r\n this.actionRegistry.register(\r\n eventId,\r\n handler\r\n );\r\n }\r\n\r\n private pendingActions =\r\n new Map<\r\n string,\r\n {\r\n eventId: string;\r\n startedAt: number;\r\n }\r\n >();\r\n\r\n constructor(\r\n audioContainer: HTMLDivElement,\r\n user?: Record<string, any>,\r\n context?: Record<string, any>,\r\n mode?: \"hybrid\" | \"voice\" | \"chat\"\r\n ) {\r\n this.audioContainer = audioContainer;\r\n this.user = user;\r\n this.context = context;\r\n this.mode = mode;\r\n }\r\n\r\n\r\n addVoiceActionListener(\r\n listener: (\r\n event: VoiceActionEvent\r\n ) => void\r\n ) {\r\n this.actionListeners.add(listener);\r\n\r\n return () => {\r\n this.actionListeners.delete(listener);\r\n };\r\n }\r\n\r\n private validateVoiceAction(\r\n event: any\r\n ) {\r\n if (\r\n !event ||\r\n typeof event !== \"object\"\r\n ) {\r\n throw new Error(\r\n \"Invalid event payload\"\r\n );\r\n }\r\n\r\n if (\r\n typeof event.request_id !==\r\n \"string\"\r\n ) {\r\n throw new Error(\r\n \"Missing request_id\"\r\n );\r\n }\r\n\r\n if (\r\n typeof event.event_id !==\r\n \"string\"\r\n ) {\r\n throw new Error(\r\n \"Missing event_id\"\r\n );\r\n }\r\n }\r\n\r\n private async handleVoiceAction(\r\n event: VoiceActionEvent\r\n ) {\r\n this.validateVoiceAction(event);\r\n\r\n this.actionListeners.forEach(\r\n listener => {\r\n try {\r\n listener(event);\r\n } catch (e) {\r\n console.error(e);\r\n }\r\n }\r\n );\r\n\r\n this.pendingActions.set(\r\n event.request_id,\r\n {\r\n eventId: event.event_id,\r\n startedAt: Date.now(),\r\n }\r\n );\r\n\r\n const handler = this.actionRegistry.resolve(event.event_id);\r\n\r\n if (!handler) {\r\n await this.publishActionResult({\r\n request_id: event.request_id,\r\n event_id: event.event_id,\r\n status: \"failure\",\r\n error: {\r\n code: \"handler_not_found\",\r\n message:\r\n \"No registered handler\",\r\n },\r\n });\r\n\r\n return;\r\n }\r\n\r\n try {\r\n const response: Omit<\r\n VoiceActionResult,\r\n \"request_id\" | \"event_id\"\r\n > = await Promise.race([\r\n handler(event),\r\n new Promise<never>((_, reject) =>\r\n setTimeout(\r\n () => reject(new Error(\"Action timeout\")),\r\n this.VOICE_ACTION_TIMEOUT_MS\r\n )\r\n ),\r\n ]);\r\n\r\n await this.publishActionResult({\r\n request_id: event.request_id,\r\n event_id: event.event_id,\r\n ...response,\r\n });\r\n this.pendingActions.delete(\r\n event.request_id\r\n );\r\n } catch (error: any) {\r\n await this.publishActionResult({\r\n request_id: event.request_id,\r\n event_id: event.event_id,\r\n status: \"failure\",\r\n error: {\r\n code: \"handler_error\",\r\n message:\r\n error?.message ||\r\n \"Handler failed\",\r\n },\r\n });\r\n this.pendingActions.delete(\r\n event.request_id\r\n );\r\n }\r\n }\r\n \r\n /**\r\n * --------------------------------------------------------------------------\r\n * Connect\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n async connect(\r\n url: string,\r\n token: string\r\n ) {\r\n const room = new Room({\r\n adaptiveStream: true,\r\n dynacast: true,\r\n });\r\n\r\n this.room = room;\r\n\r\n const registerTextStreamHandler = (room as any).registerTextStreamHandler;\r\n\r\n if (typeof registerTextStreamHandler === \"function\") {\r\n registerTextStreamHandler.call(\r\n room,\r\n \"lk.chat\",\r\n async (\r\n reader: {\r\n readAll: () => Promise<string>;\r\n },\r\n participantInfo?: {\r\n identity?: string;\r\n }\r\n ) => {\r\n const text =\r\n await reader.readAll();\r\n\r\n console.log(\r\n \"[TEXT_STREAM]\",\r\n participantInfo?.identity,\r\n text\r\n );\r\n\r\n this.onMessage?.({\r\n id:\r\n crypto.randomUUID(),\r\n type:\r\n \"assistant_text\",\r\n text,\r\n final: true,\r\n timestamp: Date.now(),\r\n });\r\n }\r\n );\r\n }\r\n\r\n /**\r\n * ------------------------------------------------------------------------\r\n * Connected\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\n room.on(RoomEvent.Connected, async () => {\r\n this.onConnected?.();\r\n\r\n try {\r\n await room.startAudio();\r\n\r\n if (this.user || this.context) {\r\n await room.localParticipant.publishData(\r\n new TextEncoder().encode(\r\n JSON.stringify({\r\n type: \"session_init\",\r\n user: this.user,\r\n context: this.context,\r\n })\r\n ),\r\n {\r\n reliable: true,\r\n topic: \"session\",\r\n }\r\n );\r\n }\r\n\r\n if (this.mode !== \"chat\") {\r\n await room.localParticipant.setMicrophoneEnabled(\r\n true\r\n );\r\n }\r\n\r\n this.onMicState?.(true);\r\n } catch (err: any) {\r\n this.onError?.(\r\n err?.message ||\r\n \"Failed to start audio\"\r\n );\r\n }\r\n });\r\n\r\n /**\r\n * ------------------------------------------------------------------------\r\n * Disconnected\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\n room.on(RoomEvent.Disconnected, () => {\r\n this.onDisconnected?.();\r\n });\r\n\r\n /**\r\n * ------------------------------------------------------------------------\r\n * Reconnecting\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\n room.on(RoomEvent.Reconnecting, () => {\r\n this.onReconnecting?.();\r\n });\r\n\r\n /**\r\n * ------------------------------------------------------------------------\r\n * Reconnected\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\n room.on(RoomEvent.Reconnected, () => {\r\n this.onReconnected?.();\r\n });\r\n\r\n /**\r\n * ------------------------------------------------------------------------\r\n * Audio tracks\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\n room.on(\r\n RoomEvent.TrackSubscribed,\r\n (track, _, participant) => {\r\n console.log(\"Track subscribed:\", participant.identity);\r\n if (\r\n track.kind ===\r\n Track.Kind.Audio\r\n ) {\r\n const audioElement = attachAudioTrack(\r\n track,\r\n participant.identity,\r\n this.audioContainer\r\n );\r\n\r\n audioElement.muted = this.speakerMuted;\r\n audioElement.volume = this.speakerMuted ? 0 : 1;\r\n\r\n if (!this.speakerMuted) {\r\n audioElement.play().catch(console.error);\r\n }\r\n }\r\n }\r\n );\r\n\r\n room.on(\r\n RoomEvent.TrackUnsubscribed,\r\n (track) => {\r\n if (\r\n track.kind ===\r\n Track.Kind.Audio\r\n ) {\r\n detachAudioTrack(track);\r\n }\r\n }\r\n );\r\n\r\n /**\r\n * ------------------------------------------------------------------------\r\n * Connection quality\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\n room.on(\r\n RoomEvent.ConnectionQualityChanged,\r\n (quality, participant) => {\r\n if (\r\n participant ===\r\n room.localParticipant\r\n ) {\r\n this.onQuality?.(quality);\r\n }\r\n }\r\n );\r\n\r\n /**\r\n * ------------------------------------------------------------------------\r\n * Agent participant\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\n room.on(\r\n RoomEvent.ParticipantConnected,\r\n (participant) => {\r\n if (\r\n participant.kind ===\r\n ParticipantKind.AGENT\r\n ) {\r\n this.onAgentState?.(\r\n \"listening\"\r\n );\r\n }\r\n }\r\n );\r\n\r\n /**\r\n * ------------------------------------------------------------------------\r\n * Transcriptions\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\n room.on(\r\n RoomEvent.TranscriptionReceived,\r\n (segments, participant) => {\r\n for (const segment of segments) {\r\n const isAgent =\r\n participant?.kind ===\r\n ParticipantKind.AGENT;\r\n\r\n this.onMessage?.({\r\n id: segment.id,\r\n type: isAgent\r\n ? \"assistant_voice\"\r\n : \"user_voice\",\r\n text: segment.text,\r\n final: segment.final,\r\n timestamp: Date.now(),\r\n });\r\n }\r\n }\r\n );\r\n\r\n /**\r\n * ------------------------------------------------------------------------\r\n * Data messages\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\n room.on(\r\n RoomEvent.DataReceived,\r\n (\r\n payload,\r\n participant,\r\n kind,\r\n topic\r\n ) => {\r\n try {\r\n const decoded = JSON.parse(new TextDecoder().decode(payload));\r\n\r\n console.log(\r\n \"[DATA_RECEIVED]\",\r\n {\r\n topic,\r\n participant: participant?.identity,\r\n raw: decoded,\r\n }\r\n );\r\n\r\n if (topic === this.VOICE_ACTION_TOPIC) {\r\n const event = decoded as VoiceActionEvent;\r\n\r\n this.onVoiceAction?.(event);\r\n this.handleVoiceAction(event);\r\n\r\n return;\r\n }\r\n\r\n if (topic === this.VOICE_ACTION_RESULT_TOPIC) {\r\n this.onVoiceActionResult?.(\r\n decoded as VoiceActionResult\r\n );\r\n\r\n return;\r\n }\r\n\r\n /**\r\n * --------------------------------------------------------------\r\n * Agent state\r\n * --------------------------------------------------------------\r\n */\r\n\r\n if (decoded.type === \"agent_state\") {\r\n this.onAgentState?.(\r\n decoded.state\r\n );\r\n }\r\n\r\n /**\r\n * --------------------------------------------------------------\r\n * Assistant text\r\n * --------------------------------------------------------------\r\n */\r\n\r\n if (decoded.type === \"assistant_text\") {\r\n this.onMessage?.({\r\n id: decoded.id,\r\n type: \"assistant_text\",\r\n text: decoded.text,\r\n final: true,\r\n timestamp: Date.now(),\r\n });\r\n }\r\n } catch (err) {\r\n console.error(err);\r\n }\r\n }\r\n );\r\n\r\n /**\r\n * ------------------------------------------------------------------------\r\n * Connect room\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\n await room.connect(url, token);\r\n }\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Disconnect\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n async disconnect() {\r\n if (!this.room) return;\r\n\r\n try {\r\n await this.room.localParticipant.setMicrophoneEnabled(\r\n false\r\n );\r\n } catch { }\r\n\r\n await this.room.disconnect();\r\n\r\n this.room = null;\r\n }\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Toggle microphone\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n async toggleMic(\r\n enabled: boolean\r\n ) {\r\n if (!this.room) return;\r\n\r\n await this.room.localParticipant.setMicrophoneEnabled(\r\n enabled\r\n );\r\n\r\n this.onMicState?.(enabled);\r\n }\r\n\r\n setSpeakerMuted(muted: boolean) {\r\n this.speakerMuted = muted;\r\n\r\n const audioElements =\r\n this.audioContainer.querySelectorAll(\"audio\");\r\n\r\n audioElements.forEach((audio) => {\r\n const el = audio as HTMLAudioElement;\r\n\r\n el.muted = muted;\r\n el.volume = muted ? 0 : 1;\r\n if (!muted) {\r\n el.play().catch(console.error);\r\n }\r\n });\r\n }\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Send text message\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n async sendText(text: string) {\r\n if (!this.room) return;\r\n\r\n console.log(\"[sendText] called:\", text);\r\n\r\n const lp = this.room.localParticipant as any;\r\n\r\n try {\r\n if (typeof lp.sendText === \"function\") {\r\n await lp.sendText(text, {\r\n topic: \"lk.chat\",\r\n });\r\n\r\n console.log(\r\n \"[sendText] sent via LiveKit TextStream\"\r\n );\r\n } else {\r\n await lp.publishData(\r\n new TextEncoder().encode(\r\n JSON.stringify({\r\n message: text,\r\n })\r\n ),\r\n {\r\n reliable: true,\r\n topic: \"lk.chat\",\r\n }\r\n );\r\n\r\n console.log(\r\n \"[sendText] sent via publishData fallback\"\r\n );\r\n }\r\n\r\n this.onMessage?.({\r\n id: crypto.randomUUID(),\r\n type: \"user_text\",\r\n text,\r\n final: true,\r\n timestamp: Date.now(),\r\n });\r\n } catch (err) {\r\n console.error(\r\n \"[sendText] failed\",\r\n err\r\n );\r\n }\r\n }\r\n\r\n async publishActionResult(\r\n result: VoiceActionResult\r\n ) {\r\n if (!this.room) return;\r\n\r\n console.log(\r\n \"[publishActionResult] Sending result:\",\r\n JSON.stringify(result, null, 2)\r\n );\r\n\r\n await this.room.localParticipant.publishData(\r\n new TextEncoder().encode(\r\n JSON.stringify(result)\r\n ),\r\n {\r\n reliable: true,\r\n topic: this.VOICE_ACTION_RESULT_TOPIC,\r\n }\r\n );\r\n }\r\n}","export function attachAudioTrack(\r\n track: any,\r\n participantId: string,\r\n container: HTMLDivElement\r\n): HTMLAudioElement {\r\n const element =\r\n track.attach() as HTMLAudioElement;\r\n\r\n element.id = `audio-${participantId}`;\r\n element.autoplay = false;\r\n (element as any).playsInline = true;\r\n\r\n container.appendChild(element);\r\n return element;\r\n}\r\n\r\nexport function detachAudioTrack(track: any) {\r\n track.detach().forEach((el: HTMLElement) => el.remove());\r\n}\r\n","import {\r\n VoiceActionHandler,\r\n} from \"../types/sdk.types\";\r\n\r\nexport class ActionRegistry {\r\n private handlers = new Map<\r\n string,\r\n VoiceActionHandler\r\n >();\r\n\r\n /**\r\n * Register handler\r\n *\r\n * Example:\r\n *\r\n * registry.register(\r\n * \"evt_search_product\",\r\n * handler\r\n * );\r\n */\r\n register(\r\n eventId: string,\r\n handler: VoiceActionHandler\r\n ): void {\r\n this.handlers.set(\r\n eventId,\r\n handler\r\n );\r\n }\r\n\r\n /**\r\n * Remove handler\r\n */\r\n unregister(\r\n eventId: string\r\n ): boolean {\r\n return this.handlers.delete(\r\n eventId\r\n );\r\n }\r\n\r\n /**\r\n * Resolve handler\r\n *\r\n * Resolution order:\r\n *\r\n * 1. Exact match\r\n * 2. Wildcard (*)\r\n */\r\n resolve(\r\n eventId: string\r\n ): VoiceActionHandler | undefined {\r\n return (\r\n this.handlers.get(eventId) ??\r\n this.handlers.get(\"*\")\r\n );\r\n }\r\n\r\n /**\r\n * Check existence\r\n */\r\n has(\r\n eventId: string\r\n ): boolean {\r\n return this.handlers.has(\r\n eventId\r\n );\r\n }\r\n\r\n /**\r\n * Remove everything\r\n */\r\n clear(): void {\r\n this.handlers.clear();\r\n }\r\n\r\n /**\r\n * Registered event ids\r\n */\r\n getRegisteredEvents(): string[] {\r\n return Array.from(\r\n this.handlers.keys()\r\n );\r\n }\r\n\r\n /**\r\n * Count handlers\r\n */\r\n size(): number {\r\n return this.handlers.size;\r\n }\r\n}","\"use client\";\r\n\r\nimport { useCallback, useMemo, useRef, useState } from \"react\";\r\n\r\nimport {\r\n ConversationMessage,\r\n MessageType,\r\n} from \"../types/sdk.types\";\r\n\r\ninterface TranscriptSegment {\r\n id: string;\r\n text: string;\r\n final: boolean;\r\n timestamp?: number;\r\n}\r\n\r\ninterface UseTranscriptSyncOptions {\r\n maxMessages?: number;\r\n enableGrouping?: boolean;\r\n}\r\n\r\ninterface UseTranscriptSyncReturn {\r\n messages: ConversationMessage[];\r\n\r\n addTranscriptSegment: (\r\n segment: TranscriptSegment,\r\n type: MessageType\r\n ) => void;\r\n\r\n addTextMessage: (\r\n text: string,\r\n type: MessageType\r\n ) => void;\r\n\r\n updateMessage: (\r\n id: string,\r\n text: string,\r\n final?: boolean\r\n ) => void;\r\n\r\n removeMessage: (id: string) => void;\r\n\r\n clearMessages: () => void;\r\n\r\n getLatestMessage: () => ConversationMessage | null;\r\n\r\n hasPendingMessages: boolean;\r\n}\r\n\r\n/**\r\n * ----------------------------------------------------------------------------\r\n * useTranscriptSync\r\n * ----------------------------------------------------------------------------\r\n *\r\n * Handles:\r\n * - Partial transcript streaming\r\n * - Final transcript reconciliation\r\n * - Ordered transcript timeline\r\n * - Text + voice synchronization\r\n * - Message deduplication\r\n * - Optimistic updates\r\n * - Transcript grouping\r\n * - Performance-safe state updates\r\n *\r\n * ----------------------------------------------------------------------------\r\n */\r\n\r\nexport function useTranscriptSync(\r\n options?: UseTranscriptSyncOptions\r\n): UseTranscriptSyncReturn {\r\n const {\r\n maxMessages = 500,\r\n enableGrouping = true,\r\n } = options || {};\r\n\r\n const [messages, setMessages] = useState<\r\n ConversationMessage[]\r\n >([]);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Fast lookup map\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const messageMapRef = useRef<\r\n Map<string, ConversationMessage>\r\n >(new Map());\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Merge and sort helper\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const commitMessages = useCallback(() => {\r\n const merged = Array.from(\r\n messageMapRef.current.values()\r\n )\r\n .sort((a, b) => a.timestamp - b.timestamp)\r\n .slice(-maxMessages);\r\n\r\n setMessages(merged);\r\n }, [maxMessages]);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Group adjacent partials\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const mergeAdjacentPartials = useCallback(\r\n (\r\n existing: ConversationMessage,\r\n incoming: ConversationMessage\r\n ) => {\r\n if (!enableGrouping) return incoming;\r\n\r\n if (\r\n existing.type === incoming.type &&\r\n !existing.final &&\r\n !incoming.final\r\n ) {\r\n return {\r\n ...existing,\r\n text: incoming.text,\r\n timestamp: incoming.timestamp,\r\n };\r\n }\r\n\r\n return incoming;\r\n },\r\n [enableGrouping]\r\n );\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Add transcript segment\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const addTranscriptSegment = useCallback(\r\n (\r\n segment: TranscriptSegment,\r\n type: MessageType\r\n ) => {\r\n const timestamp =\r\n segment.timestamp || Date.now();\r\n\r\n const incomingMessage: ConversationMessage = {\r\n id: segment.id,\r\n type,\r\n text: segment.text,\r\n final: segment.final,\r\n timestamp,\r\n };\r\n\r\n const existing =\r\n messageMapRef.current.get(segment.id);\r\n\r\n /**\r\n * --------------------------------------------------------------\r\n * Update existing partial/final transcript\r\n * --------------------------------------------------------------\r\n */\r\n\r\n if (existing) {\r\n const merged =\r\n mergeAdjacentPartials(\r\n existing,\r\n incomingMessage\r\n );\r\n\r\n /**\r\n * ----------------------------------------------------------\r\n * Preserve final transcript once finalized\r\n * ----------------------------------------------------------\r\n */\r\n\r\n if (existing.final) {\r\n return;\r\n }\r\n\r\n /**\r\n * ----------------------------------------------------------\r\n * Upgrade partial → final\r\n * ----------------------------------------------------------\r\n */\r\n\r\n messageMapRef.current.set(segment.id, {\r\n ...merged,\r\n final: segment.final,\r\n });\r\n\r\n commitMessages();\r\n\r\n return;\r\n }\r\n\r\n /**\r\n * --------------------------------------------------------------\r\n * New transcript message\r\n * --------------------------------------------------------------\r\n */\r\n\r\n messageMapRef.current.set(\r\n segment.id,\r\n incomingMessage\r\n );\r\n\r\n commitMessages();\r\n },\r\n [commitMessages, mergeAdjacentPartials]\r\n );\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Add regular text message\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const addTextMessage = useCallback(\r\n (\r\n text: string,\r\n type: MessageType\r\n ) => {\r\n const id = crypto.randomUUID();\r\n\r\n const message: ConversationMessage = {\r\n id,\r\n type,\r\n text,\r\n final: true,\r\n timestamp: Date.now(),\r\n };\r\n\r\n messageMapRef.current.set(id, message);\r\n\r\n commitMessages();\r\n },\r\n [commitMessages]\r\n );\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Update existing message\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const updateMessage = useCallback(\r\n (\r\n id: string,\r\n text: string,\r\n final = true\r\n ) => {\r\n const existing =\r\n messageMapRef.current.get(id);\r\n\r\n if (!existing) return;\r\n\r\n messageMapRef.current.set(id, {\r\n ...existing,\r\n text,\r\n final,\r\n timestamp: Date.now(),\r\n });\r\n\r\n commitMessages();\r\n },\r\n [commitMessages]\r\n );\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Remove message\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const removeMessage = useCallback(\r\n (id: string) => {\r\n messageMapRef.current.delete(id);\r\n\r\n commitMessages();\r\n },\r\n [commitMessages]\r\n );\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Clear all messages\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const clearMessages = useCallback(() => {\r\n messageMapRef.current.clear();\r\n\r\n setMessages([]);\r\n }, []);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Latest message\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const getLatestMessage = useCallback(() => {\r\n if (!messages.length) return null;\r\n\r\n return messages[messages.length - 1];\r\n }, [messages]);\r\n\r\n /**\r\n * --------------------------------------------------------------------------\r\n * Pending partial transcripts\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\n const hasPendingMessages = useMemo(() => {\r\n return messages.some((m) => !m.final);\r\n }, [messages]);\r\n\r\n return {\r\n messages,\r\n addTranscriptSegment,\r\n addTextMessage,\r\n updateMessage,\r\n removeMessage,\r\n clearMessages,\r\n getLatestMessage,\r\n hasPendingMessages,\r\n };\r\n}","import \"./index.css\";\r\n\r\nimport FloatingMic from \"./components/FloatingMic\";\r\nimport VoicePanel from \"./components/VoicePannel\";\r\nimport {LiveKitProvider} from \"./providers/LiveKitProvider\";\r\nimport type {\r\n VoiceActionHandlers,\r\n VoiceActionEvent,\r\n VoiceActionResult,\r\n} from \"./types/sdk.types\";\r\n\r\nexport { LiveKitProvider, FloatingMic, VoicePanel };\r\n\r\nexport type {\r\n VoiceActionHandlers,\r\n VoiceActionEvent,\r\n VoiceActionResult,\r\n} from \"./types/sdk.types\";\r\nexport default FloatingMic;\r\n"],"mappings":"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","names":["useEffect","useState","useMemo","Mic","useCallback","useEffect","useMemo","useRef","useState","useMemo","useRef","useState","jsx","jsxs","useRef","useState","useEffect","useCallback","useMemo","Fragment","jsx","jsxs","useState","useEffect","useMemo","Mic"]}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "vibrium-speak-sdk",
3
+ "version": "1.0.0",
4
+ "main": "./dist/index.umd.js",
5
+ "module": "./dist/index.es.js",
6
+ "types": "./dist/index.d.ts",
7
+ "sideEffects": [
8
+ "*.css"
9
+ ],
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.mjs",
14
+ "require": "./dist/index.umd.js"
15
+ },
16
+ "./style.css": "./dist/index.css"
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "dev": "tsup --watch"
24
+ },
25
+ "peerDependencies": {
26
+ "react": ">=18 <20",
27
+ "react-dom": ">=18 <20"
28
+ },
29
+ "dependencies": {
30
+ "@livekit/components-react": "^2.9.21",
31
+ "clsx": "^2.1.1",
32
+ "livekit-client": "^2.15.0",
33
+ "lucide-react": "^0.525.0",
34
+ "react-icons": "^5.6.0",
35
+ "typescript": "^5.4.0",
36
+ "tailwindcss": "^4"
37
+ },
38
+ "devDependencies": {
39
+ "@types/react": "^19.2.14",
40
+ "@types/react-dom": "^19.2.3",
41
+ "@tailwindcss/postcss": "^4.3.0",
42
+ "autoprefixer": "^10.5.0",
43
+ "postcss": "^8.5.15",
44
+ "tailwindcss": "^4.3.0",
45
+ "tsup": "^8.0.0",
46
+ "typescript": "^5.0.0"
47
+ }
48
+ }