kanha-ai 0.1.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/use-kanha-chat.ts","../src/styles.ts","../src/KanhaBot.tsx"],"names":["useState","useRef","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import { useState, useEffect, useRef, useCallback } from \"react\";\nimport type { Message, InferenceMode, KanhaChatConfig, KanhaChatReturn } from \"./types\";\n\nconst MODEL_LIB_PREFIX =\n \"https://raw.githubusercontent.com/mlc-ai/binary-mlc-llm-libs/main/web-llm-models/v0_2_80\";\n\nconst WASM_BY_SIZE: Record<string, string> = {\n small: `${MODEL_LIB_PREFIX}/Qwen3-0.6B-q4f16_1-ctx4k_cs1k-webgpu.wasm`,\n medium: `${MODEL_LIB_PREFIX}/Qwen3-1.7B-q4f16_1-ctx4k_cs1k-webgpu.wasm`,\n large: `${MODEL_LIB_PREFIX}/Qwen3-4B-q4f16_1-ctx4k_cs1k-webgpu.wasm`,\n};\n\nfunction resolveModelLib(config: KanhaChatConfig): string {\n if (config.modelLib) return config.modelLib;\n const size = config.modelSize ?? \"small\";\n const lib = WASM_BY_SIZE[size];\n if (!lib) throw new Error(`Unknown model size \"${size}\". Provide modelLib explicitly.`);\n return lib;\n}\n\n/**\n * Converts a storage URL into a format web-llm's cleanModelUrl won't mangle.\n * web-llm checks for /resolve/ in the URL — if missing, it appends /resolve/main/.\n * We append /resolve/v1/ so the URL passes through untouched.\n * Files must be stored at {modelUrl}/resolve/v1/{filename} in storage.\n */\nfunction toWebLLMModelUrl(modelUrl: string): string {\n let url = modelUrl.endsWith(\"/\") ? modelUrl.slice(0, -1) : modelUrl;\n if (!url.includes(\"/resolve/\")) {\n url += \"/resolve/v1\";\n }\n return url;\n}\n\nasync function checkWebGPU(): Promise<boolean> {\n try {\n const nav = navigator as Navigator & { gpu?: { requestAdapter(): Promise<unknown> } };\n if (!nav.gpu) return false;\n const adapter = (await nav.gpu.requestAdapter()) as { requestDevice(): Promise<unknown> } | null;\n if (!adapter) return false;\n const device = await adapter.requestDevice();\n return !!device;\n } catch {\n return false;\n }\n}\n\nfunction stripThinkTokens(text: string): string {\n let cleaned = text.replace(/<think>[\\s\\S]*?<\\/think>/g, \"\");\n cleaned = cleaned.replace(/<think>[\\s\\S]*$/g, \"\");\n return cleaned.trimStart();\n}\n\nexport function useKanhaChat(config: KanhaChatConfig): KanhaChatReturn {\n const [messages, setMessages] = useState<Message[]>([]);\n const [input, setInput] = useState(\"\");\n const [isLoading, setIsLoading] = useState(false);\n const [isThinking, setIsThinking] = useState(false);\n const [mode, setMode] = useState<InferenceMode>(\"detecting\");\n const [loadProgress, setLoadProgress] = useState(0);\n const [error, setError] = useState<string | null>(null);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const engineRef = useRef<any>(null);\n const configRef = useRef(config);\n configRef.current = config;\n\n const updateAssistantMessage = useCallback((text: string) => {\n const cleaned = stripThinkTokens(text);\n if (!cleaned) {\n setIsThinking(true);\n return;\n }\n setIsThinking(false);\n setMessages((prev) => {\n const msgs = [...prev];\n if (msgs[msgs.length - 1]?.role === \"assistant\") {\n msgs[msgs.length - 1] = { role: \"assistant\", content: cleaned };\n } else {\n msgs.push({ role: \"assistant\", content: cleaned });\n }\n return msgs;\n });\n }, []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n let cancelled = false;\n\n const init = async () => {\n setMode(\"detecting\");\n\n const hasWebGPU = await checkWebGPU();\n if (!hasWebGPU) {\n setMode(\"error\");\n setError(\"WebGPU is not supported in this browser. Try Chrome 113+ or Edge 113+.\");\n return;\n }\n\n if (cancelled) return;\n setMode(\"loading\");\n\n try {\n const webllm = await import(\"@mlc-ai/web-llm\");\n const modelId = \"kanha-custom-model\";\n const modelLib = resolveModelLib(configRef.current);\n const modelUrl = toWebLLMModelUrl(configRef.current.modelUrl);\n\n const engine = await webllm.CreateMLCEngine(modelId, {\n appConfig: {\n model_list: [\n {\n model: modelUrl,\n model_id: modelId,\n model_lib: modelLib,\n overrides: {\n context_window_size: configRef.current.contextWindowSize ?? 4096,\n },\n },\n ],\n },\n initProgressCallback: (report: { progress: number }) => {\n if (!cancelled) setLoadProgress(Math.round(report.progress * 100));\n },\n });\n\n if (cancelled) return;\n engineRef.current = engine;\n setMode(\"ready\");\n } catch (err) {\n if (cancelled) return;\n setMode(\"error\");\n setError(\n err instanceof Error ? err.message : \"Failed to load AI model.\"\n );\n }\n };\n\n init();\n return () => { cancelled = true; };\n }, [config.modelUrl, config.modelLib, config.modelSize]);\n\n const send = useCallback(async () => {\n if (!input.trim() || mode !== \"ready\" || isLoading || !engineRef.current) return;\n\n const userMsg: Message = { role: \"user\", content: input.trim() };\n const allMessages = [...messages, userMsg];\n setMessages(allMessages);\n setInput(\"\");\n setIsLoading(true);\n setIsThinking(true);\n setError(null);\n\n try {\n const systemMessages: Message[] = configRef.current.systemPrompt\n ? [{ role: \"system\", content: configRef.current.systemPrompt }]\n : [];\n\n const completion = await engineRef.current.chat.completions.create({\n messages: [...systemMessages, ...allMessages],\n temperature: configRef.current.temperature ?? 0.7,\n max_tokens: configRef.current.maxTokens ?? 1024,\n stream: true,\n });\n\n let text = \"\";\n for await (const chunk of completion) {\n const delta = chunk.choices[0]?.delta?.content || \"\";\n text += delta;\n updateAssistantMessage(text);\n }\n } catch {\n setError(\"Failed to generate response. Please try again.\");\n setMessages((prev) => [\n ...prev,\n { role: \"assistant\", content: \"Sorry, I encountered an error. Please try again.\" },\n ]);\n } finally {\n setIsLoading(false);\n setIsThinking(false);\n }\n }, [input, mode, isLoading, messages, updateAssistantMessage]);\n\n const clear = useCallback(() => {\n setMessages([]);\n setError(null);\n }, []);\n\n return {\n messages,\n input,\n setInput,\n isLoading,\n isThinking,\n mode,\n loadProgress,\n error,\n send,\n clear,\n };\n}\n","import type { CSSProperties } from \"react\";\n\nexport function fabStyle(\n primaryColor: string,\n position: \"bottom-right\" | \"bottom-left\",\n): CSSProperties {\n return {\n position: \"fixed\",\n bottom: 24,\n [position === \"bottom-right\" ? \"right\" : \"left\"]: 24,\n width: 56,\n height: 56,\n borderRadius: \"50%\",\n background: primaryColor,\n color: \"#fff\",\n border: \"none\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"0 4px 12px rgba(0,0,0,0.15)\",\n zIndex: 9999,\n transition: \"transform 0.15s ease, box-shadow 0.15s ease\",\n };\n}\n\nexport function panelStyle(position: \"bottom-right\" | \"bottom-left\"): CSSProperties {\n return {\n position: \"fixed\",\n bottom: 96,\n [position === \"bottom-right\" ? \"right\" : \"left\"]: 24,\n width: 384,\n maxWidth: \"calc(100vw - 48px)\",\n maxHeight: \"calc(100vh - 120px)\",\n borderRadius: 16,\n overflow: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n boxShadow: \"0 8px 30px rgba(0,0,0,0.12)\",\n border: \"1px solid #e5e7eb\",\n background: \"#ffffff\",\n zIndex: 9999,\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n };\n}\n\nexport const headerStyle: CSSProperties = {\n padding: \"16px\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n};\n\nexport const headerTitleStyle: CSSProperties = {\n fontWeight: 600,\n fontSize: 15,\n margin: 0,\n};\n\nexport const headerSubtitleStyle: CSSProperties = {\n fontSize: 12,\n opacity: 0.85,\n margin: \"4px 0 0\",\n};\n\nexport const messagesContainerStyle: CSSProperties = {\n flex: 1,\n overflowY: \"auto\",\n padding: 16,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 12,\n minHeight: 300,\n maxHeight: 384,\n background: \"#fafafa\",\n};\n\nexport const emptyStateStyle: CSSProperties = {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n height: \"100%\",\n textAlign: \"center\",\n color: \"#6b7280\",\n fontSize: 14,\n padding: 16,\n};\n\nexport function userBubbleStyle(primaryColor: string): CSSProperties {\n return {\n maxWidth: \"80%\",\n padding: \"8px 14px\",\n borderRadius: 16,\n background: primaryColor,\n color: \"#fff\",\n fontSize: 14,\n lineHeight: 1.5,\n alignSelf: \"flex-end\",\n wordBreak: \"break-word\",\n };\n}\n\nexport const assistantBubbleStyle: CSSProperties = {\n maxWidth: \"80%\",\n padding: \"8px 14px\",\n borderRadius: 16,\n background: \"#fff\",\n color: \"#1f2937\",\n fontSize: 14,\n lineHeight: 1.5,\n border: \"1px solid #e5e7eb\",\n alignSelf: \"flex-start\",\n wordBreak: \"break-word\",\n};\n\nexport const inputBarStyle: CSSProperties = {\n display: \"flex\",\n gap: 8,\n padding: \"12px 16px\",\n borderTop: \"1px solid #e5e7eb\",\n background: \"#fff\",\n};\n\nexport const textareaStyle: CSSProperties = {\n flex: 1,\n padding: \"8px 12px\",\n border: \"1px solid #e5e7eb\",\n borderRadius: 10,\n fontSize: 14,\n resize: \"none\",\n overflow: \"hidden\",\n outline: \"none\",\n fontFamily: \"inherit\",\n minHeight: 40,\n maxHeight: 120,\n lineHeight: 1.5,\n};\n\nexport function sendButtonStyle(primaryColor: string): CSSProperties {\n return {\n padding: \"8px 14px\",\n background: primaryColor,\n color: \"#fff\",\n border: \"none\",\n borderRadius: 10,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flexShrink: 0,\n transition: \"opacity 0.15s ease\",\n };\n}\n\nexport const iconButtonStyle: CSSProperties = {\n background: \"none\",\n border: \"none\",\n color: \"inherit\",\n cursor: \"pointer\",\n padding: 4,\n borderRadius: 8,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n opacity: 0.8,\n transition: \"opacity 0.15s ease\",\n};\n\nexport function suggestionButtonStyle(primaryColor: string): CSSProperties {\n return {\n fontSize: 13,\n padding: \"8px 12px\",\n borderRadius: 10,\n border: \"1px solid #e5e7eb\",\n background: \"#fff\",\n color: \"#374151\",\n cursor: \"pointer\",\n textAlign: \"left\" as const,\n width: \"100%\",\n transition: \"border-color 0.15s ease\",\n // hover handled inline\n };\n}\n\nexport const progressBarContainer: CSSProperties = {\n width: \"60%\",\n height: 4,\n borderRadius: 2,\n background: \"rgba(255,255,255,0.3)\",\n marginTop: 8,\n overflow: \"hidden\",\n};\n\nexport function progressBarFill(progress: number, primaryColor: string): CSSProperties {\n return {\n width: `${progress}%`,\n height: \"100%\",\n borderRadius: 2,\n background: primaryColor,\n transition: \"width 0.3s ease\",\n };\n}\n","import {\n useState,\n useEffect,\n useRef,\n type KeyboardEvent,\n type CSSProperties,\n} from \"react\";\nimport ReactMarkdown from \"react-markdown\";\nimport { useKanhaChat } from \"./use-kanha-chat\";\nimport type { KanhaBotProps } from \"./types\";\nimport * as s from \"./styles\";\n\n// Inline SVG icons (no icon library dependency)\nconst ChatIcon = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n);\n\nconst CloseIcon = () => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" /><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n);\n\nconst SendIcon = () => (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" /><polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n);\n\nconst TrashIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"3 6 5 6 21 6\" /><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n </svg>\n);\n\nconst Spinner = ({ size = 18 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" style={{ animation: \"kanha-spin 1s linear infinite\" }}>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n);\n\nconst spinKeyframes = `@keyframes kanha-spin { to { transform: rotate(360deg); } }`;\nconst bounceKeyframes = `\n@keyframes kanha-bounce {\n 0%, 80%, 100% { transform: translateY(0); }\n 40% { transform: translateY(-4px); }\n}`;\n\nfunction ThinkingDots() {\n const dotStyle = (delay: number): CSSProperties => ({\n width: 6,\n height: 6,\n borderRadius: \"50%\",\n background: \"#9ca3af\",\n animation: `kanha-bounce 1.2s ease-in-out ${delay}ms infinite`,\n });\n return (\n <span style={{ display: \"flex\", gap: 3, alignItems: \"center\" }}>\n <span style={dotStyle(0)} />\n <span style={dotStyle(150)} />\n <span style={dotStyle(300)} />\n <span style={{ fontSize: 12, color: \"#9ca3af\", marginLeft: 6 }}>Thinking</span>\n </span>\n );\n}\n\nexport function KanhaBot({\n modelUrl,\n modelLib,\n modelSize,\n systemPrompt,\n temperature,\n maxTokens,\n contextWindowSize,\n botName = \"AI Assistant\",\n welcomeMessage = \"Ask me anything!\",\n suggestions = [],\n theme = {},\n}: KanhaBotProps) {\n const primaryColor = theme.primaryColor ?? \"#0d9488\";\n const position = theme.position ?? \"bottom-right\";\n\n const {\n messages,\n input,\n setInput,\n isLoading,\n isThinking,\n mode,\n loadProgress,\n error,\n send,\n clear,\n } = useKanhaChat({\n modelUrl,\n modelLib,\n modelSize,\n systemPrompt,\n temperature,\n maxTokens,\n contextWindowSize,\n });\n\n const [isOpen, setIsOpen] = useState(false);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n useEffect(() => {\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\";\n textareaRef.current.style.height = Math.min(textareaRef.current.scrollHeight, 120) + \"px\";\n }\n }, [input]);\n\n const handleKeyPress = (e: KeyboardEvent) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n send();\n }\n };\n\n const isReady = mode === \"ready\";\n\n return (\n <>\n <style>{spinKeyframes}{bounceKeyframes}</style>\n\n {isOpen && (\n <div style={s.panelStyle(position)}>\n {/* Header */}\n <div style={{ ...s.headerStyle, background: primaryColor }}>\n <div>\n <p style={s.headerTitleStyle}>{botName}</p>\n <p style={s.headerSubtitleStyle}>\n {isReady\n ? welcomeMessage\n : mode === \"loading\"\n ? `Loading AI model (${loadProgress}%)`\n : mode === \"error\"\n ? \"Failed to load\"\n : \"Detecting capabilities...\"}\n </p>\n {mode === \"loading\" && (\n <div style={s.progressBarContainer}>\n <div style={s.progressBarFill(loadProgress, \"#fff\")} />\n </div>\n )}\n </div>\n <div style={{ display: \"flex\", gap: 4 }}>\n {messages.length > 0 && (\n <button onClick={clear} style={s.iconButtonStyle} aria-label=\"Clear chat\">\n <TrashIcon />\n </button>\n )}\n <button onClick={() => setIsOpen(false)} style={s.iconButtonStyle} aria-label=\"Close\">\n <CloseIcon />\n </button>\n </div>\n </div>\n\n {/* Error banner */}\n {error && (\n <div style={{ padding: \"10px 16px\", background: \"#fef2f2\", borderBottom: \"1px solid #fecaca\", fontSize: 13, color: \"#b91c1c\" }}>\n {error}\n </div>\n )}\n\n {/* Messages */}\n <div style={s.messagesContainerStyle}>\n {messages.length === 0 ? (\n <div style={s.emptyStateStyle}>\n {isReady ? (\n <>\n <ChatIcon />\n <p style={{ marginTop: 12, fontWeight: 500, color: \"#374151\" }}>\n {welcomeMessage}\n </p>\n {suggestions.length > 0 && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 6, width: \"100%\", marginTop: 16 }}>\n {suggestions.map((text) => (\n <button\n key={text}\n onClick={() => { setInput(text); setTimeout(send, 0); }}\n style={s.suggestionButtonStyle(primaryColor)}\n onMouseEnter={(e) => { (e.target as HTMLElement).style.borderColor = primaryColor; }}\n onMouseLeave={(e) => { (e.target as HTMLElement).style.borderColor = \"#e5e7eb\"; }}\n >\n {text}\n </button>\n ))}\n </div>\n )}\n </>\n ) : mode === \"loading\" ? (\n <>\n <Spinner size={32} />\n <p style={{ marginTop: 8 }}>Loading AI model ({loadProgress}%)</p>\n <p style={{ fontSize: 12, marginTop: 4 }}>First load takes about a minute</p>\n </>\n ) : mode === \"error\" ? (\n <p>{error}</p>\n ) : (\n <>\n <Spinner size={32} />\n <p style={{ marginTop: 8 }}>Detecting browser capabilities...</p>\n </>\n )}\n </div>\n ) : (\n <>\n {messages.map((msg, i) => (\n <div\n key={i}\n style={{\n display: \"flex\",\n justifyContent: msg.role === \"user\" ? \"flex-end\" : \"flex-start\",\n }}\n >\n <div style={msg.role === \"user\" ? s.userBubbleStyle(primaryColor) : s.assistantBubbleStyle}>\n {msg.role === \"assistant\" ? (\n <ReactMarkdown>{msg.content}</ReactMarkdown>\n ) : (\n <span style={{ whiteSpace: \"pre-wrap\" }}>{msg.content}</span>\n )}\n </div>\n </div>\n ))}\n {isLoading && (isThinking || messages[messages.length - 1]?.role !== \"assistant\") && (\n <div style={{ display: \"flex\", justifyContent: \"flex-start\" }}>\n <div style={s.assistantBubbleStyle}>\n {isThinking ? <ThinkingDots /> : <Spinner size={16} />}\n </div>\n </div>\n )}\n <div ref={messagesEndRef} />\n </>\n )}\n </div>\n\n {/* Input */}\n <div style={s.inputBarStyle}>\n <textarea\n ref={textareaRef}\n value={input}\n onChange={(e) => setInput(e.target.value)}\n onKeyDown={handleKeyPress}\n placeholder={isReady ? \"Type your message...\" : \"Waiting for model...\"}\n disabled={!isReady || isLoading}\n rows={1}\n style={{\n ...s.textareaStyle,\n opacity: !isReady ? 0.5 : 1,\n }}\n />\n <button\n onClick={send}\n disabled={!isReady || isLoading || !input.trim()}\n style={{\n ...s.sendButtonStyle(primaryColor),\n opacity: !isReady || isLoading || !input.trim() ? 0.5 : 1,\n cursor: !isReady || isLoading || !input.trim() ? \"not-allowed\" : \"pointer\",\n }}\n aria-label=\"Send message\"\n >\n {isLoading ? <Spinner size={18} /> : <SendIcon />}\n </button>\n </div>\n </div>\n )}\n\n {/* FAB */}\n <button\n onClick={() => setIsOpen(!isOpen)}\n style={s.fabStyle(primaryColor, position)}\n aria-label=\"Toggle chat\"\n onMouseEnter={(e) => { (e.target as HTMLElement).style.transform = \"scale(1.05)\"; }}\n onMouseLeave={(e) => { (e.target as HTMLElement).style.transform = \"scale(1)\"; }}\n >\n {isOpen ? <CloseIcon /> : <ChatIcon />}\n </button>\n </>\n );\n}\n"]}
@@ -0,0 +1,65 @@
1
+ interface Message {
2
+ role: "user" | "assistant" | "system";
3
+ content: string;
4
+ }
5
+ type InferenceMode = "detecting" | "loading" | "ready" | "error";
6
+ interface KanhaChatConfig {
7
+ /** Base URL for model artifacts in storage (e.g. Supabase Storage public URL) */
8
+ modelUrl: string;
9
+ /** URL to the WASM library file. If omitted, auto-detected from modelSize. */
10
+ modelLib?: string;
11
+ /** Model size tier — used for WASM auto-detection. Default: "small" */
12
+ modelSize?: "small" | "medium" | "large";
13
+ /** System prompt for the bot */
14
+ systemPrompt?: string;
15
+ /** Sampling temperature (0-2). Default: 0.7 */
16
+ temperature?: number;
17
+ /** Max tokens to generate per response. Default: 1024 */
18
+ maxTokens?: number;
19
+ /** Context window size override */
20
+ contextWindowSize?: number;
21
+ }
22
+ interface KanhaBotTheme {
23
+ /** Primary brand color (hex). Default: "#0d9488" */
24
+ primaryColor?: string;
25
+ /** Widget position. Default: "bottom-right" */
26
+ position?: "bottom-right" | "bottom-left";
27
+ }
28
+ interface KanhaBotProps extends KanhaChatConfig {
29
+ /** Bot display name */
30
+ botName?: string;
31
+ /** Welcome message shown before first interaction */
32
+ welcomeMessage?: string;
33
+ /** Suggested prompts shown in empty state */
34
+ suggestions?: string[];
35
+ /** Theme customization */
36
+ theme?: KanhaBotTheme;
37
+ }
38
+
39
+ /**
40
+ * Standalone widget for CDN / vanilla JS usage.
41
+ * No React dependency — pure DOM manipulation.
42
+ *
43
+ * Usage via CDN:
44
+ * <script type="module">
45
+ * import { mount } from 'https://cdn.jsdelivr.net/npm/kanha/dist/widget.js';
46
+ * const bot = mount('#chat', { modelUrl: '...', systemPrompt: '...' });
47
+ * </script>
48
+ *
49
+ * Or as a web component:
50
+ * <script type="module" src="https://cdn.jsdelivr.net/npm/kanha/dist/widget.js"></script>
51
+ * <kanha-bot model-url="..." system-prompt="..." bot-name="Acme Bot"></kanha-bot>
52
+ */
53
+
54
+ /**
55
+ * Mount a Kanha chatbot widget onto a DOM element.
56
+ *
57
+ * @param target - CSS selector string or HTMLElement
58
+ * @param props - Bot configuration
59
+ * @returns Object with `destroy()` method to unmount
60
+ */
61
+ declare function mount(target: string | HTMLElement, props: KanhaBotProps): {
62
+ destroy: () => void;
63
+ };
64
+
65
+ export { type InferenceMode, type KanhaBotProps, type KanhaBotTheme, type Message, mount };
package/dist/widget.js ADDED
@@ -0,0 +1,414 @@
1
+ // src/widget.ts
2
+ var MODEL_LIB_PREFIX = "https://raw.githubusercontent.com/mlc-ai/binary-mlc-llm-libs/main/web-llm-models/v0_2_80";
3
+ var WASM_BY_SIZE = {
4
+ small: `${MODEL_LIB_PREFIX}/Qwen3-0.6B-q4f16_1-ctx4k_cs1k-webgpu.wasm`,
5
+ medium: `${MODEL_LIB_PREFIX}/Qwen3-1.7B-q4f16_1-ctx4k_cs1k-webgpu.wasm`,
6
+ large: `${MODEL_LIB_PREFIX}/Qwen3-4B-q4f16_1-ctx4k_cs1k-webgpu.wasm`
7
+ };
8
+ function resolveModelLib(modelLib, modelSize) {
9
+ if (modelLib) return modelLib;
10
+ const size = modelSize ?? "small";
11
+ const lib = WASM_BY_SIZE[size];
12
+ if (!lib) throw new Error(`Unknown model size "${size}". Provide modelLib explicitly.`);
13
+ return lib;
14
+ }
15
+ function toWebLLMModelUrl(modelUrl) {
16
+ let url = modelUrl.endsWith("/") ? modelUrl.slice(0, -1) : modelUrl;
17
+ if (!url.includes("/resolve/")) url += "/resolve/v1";
18
+ return url;
19
+ }
20
+ async function checkWebGPU() {
21
+ try {
22
+ const nav = navigator;
23
+ if (!nav.gpu) return false;
24
+ const adapter = await nav.gpu.requestAdapter();
25
+ if (!adapter) return false;
26
+ return !!await adapter.requestDevice();
27
+ } catch {
28
+ return false;
29
+ }
30
+ }
31
+ function stripThinkTokens(text) {
32
+ let cleaned = text.replace(/<think>[\s\S]*?<\/think>/g, "");
33
+ cleaned = cleaned.replace(/<think>[\s\S]*$/g, "");
34
+ return cleaned.trimStart();
35
+ }
36
+ function esc(text) {
37
+ const el = document.createElement("span");
38
+ el.textContent = text;
39
+ return el.innerHTML;
40
+ }
41
+ var CSS = `
42
+ :host {
43
+ all: initial;
44
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
45
+ }
46
+ @keyframes kb-spin { to { transform: rotate(360deg); } }
47
+ @keyframes kb-bounce {
48
+ 0%, 80%, 100% { transform: translateY(0); }
49
+ 40% { transform: translateY(-4px); }
50
+ }
51
+ .kb-fab {
52
+ position: fixed; bottom: 24px; width: 56px; height: 56px; border-radius: 50%;
53
+ color: #fff; border: none; cursor: pointer; display: flex; align-items: center;
54
+ justify-content: center; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 9999;
55
+ transition: transform 0.15s ease;
56
+ }
57
+ .kb-fab:hover { transform: scale(1.05); }
58
+ .kb-panel {
59
+ position: fixed; bottom: 96px; width: 384px; max-width: calc(100vw - 48px);
60
+ border-radius: 16px; overflow: hidden; display: flex; flex-direction: column;
61
+ box-shadow: 0 8px 30px rgba(0,0,0,0.12); border: 1px solid #e5e7eb;
62
+ background: #fff; z-index: 9999;
63
+ }
64
+ .kb-header { padding: 16px; color: #fff; display: flex; align-items: center; justify-content: space-between; }
65
+ .kb-header-title { font-weight: 600; font-size: 15px; margin: 0; }
66
+ .kb-header-sub { font-size: 12px; opacity: 0.85; margin: 4px 0 0; }
67
+ .kb-progress { width: 60%; height: 4px; border-radius: 2px; background: rgba(255,255,255,0.3); margin-top: 8px; overflow: hidden; }
68
+ .kb-progress-fill { height: 100%; border-radius: 2px; background: #fff; transition: width 0.3s ease; }
69
+ .kb-messages { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 12px; min-height: 300px; max-height: 384px; background: #fafafa; }
70
+ .kb-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; text-align: center; color: #6b7280; font-size: 14px; padding: 16px; }
71
+ .kb-msg { display: flex; }
72
+ .kb-msg-user { justify-content: flex-end; }
73
+ .kb-msg-assistant { justify-content: flex-start; }
74
+ .kb-bubble { max-width: 80%; padding: 8px 14px; border-radius: 16px; font-size: 14px; line-height: 1.5; word-break: break-word; }
75
+ .kb-bubble-user { color: #fff; }
76
+ .kb-bubble-assistant { background: #fff; color: #1f2937; border: 1px solid #e5e7eb; }
77
+ .kb-bubble p { margin: 0; } .kb-bubble p + p { margin-top: 8px; }
78
+ .kb-thinking { display: flex; gap: 3px; align-items: center; }
79
+ .kb-dot { width: 6px; height: 6px; border-radius: 50%; background: #9ca3af; }
80
+ .kb-dot:nth-child(1) { animation: kb-bounce 1.2s ease-in-out 0ms infinite; }
81
+ .kb-dot:nth-child(2) { animation: kb-bounce 1.2s ease-in-out 150ms infinite; }
82
+ .kb-dot:nth-child(3) { animation: kb-bounce 1.2s ease-in-out 300ms infinite; }
83
+ .kb-thinking-label { font-size: 12px; color: #9ca3af; margin-left: 6px; }
84
+ .kb-spinner { animation: kb-spin 1s linear infinite; }
85
+ .kb-input-bar { display: flex; gap: 8px; padding: 12px 16px; border-top: 1px solid #e5e7eb; background: #fff; }
86
+ .kb-textarea {
87
+ flex: 1; padding: 8px 12px; border: 1px solid #e5e7eb; border-radius: 10px; font-size: 14px;
88
+ resize: none; overflow: hidden; outline: none; font-family: inherit; min-height: 40px; max-height: 120px; line-height: 1.5;
89
+ }
90
+ .kb-textarea:focus { box-shadow: 0 0 0 2px rgba(13,148,136,0.25); }
91
+ .kb-send {
92
+ padding: 8px 14px; color: #fff; border: none; border-radius: 10px; cursor: pointer;
93
+ display: flex; align-items: center; justify-content: center; flex-shrink: 0;
94
+ transition: opacity 0.15s ease;
95
+ }
96
+ .kb-send:disabled { opacity: 0.5; cursor: not-allowed; }
97
+ .kb-icon-btn { background: none; border: none; color: inherit; cursor: pointer; padding: 4px; border-radius: 8px; display: flex; align-items: center; opacity: 0.8; }
98
+ .kb-icon-btn:hover { opacity: 1; }
99
+ .kb-suggestions { display: flex; flex-direction: column; gap: 6px; width: 100%; margin-top: 16px; }
100
+ .kb-suggestion {
101
+ font-size: 13px; padding: 8px 12px; border-radius: 10px; border: 1px solid #e5e7eb;
102
+ background: #fff; color: #374151; cursor: pointer; text-align: left; width: 100%;
103
+ transition: border-color 0.15s ease;
104
+ }
105
+ .kb-suggestion:hover { border-color: var(--kb-primary, #0d9488); }
106
+ .kb-error { padding: 10px 16px; background: #fef2f2; border-bottom: 1px solid #fecaca; font-size: 13px; color: #b91c1c; }
107
+ `;
108
+ var SVG_CHAT = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>`;
109
+ var SVG_CLOSE = `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>`;
110
+ var SVG_SEND = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>`;
111
+ var SVG_TRASH = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>`;
112
+ var SVG_SPINNER = `<svg width="SIZE" height="SIZE" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="kb-spinner"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>`;
113
+ function spinner(size = 18) {
114
+ return SVG_SPINNER.replace(/SIZE/g, String(size));
115
+ }
116
+ var KanhaBotWidget = class {
117
+ constructor(container, props) {
118
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
+ this.engine = null;
120
+ this.panelEl = null;
121
+ this.messagesEl = null;
122
+ this.textareaEl = null;
123
+ this.unmounted = false;
124
+ this.props = {
125
+ botName: "AI Assistant",
126
+ welcomeMessage: "Ask me anything!",
127
+ suggestions: [],
128
+ theme: {},
129
+ ...props
130
+ };
131
+ this.state = {
132
+ messages: [],
133
+ input: "",
134
+ isLoading: false,
135
+ isThinking: false,
136
+ mode: "detecting",
137
+ loadProgress: 0,
138
+ error: null,
139
+ isOpen: false
140
+ };
141
+ this.root = container.attachShadow({ mode: "open" });
142
+ const style = document.createElement("style");
143
+ style.textContent = CSS;
144
+ this.root.appendChild(style);
145
+ this.render();
146
+ this.initEngine();
147
+ }
148
+ get primary() {
149
+ return this.props.theme?.primaryColor ?? "#0d9488";
150
+ }
151
+ get position() {
152
+ return this.props.theme?.position ?? "bottom-right";
153
+ }
154
+ async initEngine() {
155
+ const hasWebGPU = await checkWebGPU();
156
+ if (!hasWebGPU) {
157
+ this.setState({ mode: "error", error: "WebGPU is not supported in this browser. Try Chrome 113+ or Edge 113+." });
158
+ return;
159
+ }
160
+ this.setState({ mode: "loading" });
161
+ try {
162
+ const webllm = await import('@mlc-ai/web-llm');
163
+ const modelId = "kanha-custom-model";
164
+ const modelLib = resolveModelLib(this.props.modelLib, this.props.modelSize);
165
+ const modelUrl = toWebLLMModelUrl(this.props.modelUrl);
166
+ this.engine = await webllm.CreateMLCEngine(modelId, {
167
+ appConfig: {
168
+ model_list: [{
169
+ model: modelUrl,
170
+ model_id: modelId,
171
+ model_lib: modelLib,
172
+ overrides: { context_window_size: this.props.contextWindowSize ?? 4096 }
173
+ }]
174
+ },
175
+ initProgressCallback: (report) => {
176
+ if (!this.unmounted) this.setState({ loadProgress: Math.round(report.progress * 100) });
177
+ }
178
+ });
179
+ if (!this.unmounted) this.setState({ mode: "ready" });
180
+ } catch (err) {
181
+ if (!this.unmounted) {
182
+ this.setState({
183
+ mode: "error",
184
+ error: err instanceof Error ? err.message : "Failed to load AI model."
185
+ });
186
+ }
187
+ }
188
+ }
189
+ setState(partial) {
190
+ Object.assign(this.state, partial);
191
+ this.render();
192
+ }
193
+ async handleSend() {
194
+ const text = this.state.input.trim();
195
+ if (!text || this.state.mode !== "ready" || this.state.isLoading || !this.engine) return;
196
+ const userMsg = { role: "user", content: text };
197
+ const allMessages = [...this.state.messages, userMsg];
198
+ this.setState({ messages: allMessages, input: "", isLoading: true, isThinking: true, error: null });
199
+ try {
200
+ const systemMessages = this.props.systemPrompt ? [{ role: "system", content: this.props.systemPrompt }] : [];
201
+ const completion = await this.engine.chat.completions.create({
202
+ messages: [...systemMessages, ...allMessages],
203
+ temperature: this.props.temperature ?? 0.7,
204
+ max_tokens: this.props.maxTokens ?? 1024,
205
+ stream: true
206
+ });
207
+ let fullText = "";
208
+ for await (const chunk of completion) {
209
+ const delta = chunk.choices[0]?.delta?.content || "";
210
+ fullText += delta;
211
+ const cleaned = stripThinkTokens(fullText);
212
+ if (!cleaned) {
213
+ this.setState({ isThinking: true });
214
+ } else {
215
+ const msgs = [...allMessages];
216
+ if (msgs[msgs.length - 1]?.role === "assistant") {
217
+ msgs[msgs.length - 1] = { role: "assistant", content: cleaned };
218
+ } else {
219
+ msgs.push({ role: "assistant", content: cleaned });
220
+ }
221
+ this.setState({ messages: msgs, isThinking: false });
222
+ }
223
+ }
224
+ } catch {
225
+ this.setState({
226
+ error: "Failed to generate response. Please try again.",
227
+ messages: [...allMessages, { role: "assistant", content: "Sorry, I encountered an error. Please try again." }]
228
+ });
229
+ } finally {
230
+ this.setState({ isLoading: false, isThinking: false });
231
+ }
232
+ }
233
+ render() {
234
+ const { messages, isLoading, isThinking, mode, loadProgress, error, isOpen } = this.state;
235
+ const isReady = mode === "ready";
236
+ const style = this.root.querySelector("style");
237
+ this.root.innerHTML = "";
238
+ if (style) this.root.appendChild(style);
239
+ const wrapper = document.createElement("div");
240
+ wrapper.style.setProperty("--kb-primary", this.primary);
241
+ this.root.appendChild(wrapper);
242
+ const fab = document.createElement("button");
243
+ fab.className = "kb-fab";
244
+ fab.style.background = this.primary;
245
+ fab.style[this.position === "bottom-right" ? "right" : "left"] = "24px";
246
+ fab.innerHTML = isOpen ? SVG_CLOSE : SVG_CHAT;
247
+ fab.setAttribute("aria-label", "Toggle chat");
248
+ fab.onclick = () => this.setState({ isOpen: !isOpen });
249
+ wrapper.appendChild(fab);
250
+ if (!isOpen) return;
251
+ const panel = document.createElement("div");
252
+ panel.className = "kb-panel";
253
+ panel.style[this.position === "bottom-right" ? "right" : "left"] = "24px";
254
+ wrapper.appendChild(panel);
255
+ this.panelEl = panel;
256
+ const header = document.createElement("div");
257
+ header.className = "kb-header";
258
+ header.style.background = this.primary;
259
+ header.innerHTML = `
260
+ <div>
261
+ <p class="kb-header-title">${esc(this.props.botName)}</p>
262
+ <p class="kb-header-sub">${isReady ? esc(this.props.welcomeMessage) : mode === "loading" ? `Loading AI model (${loadProgress}%)` : mode === "error" ? "Failed to load" : "Detecting capabilities..."}</p>
263
+ ${mode === "loading" ? `<div class="kb-progress"><div class="kb-progress-fill" style="width:${loadProgress}%"></div></div>` : ""}
264
+ </div>
265
+ <div style="display:flex;gap:4px">
266
+ ${messages.length > 0 ? `<button class="kb-icon-btn" data-action="clear" aria-label="Clear">${SVG_TRASH}</button>` : ""}
267
+ <button class="kb-icon-btn" data-action="close" aria-label="Close">${SVG_CLOSE}</button>
268
+ </div>`;
269
+ header.querySelector("[data-action=clear]")?.addEventListener("click", () => this.setState({ messages: [], error: null }));
270
+ header.querySelector("[data-action=close]")?.addEventListener("click", () => this.setState({ isOpen: false }));
271
+ panel.appendChild(header);
272
+ if (error) {
273
+ const errEl = document.createElement("div");
274
+ errEl.className = "kb-error";
275
+ errEl.textContent = error;
276
+ panel.appendChild(errEl);
277
+ }
278
+ const msgsContainer = document.createElement("div");
279
+ msgsContainer.className = "kb-messages";
280
+ panel.appendChild(msgsContainer);
281
+ this.messagesEl = msgsContainer;
282
+ if (messages.length === 0) {
283
+ const empty = document.createElement("div");
284
+ empty.className = "kb-empty";
285
+ if (isReady) {
286
+ empty.innerHTML = `${SVG_CHAT}<p style="margin-top:12px;font-weight:500;color:#374151">${esc(this.props.welcomeMessage)}</p>`;
287
+ if (this.props.suggestions && this.props.suggestions.length > 0) {
288
+ const sugDiv = document.createElement("div");
289
+ sugDiv.className = "kb-suggestions";
290
+ for (const text of this.props.suggestions) {
291
+ const btn = document.createElement("button");
292
+ btn.className = "kb-suggestion";
293
+ btn.textContent = text;
294
+ btn.onclick = () => {
295
+ this.setState({ input: text });
296
+ setTimeout(() => this.handleSend(), 0);
297
+ };
298
+ sugDiv.appendChild(btn);
299
+ }
300
+ empty.appendChild(sugDiv);
301
+ }
302
+ } else if (mode === "loading") {
303
+ empty.innerHTML = `${spinner(32)}<p style="margin-top:8px">Loading AI model (${loadProgress}%)</p><p style="font-size:12px;margin-top:4px">First load takes about a minute</p>`;
304
+ } else if (mode === "error") {
305
+ empty.innerHTML = `<p>${esc(error ?? "An error occurred")}</p>`;
306
+ } else {
307
+ empty.innerHTML = `${spinner(32)}<p style="margin-top:8px">Detecting browser capabilities...</p>`;
308
+ }
309
+ msgsContainer.appendChild(empty);
310
+ } else {
311
+ for (const msg of messages) {
312
+ const row = document.createElement("div");
313
+ row.className = `kb-msg kb-msg-${msg.role}`;
314
+ const bubble = document.createElement("div");
315
+ bubble.className = `kb-bubble kb-bubble-${msg.role}`;
316
+ if (msg.role === "user") {
317
+ bubble.style.background = this.primary;
318
+ bubble.innerHTML = `<span style="white-space:pre-wrap">${esc(msg.content)}</span>`;
319
+ } else {
320
+ bubble.innerHTML = msg.content.split("\n\n").map((p) => `<p>${esc(p).replace(/\n/g, "<br>")}</p>`).join("");
321
+ }
322
+ row.appendChild(bubble);
323
+ msgsContainer.appendChild(row);
324
+ }
325
+ if (isLoading && (isThinking || messages[messages.length - 1]?.role !== "assistant")) {
326
+ const row = document.createElement("div");
327
+ row.className = "kb-msg kb-msg-assistant";
328
+ const bubble = document.createElement("div");
329
+ bubble.className = "kb-bubble kb-bubble-assistant";
330
+ bubble.innerHTML = isThinking ? `<span class="kb-thinking"><span class="kb-dot"></span><span class="kb-dot"></span><span class="kb-dot"></span><span class="kb-thinking-label">Thinking</span></span>` : spinner(16);
331
+ row.appendChild(bubble);
332
+ msgsContainer.appendChild(row);
333
+ }
334
+ msgsContainer.scrollTop = msgsContainer.scrollHeight;
335
+ }
336
+ const inputBar = document.createElement("div");
337
+ inputBar.className = "kb-input-bar";
338
+ panel.appendChild(inputBar);
339
+ const textarea = document.createElement("textarea");
340
+ textarea.className = "kb-textarea";
341
+ textarea.rows = 1;
342
+ textarea.placeholder = isReady ? "Type your message..." : "Waiting for model...";
343
+ textarea.disabled = !isReady || isLoading;
344
+ textarea.value = this.state.input;
345
+ textarea.oninput = () => {
346
+ this.state.input = textarea.value;
347
+ textarea.style.height = "auto";
348
+ textarea.style.height = Math.min(textarea.scrollHeight, 120) + "px";
349
+ };
350
+ textarea.onkeydown = (e) => {
351
+ if (e.key === "Enter" && !e.shiftKey) {
352
+ e.preventDefault();
353
+ this.handleSend();
354
+ }
355
+ };
356
+ inputBar.appendChild(textarea);
357
+ this.textareaEl = textarea;
358
+ const sendBtn = document.createElement("button");
359
+ sendBtn.className = "kb-send";
360
+ sendBtn.style.background = this.primary;
361
+ sendBtn.disabled = !isReady || isLoading || !this.state.input.trim();
362
+ sendBtn.innerHTML = isLoading ? spinner(18) : SVG_SEND;
363
+ sendBtn.setAttribute("aria-label", "Send");
364
+ sendBtn.onclick = () => this.handleSend();
365
+ inputBar.appendChild(sendBtn);
366
+ if (isReady && !isLoading) {
367
+ requestAnimationFrame(() => textarea.focus());
368
+ }
369
+ }
370
+ destroy() {
371
+ this.unmounted = true;
372
+ this.root.innerHTML = "";
373
+ }
374
+ };
375
+ function mount(target, props) {
376
+ const el = typeof target === "string" ? document.querySelector(target) : target;
377
+ if (!el) throw new Error(`Kanha: element "${target}" not found`);
378
+ const widget = new KanhaBotWidget(el, props);
379
+ return { destroy: () => widget.destroy() };
380
+ }
381
+ var KanhaBotElement = class extends HTMLElement {
382
+ constructor() {
383
+ super(...arguments);
384
+ this.widget = null;
385
+ }
386
+ connectedCallback() {
387
+ const props = {
388
+ modelUrl: this.getAttribute("model-url") ?? "",
389
+ modelLib: this.getAttribute("model-lib") ?? void 0,
390
+ modelSize: this.getAttribute("model-size") ?? void 0,
391
+ systemPrompt: this.getAttribute("system-prompt") ?? void 0,
392
+ temperature: this.hasAttribute("temperature") ? Number(this.getAttribute("temperature")) : void 0,
393
+ maxTokens: this.hasAttribute("max-tokens") ? Number(this.getAttribute("max-tokens")) : void 0,
394
+ botName: this.getAttribute("bot-name") ?? void 0,
395
+ welcomeMessage: this.getAttribute("welcome-message") ?? void 0,
396
+ suggestions: this.hasAttribute("suggestions") ? JSON.parse(this.getAttribute("suggestions")) : void 0,
397
+ theme: {
398
+ primaryColor: this.getAttribute("primary-color") ?? void 0,
399
+ position: this.getAttribute("position") ?? void 0
400
+ }
401
+ };
402
+ this.widget = new KanhaBotWidget(this, props);
403
+ }
404
+ disconnectedCallback() {
405
+ this.widget?.destroy();
406
+ }
407
+ };
408
+ if (typeof customElements !== "undefined" && !customElements.get("kanha-bot")) {
409
+ customElements.define("kanha-bot", KanhaBotElement);
410
+ }
411
+
412
+ export { mount };
413
+ //# sourceMappingURL=widget.js.map
414
+ //# sourceMappingURL=widget.js.map