@vamlabs/vam-chatbot 0.1.70 → 0.1.71
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.
- package/README.md +18 -0
- package/dist/web-component.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,8 +13,26 @@
|
|
|
13
13
|
<vam-chatbot client-id="<your-client-id>"></vam-chatbot>
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
3. **Provide an Auth Token (Optional):**
|
|
17
|
+
- For protected deployments (for example, your portal domain), pass a bearer token for `POST /chat/session`.
|
|
18
|
+
- For public embeds where your backend allows unauthenticated session minting, this can be omitted.
|
|
19
|
+
- Static token via attribute:
|
|
20
|
+
```html
|
|
21
|
+
<vam-chatbot client-id="<your-client-id>" auth-token="<id-token>"></vam-chatbot>
|
|
22
|
+
```
|
|
23
|
+
- Recommended (fresh token per request) via JS property:
|
|
24
|
+
```html
|
|
25
|
+
<script>
|
|
26
|
+
const bot = document.querySelector("vam-chatbot");
|
|
27
|
+
bot.authTokenProvider = async () => {
|
|
28
|
+
return window.getCognitoIdToken();
|
|
29
|
+
};
|
|
30
|
+
</script>
|
|
31
|
+
```
|
|
32
|
+
|
|
16
33
|
These steps will help you integrate the VAM chatbot into your webpage seamlessly. Ensure you replace the `client-id` with the one provided to you for proper configuration.
|
|
17
34
|
|
|
18
35
|
## Notes
|
|
19
36
|
|
|
20
37
|
- The widget uses a 2-step chat flow (`POST /chat/session` then streamed `POST /chat/stream`) and requires your site origin to be allowlisted for your tenant.
|
|
38
|
+
- If configured, `authTokenProvider` is called before each message stream starts so expiring tokens can be refreshed on-demand.
|
package/dist/web-component.js
CHANGED
|
@@ -26,7 +26,7 @@ return /******/ (() => { // webpackBootstrap
|
|
|
26
26
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
27
27
|
|
|
28
28
|
"use strict";
|
|
29
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var framer_motion__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! framer-motion */ \"./node_modules/framer-motion/dist/es/components/LazyMotion/index.mjs\");\n/* harmony import */ var framer_motion__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! framer-motion */ \"./node_modules/framer-motion/dist/es/render/dom/features-animation.mjs\");\n/* harmony import */ var framer_motion__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! framer-motion */ \"./node_modules/framer-motion/dist/es/render/components/m/proxy.mjs\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! axios */ \"./node_modules/axios/lib/axios.js\");\n/* harmony import */ var _components_ChatbotHeader__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./components/ChatbotHeader */ \"./components/ChatbotHeader.jsx\");\n/* harmony import */ var _components_ChatbotBody__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./components/ChatbotBody */ \"./components/ChatbotBody.jsx\");\n/* harmony import */ var _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Chatbot.module.css */ \"./Chatbot.module.css\");\n/* harmony import */ var _utils_variants__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./utils/variants */ \"./utils/variants.js\");\n/* harmony import */ var _utils_useClickHandler__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./utils/useClickHandler */ \"./utils/useClickHandler.js\");\n/* harmony import */ var _utils_defaults__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./utils/defaults */ \"./utils/defaults.js\");\n/* harmony import */ var _utils_config__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./utils/config */ \"./utils/config.js\");\n/* harmony import */ var _utils_sseClient__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./utils/sseClient */ \"./utils/sseClient.js\");\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! react/jsx-runtime */ \"./node_modules/react/jsx-runtime.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n/* \n- valid chatbot states:\n 0: \"at rest\",\n 1: \"waiting for response from api\"\n 2: \"receiving response from api\"\n*/\n\nconst fixSpecialLLMChars = text => {\n // forward slash is replaced by <|slash|> in the response from the api\n return text.replace(/\\u003c\\|slash\\|\\u003e/g, \"/\");\n};\nconst normalizeResponseText = text => {\n if (typeof text !== \"string\") return \"\";\n return fixSpecialLLMChars(text);\n};\nconst randomId = () => {\n try {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n } catch (e) {}\n return `${Date.now()}-${Math.random().toString(16).slice(2)}`;\n};\nfunction Chatbot(_ref) {\n let {\n clientId,\n onTrackEvent\n } = _ref;\n const [messageList, setMessageList] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);\n const [inputText, setInputText] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(\"\");\n const [chatbotState, setChatbotState] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(0);\n const [chatbotMinimized, setChatbotMinimized] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(true);\n const [chatbotPopupMinimized, setChatbotPopupMinimized] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);\n const [promptsData, setPromptsData] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({\n show: true,\n prompts: []\n });\n const [promptsMinimized, setPromptsMinimized] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(true);\n const [chatbotConfig, setChatbotConfig] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({\n fetchedData: false,\n data: {}\n });\n const [chatbotIcon, setChatbotIcon] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);\n const defaultMessageList = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)([]);\n const conversationIdRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(randomId());\n const streamAbortRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);\n const inputRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);\n const scrollAnchorRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);\n const chatbotRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);\n\n // Use the custom hook to track clicks\n (0,_utils_useClickHandler__WEBPACK_IMPORTED_MODULE_5__[\"default\"])(onTrackEvent, chatbotRef);\n\n // use effect to upate the css variables once available through the chatbot config API\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n try {\n if (chatbotConfig?.data?.styles?.css_variables) {\n // escape special characters with backslash\n // since query selctor does not allow special characters\n let chatbotParent = document?.querySelector(\"vam-chatbot\")?.shadowRoot.querySelector(`.${_Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotParent.replace(/([^\\w-])/g, \"\\\\$1\")}`) || document?.querySelector(`.${_Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotParent.replace(/([^\\w-])/g, \"\\\\$1\")}`);\n for (let variable in chatbotConfig.data.styles.css_variables) {\n chatbotParent.style.setProperty(`--${variable}`, chatbotConfig.data.styles.css_variables[variable]);\n }\n }\n } catch (error) {\n console.log(error);\n }\n }, [chatbotConfig?.data?.styles?.css_variables]);\n\n // useeffect to store the chatbot icon when its url is fetched from the chatbot config API\n // this is to prevent the api call being made on render of every message\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n try {\n if (chatbotConfig?.data?.icon_url) {\n const fetchChatbotIcon = async () => {\n let url = chatbotConfig?.data?.icon_url;\n let apiResponse = await (0,axios__WEBPACK_IMPORTED_MODULE_10__[\"default\"])({\n url,\n method: \"GET\",\n responseType: \"blob\"\n });\n let imageBlob = apiResponse.data;\n if (imageBlob) {\n let imageObjectURL = URL.createObjectURL(imageBlob);\n setChatbotIcon(imageObjectURL);\n }\n };\n fetchChatbotIcon();\n }\n } catch (error) {\n console.log(error);\n }\n }, [chatbotConfig?.data?.icon_url]);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n const fetchConfigData = async () => {\n // Check if configUrl is null and handle appropriately\n if (!_utils_config__WEBPACK_IMPORTED_MODULE_7__.configUrl) {\n console.error(\"Chatbot config URL is not set. Please provide CHATBOT_DEV_URL or CHATBOT_PROD_URL environment variables.\");\n return;\n }\n const url = `${_utils_config__WEBPACK_IMPORTED_MODULE_7__.configUrl}/api/getBotConfig`;\n const method = \"POST\";\n const requestBody = {\n clientId\n };\n try {\n let apiResponse = await (0,axios__WEBPACK_IMPORTED_MODULE_10__[\"default\"])({\n url,\n method,\n data: requestBody\n });\n if (apiResponse?.data) {\n let data = apiResponse.data;\n setChatbotConfig({\n fetchedData: true,\n data\n });\n setPromptsData(data?.default_prompts || {\n show: false,\n prompts: []\n });\n setMessageList(data?.default_message_list || []);\n defaultMessageList.current = data?.default_message_list || [];\n } else {\n // handle no data here\n console.log(\"no data found for the provided client id: \", clientId);\n }\n } catch (e) {\n console.error(e);\n // handle api failure here\n }\n };\n fetchConfigData();\n }, [clientId]);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n return () => {\n streamAbortRef.current?.abort?.();\n };\n }, []);\n\n // scroll to the latest message whenever the message list updates\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n scrollAnchorRef.current?.scrollIntoView({\n behavior: \"smooth\",\n block: \"end\",\n inline: \"nearest\"\n });\n }, [messageList]);\n const handleStreamEnvelope = env => {\n try {\n let {\n status,\n data\n } = env || {};\n let {\n response,\n sources,\n image_links,\n promoted_topics\n } = data || {};\n const normalizedResponse = normalizeResponseText(response);\n const normalizedSources = sources?.map(fixSpecialLLMChars);\n const normalizedImageLinks = image_links?.map(fixSpecialLLMChars);\n const normalizedPromotedTopics = promoted_topics?.filter(item => item?.title);\n const promotedImageLinks = normalizedPromotedTopics?.map(pt => pt?.image_link)?.filter(Boolean)?.map(fixSpecialLLMChars);\n if (status === \"streaming\") {\n // set the chatbot state to \"receiving response\" and initialize the response\n setChatbotState(2);\n if (normalizedResponse) {\n setMessageList(prevList => {\n let responseList = [...prevList];\n try {\n let latestMessage = prevList.slice(-1)[0];\n if (latestMessage?.status === \"streaming\") {\n latestMessage.data.text = normalizedResponse;\n } else {\n let responseMessage = {\n source: \"bot\",\n data: {\n text: normalizedResponse\n },\n origin: \"server\",\n status: \"streaming\"\n };\n responseList = [...responseList, responseMessage];\n }\n } catch (error) {}\n return responseList;\n });\n }\n } else if (status === \"done\") {\n setChatbotState(0);\n\n // update the status as done for the last message\n setMessageList(prevList => {\n let responseList = [...prevList];\n try {\n let latestMessage = responseList.slice(-1)[0];\n const finalResponseText = normalizedResponse || _utils_defaults__WEBPACK_IMPORTED_MODULE_6__.errorResponse;\n const whatsappConfig = chatbotConfig?.data?.external_redirect_metadata?.whatsapp;\n if (latestMessage?.source !== \"user\") {\n latestMessage.status = \"done\";\n latestMessage.data.text = finalResponseText;\n latestMessage.data.sources = normalizedSources;\n latestMessage.data.image_links = promotedImageLinks?.length > 0 ? promotedImageLinks : normalizedImageLinks;\n latestMessage.data.promoted_topics = normalizedPromotedTopics;\n\n // Logic to show support button after every 2nd answer\n const botMessageCount = responseList.filter(msg => msg.source === \"bot\" && msg.origin === \"server\").length;\n if (whatsappConfig) {\n const triggerFrequency = whatsappConfig?.trigger_message_frequency;\n const redirectUrl = whatsappConfig?.redirect_url;\n if (triggerFrequency && redirectUrl && botMessageCount % triggerFrequency === 0) {\n latestMessage.data.showSupportButton = true;\n latestMessage.data.supportUrl = redirectUrl;\n }\n }\n } else {\n let responseMessage = {\n source: \"bot\",\n data: {\n text: finalResponseText,\n sources: normalizedSources,\n image_links: promotedImageLinks?.length > 0 ? promotedImageLinks : normalizedImageLinks,\n promoted_topics: normalizedPromotedTopics\n },\n origin: \"server\",\n status: \"done\"\n };\n if (whatsappConfig) {\n const triggerFrequency = whatsappConfig?.trigger_message_frequency;\n const redirectUrl = whatsappConfig?.redirect_url;\n const nextBotMessageCount = responseList.filter(msg => msg.source === \"bot\" && msg.origin === \"server\").length + 1;\n if (triggerFrequency && redirectUrl && nextBotMessageCount % triggerFrequency === 0) {\n responseMessage.data.showSupportButton = true;\n responseMessage.data.supportUrl = redirectUrl;\n }\n }\n responseList = [...responseList, responseMessage];\n }\n } catch (error) {}\n return responseList;\n });\n }\n } catch (error) {}\n };\n\n // to keep the input field in focus and scroll to the latest message\n // when the enter button is clicked.\n // const focusInput = () => {\n // inputRef.current.focus();\n // };\n\n // to handle the minimize/maximize animation of the chatbot.\n const handleChatbotAnimation = () => {\n setChatbotMinimized(!chatbotMinimized);\n };\n\n // to reset the chatbot content.\n const resetChatbot = () => {\n try {\n streamAbortRef.current?.abort?.();\n streamAbortRef.current = null;\n conversationIdRef.current = randomId();\n setMessageList(defaultMessageList.current);\n setPromptsData(prevData => {\n return {\n ...prevData,\n show: true\n };\n });\n setChatbotState(0);\n setInputText(\"\");\n } catch (error) {}\n };\n const handleInput = event => {\n try {\n setInputText(event.target.value);\n } catch (error) {}\n };\n const getChatHistory = messages => {\n let response = [];\n try {\n let historyItem = {\n user: \"\",\n assistant: \"\"\n };\n for (let message of messages || []) {\n if (message.source === \"user\") {\n historyItem.user = message?.data?.text;\n } else if (message.source === \"bot\" && message.origin === \"server\") {\n if (message?.status === \"done\") {\n historyItem.assistant = message?.data?.text;\n response.push(historyItem);\n historyItem = {\n user: \"\",\n assistant: \"\"\n };\n }\n }\n }\n } catch (error) {\n console.log(error);\n } finally {\n return response;\n }\n };\n const getPromotionsShown = messages => {\n const out = [];\n try {\n let pendingUserSeen = false;\n for (let message of messages || []) {\n if (message.source === \"user\") {\n pendingUserSeen = true;\n continue;\n }\n if (!pendingUserSeen) continue;\n if (message.source === \"bot\" && message.origin === \"server\" && message.status === \"done\") {\n const titles = (message?.data?.promoted_topics || []).map(t => t?.title).filter(t => typeof t === \"string\" && t.trim().length > 0);\n out.push(titles);\n pendingUserSeen = false;\n }\n }\n } catch (error) {}\n return out;\n };\n const startNewStream = async (prompt, prevMessages) => {\n const chatbotBaseUrl = chatbotConfig?.data?.chatbot_url || chatbotConfig?.data?.chatbotUrl;\n if (!chatbotBaseUrl) {\n throw new Error(\"chatbot_url missing from config\");\n }\n streamAbortRef.current?.abort?.();\n const abortController = new AbortController();\n streamAbortRef.current = abortController;\n let chatHistory = getChatHistory(prevMessages);\n let promotionsShown = getPromotionsShown(prevMessages);\n if (chatHistory.length > 40) {\n const start = chatHistory.length - 40;\n chatHistory = chatHistory.slice(start);\n promotionsShown = promotionsShown.slice(start);\n }\n const messageId = randomId();\n const session = await (0,_utils_sseClient__WEBPACK_IMPORTED_MODULE_8__.mintChatbotSessionToken)({\n chatbotBaseUrl,\n clientHint: clientId,\n signal: abortController.signal\n });\n if (!session?.token) {\n throw new Error(\"missing session token\");\n }\n await (0,_utils_sseClient__WEBPACK_IMPORTED_MODULE_8__.streamChatbotSse)({\n chatbotBaseUrl,\n token: session.token,\n body: {\n chatHistory,\n conversationId: conversationIdRef.current,\n message: prompt,\n messageId,\n promotionsShown\n },\n signal: abortController.signal,\n onEnvelope: handleStreamEnvelope\n });\n };\n const handleSubmit = async function () {\n let prompt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : \"\";\n let typewriterEffect = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n if (!prompt) {\n prompt = inputText;\n } else {\n typewriterEffect = true;\n }\n try {\n prompt = prompt.trim();\n if (prompt) {\n const prevMessages = messageList;\n setChatbotState(1);\n\n // put the user's prompt in the chat\n let userMessage = {\n source: \"user\",\n data: {\n text: prompt\n },\n status: \"done\",\n typewriterEffect\n };\n setMessageList(prevList => [...prevList, userMessage]);\n\n // hide the default prompts\n setPromptsData({\n ...promptsData,\n show: false\n });\n\n // clear the input field\n setInputText(\"\");\n await startNewStream(prompt, prevMessages);\n }\n } catch (error) {\n if (error?.name === \"AbortError\") {\n return;\n }\n console.error(\"Error sending chat message:\", error);\n setChatbotState(0);\n setMessageList(prevList => [...prevList, {\n source: \"error\",\n data: {\n text: _utils_defaults__WEBPACK_IMPORTED_MODULE_6__.errorResponse\n },\n status: \"done\"\n }]);\n }\n };\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.Fragment, {\n children: chatbotConfig?.fetchedData && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"div\", {\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotParent,\n ref: chatbotRef,\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxs)(framer_motion__WEBPACK_IMPORTED_MODULE_11__.LazyMotion, {\n features: framer_motion__WEBPACK_IMPORTED_MODULE_12__.domAnimation,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxs)(framer_motion__WEBPACK_IMPORTED_MODULE_13__.m.div, {\n initial: false,\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotContainer,\n animate: chatbotMinimized ? \"hide\" : \"show\",\n variants: _utils_variants__WEBPACK_IMPORTED_MODULE_4__.maximizedChatbotVariants,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(_components_ChatbotHeader__WEBPACK_IMPORTED_MODULE_1__[\"default\"], {\n headerText: chatbotConfig?.data?.header_text,\n setPromptsMinimized: setPromptsMinimized,\n handleChatbotAnimation: handleChatbotAnimation,\n resetChatbot: resetChatbot\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(_components_ChatbotBody__WEBPACK_IMPORTED_MODULE_2__[\"default\"], {\n messageList: messageList,\n promptsData: promptsData,\n handleSubmit: handleSubmit,\n chatbotState: chatbotState,\n scrollAnchorRef: scrollAnchorRef,\n promptsMinimized: promptsMinimized,\n setPromptsMinimized: setPromptsMinimized,\n inputRef: inputRef,\n inputText: inputText,\n handleInput: handleInput,\n placeholderInputText: chatbotConfig?.data?.placeholder_input_text,\n chatbotIcon: chatbotIcon\n })]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxs)(framer_motion__WEBPACK_IMPORTED_MODULE_13__.m.div, {\n variants: _utils_variants__WEBPACK_IMPORTED_MODULE_4__.minimizedChatbotVariants,\n animate: chatbotMinimized ? \"show\" : \"hide\",\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotCircleContainer,\n children: [!chatbotPopupMinimized && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxs)(framer_motion__WEBPACK_IMPORTED_MODULE_13__.m.div, {\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].popupContainer,\n variants: _utils_variants__WEBPACK_IMPORTED_MODULE_4__.minimizedChatbotContentVariants,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"button\", {\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].closePopup,\n onClick: () => setChatbotPopupMinimized(true),\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"i\", {\n className: \"bi bi-x-circle-fill\"\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"div\", {\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].popup,\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"div\", {\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].popupContent,\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"span\", {\n children: chatbotConfig?.data?.popup_body_text\n })\n })\n })]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(framer_motion__WEBPACK_IMPORTED_MODULE_13__.m.div, {\n variants: _utils_variants__WEBPACK_IMPORTED_MODULE_4__.minimizedChatbotContentVariants,\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotCircle,\n onClick: handleChatbotAnimation,\n children: chatbotIcon && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"div\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"img\", {\n src: chatbotIcon,\n loading: \"lazy\",\n alt: \"chatbot icon\",\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotIcon\n })\n })\n })]\n })]\n })\n })\n });\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Chatbot);\n\n//# sourceURL=webpack://VamChatbot/./Chatbot.jsx?");
|
|
29
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var framer_motion__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! framer-motion */ \"./node_modules/framer-motion/dist/es/components/LazyMotion/index.mjs\");\n/* harmony import */ var framer_motion__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! framer-motion */ \"./node_modules/framer-motion/dist/es/render/dom/features-animation.mjs\");\n/* harmony import */ var framer_motion__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! framer-motion */ \"./node_modules/framer-motion/dist/es/render/components/m/proxy.mjs\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! axios */ \"./node_modules/axios/lib/axios.js\");\n/* harmony import */ var _components_ChatbotHeader__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./components/ChatbotHeader */ \"./components/ChatbotHeader.jsx\");\n/* harmony import */ var _components_ChatbotBody__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./components/ChatbotBody */ \"./components/ChatbotBody.jsx\");\n/* harmony import */ var _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Chatbot.module.css */ \"./Chatbot.module.css\");\n/* harmony import */ var _utils_variants__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./utils/variants */ \"./utils/variants.js\");\n/* harmony import */ var _utils_useClickHandler__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./utils/useClickHandler */ \"./utils/useClickHandler.js\");\n/* harmony import */ var _utils_defaults__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./utils/defaults */ \"./utils/defaults.js\");\n/* harmony import */ var _utils_config__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./utils/config */ \"./utils/config.js\");\n/* harmony import */ var _utils_sseClient__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./utils/sseClient */ \"./utils/sseClient.js\");\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! react/jsx-runtime */ \"./node_modules/react/jsx-runtime.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n/* \n- valid chatbot states:\n 0: \"at rest\",\n 1: \"waiting for response from api\"\n 2: \"receiving response from api\"\n*/\n\nconst fixSpecialLLMChars = text => {\n // forward slash is replaced by <|slash|> in the response from the api\n return text.replace(/\\u003c\\|slash\\|\\u003e/g, \"/\");\n};\nconst normalizeResponseText = text => {\n if (typeof text !== \"string\") return \"\";\n return fixSpecialLLMChars(text);\n};\nconst normalizeAuthToken = value => {\n if (typeof value !== \"string\") return \"\";\n return value.trim();\n};\nconst resolveAuthToken = async _ref => {\n let {\n authToken,\n authTokenProvider\n } = _ref;\n if (typeof authTokenProvider === \"function\") {\n const providedToken = await authTokenProvider();\n const normalizedToken = normalizeAuthToken(providedToken);\n if (normalizedToken) return normalizedToken;\n }\n return normalizeAuthToken(authToken);\n};\nconst randomId = () => {\n try {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n } catch (e) {}\n return `${Date.now()}-${Math.random().toString(16).slice(2)}`;\n};\nfunction Chatbot(_ref2) {\n let {\n clientId,\n onTrackEvent,\n authToken,\n authTokenProvider\n } = _ref2;\n const [messageList, setMessageList] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);\n const [inputText, setInputText] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(\"\");\n const [chatbotState, setChatbotState] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(0);\n const [chatbotMinimized, setChatbotMinimized] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(true);\n const [chatbotPopupMinimized, setChatbotPopupMinimized] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);\n const [promptsData, setPromptsData] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({\n show: true,\n prompts: []\n });\n const [promptsMinimized, setPromptsMinimized] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(true);\n const [chatbotConfig, setChatbotConfig] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({\n fetchedData: false,\n data: {}\n });\n const [chatbotIcon, setChatbotIcon] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);\n const defaultMessageList = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)([]);\n const conversationIdRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(randomId());\n const streamAbortRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);\n const inputRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);\n const scrollAnchorRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);\n const chatbotRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);\n\n // Use the custom hook to track clicks\n (0,_utils_useClickHandler__WEBPACK_IMPORTED_MODULE_5__[\"default\"])(onTrackEvent, chatbotRef);\n\n // use effect to upate the css variables once available through the chatbot config API\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n try {\n if (chatbotConfig?.data?.styles?.css_variables) {\n // escape special characters with backslash\n // since query selctor does not allow special characters\n let chatbotParent = document?.querySelector(\"vam-chatbot\")?.shadowRoot.querySelector(`.${_Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotParent.replace(/([^\\w-])/g, \"\\\\$1\")}`) || document?.querySelector(`.${_Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotParent.replace(/([^\\w-])/g, \"\\\\$1\")}`);\n for (let variable in chatbotConfig.data.styles.css_variables) {\n chatbotParent.style.setProperty(`--${variable}`, chatbotConfig.data.styles.css_variables[variable]);\n }\n }\n } catch (error) {\n console.log(error);\n }\n }, [chatbotConfig?.data?.styles?.css_variables]);\n\n // useeffect to store the chatbot icon when its url is fetched from the chatbot config API\n // this is to prevent the api call being made on render of every message\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n try {\n if (chatbotConfig?.data?.icon_url) {\n const fetchChatbotIcon = async () => {\n let url = chatbotConfig?.data?.icon_url;\n let apiResponse = await (0,axios__WEBPACK_IMPORTED_MODULE_10__[\"default\"])({\n url,\n method: \"GET\",\n responseType: \"blob\"\n });\n let imageBlob = apiResponse.data;\n if (imageBlob) {\n let imageObjectURL = URL.createObjectURL(imageBlob);\n setChatbotIcon(imageObjectURL);\n }\n };\n fetchChatbotIcon();\n }\n } catch (error) {\n console.log(error);\n }\n }, [chatbotConfig?.data?.icon_url]);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n const fetchConfigData = async () => {\n // Check if configUrl is null and handle appropriately\n if (!_utils_config__WEBPACK_IMPORTED_MODULE_7__.configUrl) {\n console.error(\"Chatbot config URL is not set. Please provide CHATBOT_DEV_URL or CHATBOT_PROD_URL environment variables.\");\n return;\n }\n const url = `${_utils_config__WEBPACK_IMPORTED_MODULE_7__.configUrl}/api/getBotConfig`;\n const method = \"POST\";\n const requestBody = {\n clientId\n };\n try {\n let apiResponse = await (0,axios__WEBPACK_IMPORTED_MODULE_10__[\"default\"])({\n url,\n method,\n data: requestBody\n });\n if (apiResponse?.data) {\n let data = apiResponse.data;\n setChatbotConfig({\n fetchedData: true,\n data\n });\n setPromptsData(data?.default_prompts || {\n show: false,\n prompts: []\n });\n setMessageList(data?.default_message_list || []);\n defaultMessageList.current = data?.default_message_list || [];\n } else {\n // handle no data here\n console.log(\"no data found for the provided client id: \", clientId);\n }\n } catch (e) {\n console.error(e);\n // handle api failure here\n }\n };\n fetchConfigData();\n }, [clientId]);\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n return () => {\n streamAbortRef.current?.abort?.();\n };\n }, []);\n\n // scroll to the latest message whenever the message list updates\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n scrollAnchorRef.current?.scrollIntoView({\n behavior: \"smooth\",\n block: \"end\",\n inline: \"nearest\"\n });\n }, [messageList]);\n const handleStreamEnvelope = env => {\n try {\n let {\n status,\n data\n } = env || {};\n let {\n response,\n sources,\n image_links,\n promoted_topics\n } = data || {};\n const normalizedResponse = normalizeResponseText(response);\n const normalizedSources = sources?.map(fixSpecialLLMChars);\n const normalizedImageLinks = image_links?.map(fixSpecialLLMChars);\n const normalizedPromotedTopics = promoted_topics?.filter(item => item?.title);\n const promotedImageLinks = normalizedPromotedTopics?.map(pt => pt?.image_link)?.filter(Boolean)?.map(fixSpecialLLMChars);\n if (status === \"streaming\") {\n // set the chatbot state to \"receiving response\" and initialize the response\n setChatbotState(2);\n if (normalizedResponse) {\n setMessageList(prevList => {\n let responseList = [...prevList];\n try {\n let latestMessage = prevList.slice(-1)[0];\n if (latestMessage?.status === \"streaming\") {\n latestMessage.data.text = normalizedResponse;\n } else {\n let responseMessage = {\n source: \"bot\",\n data: {\n text: normalizedResponse\n },\n origin: \"server\",\n status: \"streaming\"\n };\n responseList = [...responseList, responseMessage];\n }\n } catch (error) {}\n return responseList;\n });\n }\n } else if (status === \"done\") {\n setChatbotState(0);\n\n // update the status as done for the last message\n setMessageList(prevList => {\n let responseList = [...prevList];\n try {\n let latestMessage = responseList.slice(-1)[0];\n const finalResponseText = normalizedResponse || _utils_defaults__WEBPACK_IMPORTED_MODULE_6__.errorResponse;\n const whatsappConfig = chatbotConfig?.data?.external_redirect_metadata?.whatsapp;\n if (latestMessage?.source !== \"user\") {\n latestMessage.status = \"done\";\n latestMessage.data.text = finalResponseText;\n latestMessage.data.sources = normalizedSources;\n latestMessage.data.image_links = promotedImageLinks?.length > 0 ? promotedImageLinks : normalizedImageLinks;\n latestMessage.data.promoted_topics = normalizedPromotedTopics;\n\n // Logic to show support button after every 2nd answer\n const botMessageCount = responseList.filter(msg => msg.source === \"bot\" && msg.origin === \"server\").length;\n if (whatsappConfig) {\n const triggerFrequency = whatsappConfig?.trigger_message_frequency;\n const redirectUrl = whatsappConfig?.redirect_url;\n if (triggerFrequency && redirectUrl && botMessageCount % triggerFrequency === 0) {\n latestMessage.data.showSupportButton = true;\n latestMessage.data.supportUrl = redirectUrl;\n }\n }\n } else {\n let responseMessage = {\n source: \"bot\",\n data: {\n text: finalResponseText,\n sources: normalizedSources,\n image_links: promotedImageLinks?.length > 0 ? promotedImageLinks : normalizedImageLinks,\n promoted_topics: normalizedPromotedTopics\n },\n origin: \"server\",\n status: \"done\"\n };\n if (whatsappConfig) {\n const triggerFrequency = whatsappConfig?.trigger_message_frequency;\n const redirectUrl = whatsappConfig?.redirect_url;\n const nextBotMessageCount = responseList.filter(msg => msg.source === \"bot\" && msg.origin === \"server\").length + 1;\n if (triggerFrequency && redirectUrl && nextBotMessageCount % triggerFrequency === 0) {\n responseMessage.data.showSupportButton = true;\n responseMessage.data.supportUrl = redirectUrl;\n }\n }\n responseList = [...responseList, responseMessage];\n }\n } catch (error) {}\n return responseList;\n });\n }\n } catch (error) {}\n };\n\n // to keep the input field in focus and scroll to the latest message\n // when the enter button is clicked.\n // const focusInput = () => {\n // inputRef.current.focus();\n // };\n\n // to handle the minimize/maximize animation of the chatbot.\n const handleChatbotAnimation = () => {\n setChatbotMinimized(!chatbotMinimized);\n };\n\n // to reset the chatbot content.\n const resetChatbot = () => {\n try {\n streamAbortRef.current?.abort?.();\n streamAbortRef.current = null;\n conversationIdRef.current = randomId();\n setMessageList(defaultMessageList.current);\n setPromptsData(prevData => {\n return {\n ...prevData,\n show: true\n };\n });\n setChatbotState(0);\n setInputText(\"\");\n } catch (error) {}\n };\n const handleInput = event => {\n try {\n setInputText(event.target.value);\n } catch (error) {}\n };\n const getChatHistory = messages => {\n let response = [];\n try {\n let historyItem = {\n user: \"\",\n assistant: \"\"\n };\n for (let message of messages || []) {\n if (message.source === \"user\") {\n historyItem.user = message?.data?.text;\n } else if (message.source === \"bot\" && message.origin === \"server\") {\n if (message?.status === \"done\") {\n historyItem.assistant = message?.data?.text;\n response.push(historyItem);\n historyItem = {\n user: \"\",\n assistant: \"\"\n };\n }\n }\n }\n } catch (error) {\n console.log(error);\n } finally {\n return response;\n }\n };\n const getPromotionsShown = messages => {\n const out = [];\n try {\n let pendingUserSeen = false;\n for (let message of messages || []) {\n if (message.source === \"user\") {\n pendingUserSeen = true;\n continue;\n }\n if (!pendingUserSeen) continue;\n if (message.source === \"bot\" && message.origin === \"server\" && message.status === \"done\") {\n const titles = (message?.data?.promoted_topics || []).map(t => t?.title).filter(t => typeof t === \"string\" && t.trim().length > 0);\n out.push(titles);\n pendingUserSeen = false;\n }\n }\n } catch (error) {}\n return out;\n };\n const startNewStream = async (prompt, prevMessages) => {\n const chatbotBaseUrl = chatbotConfig?.data?.chatbot_url || chatbotConfig?.data?.chatbotUrl;\n if (!chatbotBaseUrl) {\n throw new Error(\"chatbot_url missing from config\");\n }\n streamAbortRef.current?.abort?.();\n const abortController = new AbortController();\n streamAbortRef.current = abortController;\n let chatHistory = getChatHistory(prevMessages);\n let promotionsShown = getPromotionsShown(prevMessages);\n if (chatHistory.length > 40) {\n const start = chatHistory.length - 40;\n chatHistory = chatHistory.slice(start);\n promotionsShown = promotionsShown.slice(start);\n }\n const messageId = randomId();\n const token = await resolveAuthToken({\n authToken,\n authTokenProvider\n });\n const pagePath = typeof window !== \"undefined\" ? window.location.pathname || \"/\" : \"/\";\n const session = await (0,_utils_sseClient__WEBPACK_IMPORTED_MODULE_8__.mintChatbotSessionToken)({\n chatbotBaseUrl,\n authToken: token,\n pagePath,\n signal: abortController.signal\n });\n if (!session?.token) {\n throw new Error(\"missing session token\");\n }\n await (0,_utils_sseClient__WEBPACK_IMPORTED_MODULE_8__.streamChatbotSse)({\n chatbotBaseUrl,\n token: session.token,\n body: {\n chatHistory,\n conversationId: conversationIdRef.current,\n message: prompt,\n messageId,\n promotionsShown\n },\n signal: abortController.signal,\n onEnvelope: handleStreamEnvelope\n });\n };\n const handleSubmit = async function () {\n let prompt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : \"\";\n let typewriterEffect = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n if (!prompt) {\n prompt = inputText;\n } else {\n typewriterEffect = true;\n }\n try {\n prompt = prompt.trim();\n if (prompt) {\n const prevMessages = messageList;\n setChatbotState(1);\n\n // put the user's prompt in the chat\n let userMessage = {\n source: \"user\",\n data: {\n text: prompt\n },\n status: \"done\",\n typewriterEffect\n };\n setMessageList(prevList => [...prevList, userMessage]);\n\n // hide the default prompts\n setPromptsData({\n ...promptsData,\n show: false\n });\n\n // clear the input field\n setInputText(\"\");\n await startNewStream(prompt, prevMessages);\n }\n } catch (error) {\n if (error?.name === \"AbortError\") {\n return;\n }\n console.error(\"Error sending chat message:\", error);\n setChatbotState(0);\n setMessageList(prevList => [...prevList, {\n source: \"error\",\n data: {\n text: _utils_defaults__WEBPACK_IMPORTED_MODULE_6__.errorResponse\n },\n status: \"done\"\n }]);\n }\n };\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.Fragment, {\n children: chatbotConfig?.fetchedData && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"div\", {\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotParent,\n ref: chatbotRef,\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxs)(framer_motion__WEBPACK_IMPORTED_MODULE_11__.LazyMotion, {\n features: framer_motion__WEBPACK_IMPORTED_MODULE_12__.domAnimation,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxs)(framer_motion__WEBPACK_IMPORTED_MODULE_13__.m.div, {\n initial: false,\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotContainer,\n animate: chatbotMinimized ? \"hide\" : \"show\",\n variants: _utils_variants__WEBPACK_IMPORTED_MODULE_4__.maximizedChatbotVariants,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(_components_ChatbotHeader__WEBPACK_IMPORTED_MODULE_1__[\"default\"], {\n headerText: chatbotConfig?.data?.header_text,\n setPromptsMinimized: setPromptsMinimized,\n handleChatbotAnimation: handleChatbotAnimation,\n resetChatbot: resetChatbot\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(_components_ChatbotBody__WEBPACK_IMPORTED_MODULE_2__[\"default\"], {\n messageList: messageList,\n promptsData: promptsData,\n handleSubmit: handleSubmit,\n chatbotState: chatbotState,\n scrollAnchorRef: scrollAnchorRef,\n promptsMinimized: promptsMinimized,\n setPromptsMinimized: setPromptsMinimized,\n inputRef: inputRef,\n inputText: inputText,\n handleInput: handleInput,\n placeholderInputText: chatbotConfig?.data?.placeholder_input_text,\n chatbotIcon: chatbotIcon\n })]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxs)(framer_motion__WEBPACK_IMPORTED_MODULE_13__.m.div, {\n variants: _utils_variants__WEBPACK_IMPORTED_MODULE_4__.minimizedChatbotVariants,\n animate: chatbotMinimized ? \"show\" : \"hide\",\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotCircleContainer,\n children: [!chatbotPopupMinimized && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxs)(framer_motion__WEBPACK_IMPORTED_MODULE_13__.m.div, {\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].popupContainer,\n variants: _utils_variants__WEBPACK_IMPORTED_MODULE_4__.minimizedChatbotContentVariants,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"button\", {\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].closePopup,\n onClick: () => setChatbotPopupMinimized(true),\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"i\", {\n className: \"bi bi-x-circle-fill\"\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"div\", {\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].popup,\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"div\", {\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].popupContent,\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"span\", {\n children: chatbotConfig?.data?.popup_body_text\n })\n })\n })]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(framer_motion__WEBPACK_IMPORTED_MODULE_13__.m.div, {\n variants: _utils_variants__WEBPACK_IMPORTED_MODULE_4__.minimizedChatbotContentVariants,\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotCircle,\n onClick: handleChatbotAnimation,\n children: chatbotIcon && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"div\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_9__.jsx)(\"img\", {\n src: chatbotIcon,\n loading: \"lazy\",\n alt: \"chatbot icon\",\n className: _Chatbot_module_css__WEBPACK_IMPORTED_MODULE_3__[\"default\"].chatbotIcon\n })\n })\n })]\n })]\n })\n })\n });\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Chatbot);\n\n//# sourceURL=webpack://VamChatbot/./Chatbot.jsx?");
|
|
30
30
|
|
|
31
31
|
/***/ }),
|
|
32
32
|
|
|
@@ -37,7 +37,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
|
37
37
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
38
38
|
|
|
39
39
|
"use strict";
|
|
40
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react_dom_client__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-dom/client */ \"./node_modules/react-dom/client.js\");\n/* harmony import */ var _Chatbot__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Chatbot */ \"./Chatbot.jsx\");\n/* harmony import */ var bootstrap_icons_font_bootstrap_icons_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! bootstrap-icons/font/bootstrap-icons.css */ \"./node_modules/bootstrap-icons/font/bootstrap-icons.css\");\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-runtime */ \"./node_modules/react/jsx-runtime.js\");\n\n\n\n\n\nlet globalSheets = null;\n\n// function to add the global style sheets to the context of the shadow root element\nfunction getGlobalStyleSheets() {\n if (globalSheets === null) {\n globalSheets = Array.from(document.styleSheets).map(x => {\n let id = x?.ownerNode?.id;\n const sheet = new CSSStyleSheet();\n if (id === \"chatbot-styles\") {\n const css = Array.from(x.cssRules).map(rule => {\n return rule.cssText;\n }).join(\" \");\n sheet.replaceSync(css);\n }\n return sheet;\n });\n }\n return globalSheets;\n}\nfunction addGlobalStylesToShadowRoot(shadowRoot) {\n shadowRoot.adoptedStyleSheets.push(...getGlobalStyleSheets());\n}\n\n// Function to fetch Bootstrap CSS\nasync function fetchBootstrapCSS() {\n const bootstrapResponse = await fetch(\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css\");\n const bootstrapCSS = await bootstrapResponse.text();\n return [bootstrapCSS];\n}\nclass WebComponent extends HTMLElement {\n constructor() {\n super();\n this.attachShadow({\n mode: \"open\"\n });\n this.root = null; // Store the root instance\n this.loadStylesAndRender();\n addGlobalStylesToShadowRoot(this.shadowRoot);\n }\n async loadStylesAndRender() {\n const [bootstrapCSS] = await fetchBootstrapCSS();\n\n // TODO: here the styles are applied to :root inside the shadow dom, but there is not root there.\n // We need to apply the variables on the :host/topmost class level rather than :root.\n const modifiedBootstrapCSS = bootstrapCSS.replace(/:root/g, \":host\");\n\n // Create a style element for Bootstrap styles\n const bootstrapStyleElement = document.createElement(\"style\");\n bootstrapStyleElement.textContent = modifiedBootstrapCSS;\n this.shadowRoot.appendChild(bootstrapStyleElement);\n\n // Render the React component\n this.render();\n }\n addGtmScript() {\n const gtmId = this.getAttribute(\"gtm-id\");\n if (!gtmId) {\n console.error(\"Chatbot GTM ID missing!\");\n return;\n }\n const head = document.createElement(\"head\");\n const script = document.createElement(\"script\");\n script.textContent = `\n (function (w, d, s, l, i) {\n w[l] = w[l] || [];\n w[l].push({ \"gtm.start\": new Date().getTime(), event: \"gtm.js\" });\n var f = d.getElementsByTagName(s)[0],\n j = d.createElement(s),\n dl = l != \"dataLayer\" ? \"&l=\" + l : \"\";\n j.async = true;\n j.src = \"https://www.googletagmanager.com/gtm.js?id=\" + i + dl;\n f.parentNode.insertBefore(j, f);\n })(window, document, \"script\", \"dataLayer\", \"${gtmId}\");\n `;\n\n // Append the script to the head\n head.appendChild(script);\n\n // Append the head to the document\n this.shadowRoot.appendChild(head);\n }\n\n // Function to push data to GTM data layer\n pushToDataLayer(data) {\n if (window.dataLayer) {\n window.dataLayer.push(data);\n } else {\n console.error(\"GTM data layer not available\");\n }\n }\n\n // Example method to send data to GTM\n sendDataToGTM(dataLayerObject) {\n const customData = {\n ...dataLayerObject,\n event: \"bot_click\",\n clientId: this.getAttribute(\"client-id\")\n };\n this.pushToDataLayer(customData);\n }\n connectedCallback() {\n if (!this.root) {\n this.root = react_dom_client__WEBPACK_IMPORTED_MODULE_1__.createRoot(this.shadowRoot);\n }\n this.addGtmScript();\n this.render();\n }\n disconnectedCallback() {\n if (this.root) {\n this.root.unmount();\n }\n }\n static get observedAttributes() {\n return [\"client-id\", \"gtm-id\"];\n }\n attributeChangedCallback(name, oldValue, newValue) {\n if (oldValue !== newValue) {\n this.render();\n }\n }\n render() {\n const clientId = this.getAttribute(\"client-id\");\n if (this.root) {\n this.root.render(/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_4__.jsx)(_Chatbot__WEBPACK_IMPORTED_MODULE_2__[\"default\"], {\n clientId: clientId,\n onTrackEvent: dataLayerObject => this.sendDataToGTM(dataLayerObject)\n }));\n }\n }\n}\ncustomElements.define(\"vam-chatbot\", WebComponent);\n\n//# sourceURL=webpack://VamChatbot/./WebComponent.js?");
|
|
40
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react_dom_client__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-dom/client */ \"./node_modules/react-dom/client.js\");\n/* harmony import */ var _Chatbot__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Chatbot */ \"./Chatbot.jsx\");\n/* harmony import */ var bootstrap_icons_font_bootstrap_icons_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! bootstrap-icons/font/bootstrap-icons.css */ \"./node_modules/bootstrap-icons/font/bootstrap-icons.css\");\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-runtime */ \"./node_modules/react/jsx-runtime.js\");\n\n\n\n\n\nlet globalSheets = null;\n\n// function to add the global style sheets to the context of the shadow root element\nfunction getGlobalStyleSheets() {\n if (globalSheets === null) {\n globalSheets = Array.from(document.styleSheets).map(x => {\n let id = x?.ownerNode?.id;\n const sheet = new CSSStyleSheet();\n if (id === \"chatbot-styles\") {\n const css = Array.from(x.cssRules).map(rule => {\n return rule.cssText;\n }).join(\" \");\n sheet.replaceSync(css);\n }\n return sheet;\n });\n }\n return globalSheets;\n}\nfunction addGlobalStylesToShadowRoot(shadowRoot) {\n shadowRoot.adoptedStyleSheets.push(...getGlobalStyleSheets());\n}\n\n// Function to fetch Bootstrap CSS\nasync function fetchBootstrapCSS() {\n const bootstrapResponse = await fetch(\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css\");\n const bootstrapCSS = await bootstrapResponse.text();\n return [bootstrapCSS];\n}\nclass WebComponent extends HTMLElement {\n constructor() {\n super();\n this.attachShadow({\n mode: \"open\"\n });\n this.root = null; // Store the root instance\n this._authTokenProvider = null;\n this.loadStylesAndRender();\n addGlobalStylesToShadowRoot(this.shadowRoot);\n }\n get authTokenProvider() {\n return this._authTokenProvider;\n }\n set authTokenProvider(providerFn) {\n this._authTokenProvider = typeof providerFn === \"function\" ? providerFn : null;\n this.render();\n }\n get authToken() {\n return this.getAttribute(\"auth-token\");\n }\n set authToken(value) {\n if (typeof value === \"string\" && value.trim().length > 0) {\n this.setAttribute(\"auth-token\", value);\n return;\n }\n this.removeAttribute(\"auth-token\");\n }\n async loadStylesAndRender() {\n const [bootstrapCSS] = await fetchBootstrapCSS();\n\n // TODO: here the styles are applied to :root inside the shadow dom, but there is not root there.\n // We need to apply the variables on the :host/topmost class level rather than :root.\n const modifiedBootstrapCSS = bootstrapCSS.replace(/:root/g, \":host\");\n\n // Create a style element for Bootstrap styles\n const bootstrapStyleElement = document.createElement(\"style\");\n bootstrapStyleElement.textContent = modifiedBootstrapCSS;\n this.shadowRoot.appendChild(bootstrapStyleElement);\n\n // Render the React component\n this.render();\n }\n addGtmScript() {\n const gtmId = this.getAttribute(\"gtm-id\");\n if (!gtmId) {\n console.error(\"Chatbot GTM ID missing!\");\n return;\n }\n const head = document.createElement(\"head\");\n const script = document.createElement(\"script\");\n script.textContent = `\n (function (w, d, s, l, i) {\n w[l] = w[l] || [];\n w[l].push({ \"gtm.start\": new Date().getTime(), event: \"gtm.js\" });\n var f = d.getElementsByTagName(s)[0],\n j = d.createElement(s),\n dl = l != \"dataLayer\" ? \"&l=\" + l : \"\";\n j.async = true;\n j.src = \"https://www.googletagmanager.com/gtm.js?id=\" + i + dl;\n f.parentNode.insertBefore(j, f);\n })(window, document, \"script\", \"dataLayer\", \"${gtmId}\");\n `;\n\n // Append the script to the head\n head.appendChild(script);\n\n // Append the head to the document\n this.shadowRoot.appendChild(head);\n }\n\n // Function to push data to GTM data layer\n pushToDataLayer(data) {\n if (window.dataLayer) {\n window.dataLayer.push(data);\n } else {\n console.error(\"GTM data layer not available\");\n }\n }\n\n // Example method to send data to GTM\n sendDataToGTM(dataLayerObject) {\n const customData = {\n ...dataLayerObject,\n event: \"bot_click\",\n clientId: this.getAttribute(\"client-id\")\n };\n this.pushToDataLayer(customData);\n }\n connectedCallback() {\n if (!this.root) {\n this.root = react_dom_client__WEBPACK_IMPORTED_MODULE_1__.createRoot(this.shadowRoot);\n }\n this.addGtmScript();\n this.render();\n }\n disconnectedCallback() {\n if (this.root) {\n this.root.unmount();\n }\n }\n static get observedAttributes() {\n return [\"client-id\", \"gtm-id\", \"auth-token\"];\n }\n attributeChangedCallback(name, oldValue, newValue) {\n if (oldValue !== newValue) {\n this.render();\n }\n }\n render() {\n const clientId = this.getAttribute(\"client-id\");\n const authToken = this.getAttribute(\"auth-token\") || \"\";\n if (this.root) {\n this.root.render(/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_4__.jsx)(_Chatbot__WEBPACK_IMPORTED_MODULE_2__[\"default\"], {\n clientId: clientId,\n authToken: authToken,\n authTokenProvider: this._authTokenProvider,\n onTrackEvent: dataLayerObject => this.sendDataToGTM(dataLayerObject)\n }));\n }\n }\n}\ncustomElements.define(\"vam-chatbot\", WebComponent);\n\n//# sourceURL=webpack://VamChatbot/./WebComponent.js?");
|
|
41
41
|
|
|
42
42
|
/***/ }),
|
|
43
43
|
|
|
@@ -191,7 +191,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
|
191
191
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
192
192
|
|
|
193
193
|
"use strict";
|
|
194
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ mintChatbotSessionToken: () => (/* binding */ mintChatbotSessionToken),\n/* harmony export */ streamChatbotSse: () => (/* binding */ streamChatbotSse)\n/* harmony export */ });\nconst normalizeBaseUrl = baseUrl => String(baseUrl || \"\").replace(/\\/+$/, \"\");\nasync function mintChatbotSessionToken(_ref) {\n let {\n chatbotBaseUrl,\n
|
|
194
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ mintChatbotSessionToken: () => (/* binding */ mintChatbotSessionToken),\n/* harmony export */ streamChatbotSse: () => (/* binding */ streamChatbotSse)\n/* harmony export */ });\nconst normalizeBaseUrl = baseUrl => String(baseUrl || \"\").replace(/\\/+$/, \"\");\nasync function mintChatbotSessionToken(_ref) {\n let {\n chatbotBaseUrl,\n authToken,\n pagePath = \"/\",\n signal\n } = _ref;\n const url = `${normalizeBaseUrl(chatbotBaseUrl)}/chat/session`;\n const headers = {\n \"Content-Type\": \"application/json\"\n };\n if (typeof authToken === \"string\" && authToken.trim()) {\n headers.Authorization = `Bearer ${authToken.trim()}`;\n }\n const resp = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n page_path: pagePath || \"/\"\n }),\n signal\n });\n if (!resp.ok) {\n const text = await resp.text().catch(() => \"\");\n throw new Error(`mint session failed (${resp.status}): ${text || resp.statusText}`);\n }\n return resp.json();\n}\nasync function streamChatbotSse(_ref2) {\n let {\n chatbotBaseUrl,\n token,\n body,\n signal,\n onEnvelope\n } = _ref2;\n const url = `${normalizeBaseUrl(chatbotBaseUrl)}/chat/stream`;\n const resp = await fetch(url, {\n method: \"POST\",\n headers: {\n Accept: \"text/event-stream\",\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`\n },\n body: JSON.stringify(body),\n signal\n });\n if (!resp.ok) {\n const text = await resp.text().catch(() => \"\");\n throw new Error(`stream failed (${resp.status}): ${text || resp.statusText}`);\n }\n if (!resp.body) {\n throw new Error(\"stream failed: missing response body\");\n }\n const reader = resp.body.getReader();\n const decoder = new TextDecoder(\"utf-8\");\n let buffer = \"\";\n let eventDataLines = [];\n const flushEvent = () => {\n if (eventDataLines.length === 0) return;\n const payload = eventDataLines.join(\"\\n\").trim();\n eventDataLines = [];\n if (!payload) return;\n try {\n onEnvelope(JSON.parse(payload));\n } catch {\n // ignore\n }\n };\n while (true) {\n const {\n value,\n done\n } = await reader.read();\n if (done) {\n flushEvent();\n break;\n }\n buffer += decoder.decode(value, {\n stream: true\n });\n while (true) {\n const newlineIndex = buffer.indexOf(\"\\n\");\n if (newlineIndex === -1) break;\n const rawLine = buffer.slice(0, newlineIndex);\n buffer = buffer.slice(newlineIndex + 1);\n const line = rawLine.endsWith(\"\\r\") ? rawLine.slice(0, -1) : rawLine;\n if (line === \"\") {\n flushEvent();\n continue;\n }\n if (line.startsWith(\":\")) continue;\n if (line.startsWith(\"data:\")) {\n eventDataLines.push(line.slice(\"data:\".length).trimStart());\n }\n }\n }\n}\n\n//# sourceURL=webpack://VamChatbot/./utils/sseClient.js?");
|
|
195
195
|
|
|
196
196
|
/***/ }),
|
|
197
197
|
|