UNPKG

saydata

Version:

Saydata seamlessly integrates AI-driven analytics for your customers into your app. Designed for beautiful visualization. Engineered for simplicity.

400 lines (399 loc) 26.8 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; import { AddCircleOutlineRounded, AutoAwesomeRounded, SendRounded, } from "@mui/icons-material"; import { Avatar, Button, IconButton, InputAdornment, TextField, Popover, CircularProgress, FormControlLabel, } from "@mui/material"; import classes from "./Chat.module.scss"; import { useEffect, useRef, useState } from "react"; import logo from "../icons/logo_s.svg"; import { StyledSwitch, stringAvatar } from "../utils/util"; import { v4 } from "uuid"; import RowsView from "../utils/RowsView"; import Graphs from "../charts/Graphs"; import { CustomQueryClient, LOADING_TEXTS } from "../utils/constant"; import TileView from "../utils/TileView"; import { ReactMarkdown } from "react-markdown/lib/react-markdown"; import remarkGfm from "remark-gfm"; import rehypeRaw from "rehype-raw"; export default function Chats(_a) { var _b, _c; var email = _a.email, chatId = _a.chatId, chatDetails = _a.chatDetails, refetch = _a.refetch, addChat = _a.addChat, addingChat = _a.addingChat, patchChat = _a.patchChat, patchingChat = _a.patchingChat, dashboards = _a.dashboards, updateDashboard = _a.updateDashboard, updatingDashboard = _a.updatingDashboard, connection = _a.connection, activeConnection = _a.activeConnection, refetchConnection = _a.refetchConnection, dashboardId = _a.dashboardId; var _d = useState(LOADING_TEXTS[0]), loadingText = _d[0], setLoadingText = _d[1]; var inputRef = useRef(null); var _e = useState({ role: "system", blockId: "", markdownString: "", }), selectedChat = _e[0], setSelectedChat = _e[1]; useEffect(function () { var _a; if (activeConnection) { refetchConnection(); if (((_a = chatHistory === null || chatHistory === void 0 ? void 0 : chatHistory.chatItems) === null || _a === void 0 ? void 0 : _a.length) === 0) { var newChatItems = __spreadArray([], chatHistory === null || chatHistory === void 0 ? void 0 : chatHistory.chatItems, true); newChatItems.push({ role: "welcome", blockId: v4(), }); chatHistory.chatItems = newChatItems; setChatHistory(chatHistory); } } }, [activeConnection]); var chatRef = useRef(null); var _f = useState({ id: chatId, email: email, connectionId: activeConnection, chatItems: [], }), chatHistory = _f[0], setChatHistory = _f[1]; var _g = useState(""), currentText = _g[0], setCurrentText = _g[1]; var _h = useState(""), currentGraphText = _h[0], setCurrentGraphText = _h[1]; var _j = useState(null), anchorElGraph = _j[0], setAnchorElGraph = _j[1]; var handleGraphClick = function (event, clickedChat) { setAnchorElGraph(event.currentTarget); setSelectedChat(clickedChat); }; var handleGraphClose = function () { setAnchorElGraph(null); }; var openGraphPopover = Boolean(anchorElGraph); var _k = useState(""), currentFeedbackText = _k[0], setCurrentFeedbackText = _k[1]; var _l = useState(null), anchorElFeedback = _l[0], setFeedbackAnchorEl = _l[1]; var handleFeedbackClose = function () { setFeedbackAnchorEl(null); }; var feedbackPopover = Boolean(anchorElFeedback); useEffect(function () { setChatHistory({ id: chatId, email: email, connectionId: activeConnection, chatItems: [], }); refetch(); }, [chatId]); useEffect(function () { var _a, _b, _c; if (chatDetails === null || chatDetails === void 0 ? void 0 : chatDetails.data) { if (((_b = (_a = chatDetails.data) === null || _a === void 0 ? void 0 : _a.chatItems) === null || _b === void 0 ? void 0 : _b.length) > 0) { setChatHistory(chatDetails.data); } else { var newChatItems = __spreadArray([], (_c = chatDetails.data) === null || _c === void 0 ? void 0 : _c.chatItems, true); newChatItems.push({ role: "welcome", blockId: v4(), }); chatDetails.data.chatItems = newChatItems; setChatHistory(chatDetails.data); } } }, [chatDetails]); var changeLoadingText = function () { var index = Math.floor(Math.random() * LOADING_TEXTS.length); setLoadingText(LOADING_TEXTS[index]); }; var scrollToBottom = function () { setTimeout(function () { if (chatRef.current) { var scrollOptions = { top: chatRef.current.scrollHeight, behavior: "smooth", }; chatRef.current.scrollTo(scrollOptions); } }, 100); }; var onSubmit = function (text) { var _a, _b; var newChatHistory = __assign({}, chatHistory); (_a = newChatHistory.chatItems) === null || _a === void 0 ? void 0 : _a.push({ role: "user", markdownString: text, blockId: v4(), }); setChatHistory(newChatHistory); setCurrentText(""); (_b = newChatHistory.chatItems) === null || _b === void 0 ? void 0 : _b.push({ role: "loading", blockId: v4(), }); setChatHistory(newChatHistory); var loadInterval = setInterval(function () { changeLoadingText(); }, 4000); var request = { chatId: chatId, question: text, blockId: v4(), connectionId: chatHistory.connectionId || activeConnection, }; addChat(request, { onSuccess: function (response) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; (_a = newChatHistory.chatItems) === null || _a === void 0 ? void 0 : _a.splice(-1); clearInterval(loadInterval); (_b = newChatHistory.chatItems) === null || _b === void 0 ? void 0 : _b.push({ role: "system", markdownString: (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.markdownString, sql: (_d = response === null || response === void 0 ? void 0 : response.data) === null || _d === void 0 ? void 0 : _d.sql, blockId: (_e = response === null || response === void 0 ? void 0 : response.data) === null || _e === void 0 ? void 0 : _e.blockId, showSql: false, graph: (_f = response === null || response === void 0 ? void 0 : response.data) === null || _f === void 0 ? void 0 : _f.graph, rows: (_g = response === null || response === void 0 ? void 0 : response.data) === null || _g === void 0 ? void 0 : _g.rows, title: (_h = response === null || response === void 0 ? void 0 : response.data) === null || _h === void 0 ? void 0 : _h.title, value: (_j = response === null || response === void 0 ? void 0 : response.data) === null || _j === void 0 ? void 0 : _j.value, }); setChatHistory(newChatHistory); scrollToBottom(); }, onError: function (error) { var _a, _b; (_a = newChatHistory.chatItems) === null || _a === void 0 ? void 0 : _a.splice(-1); clearInterval(loadInterval); (_b = newChatHistory.chatItems) === null || _b === void 0 ? void 0 : _b.push({ role: "error", markdownString: (error === null || error === void 0 ? void 0 : error.message) === "Guardrails check failed" ? "Invalid question, please ask valid questions about the selected dataset only." : "Current model was not able to find any results, upgrade your model for better and complex analysis. \n [Book a demo](https://calendly.com/say-data/30min)", blockId: v4(), }); setChatHistory(newChatHistory); scrollToBottom(); }, onSettled: function () { setTimeout(function () { var _a; (_a = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); }, 100); }, }); }; var onBlockUpdate = function (blockId, key, newVal) { var newChatItems = __spreadArray([], chatHistory.chatItems, true); var chatBlockIndex = newChatItems === null || newChatItems === void 0 ? void 0 : newChatItems.findIndex(function (chat) { return chat.blockId === blockId && (chat === null || chat === void 0 ? void 0 : chat.role) === "system"; }); if (chatBlockIndex && chatBlockIndex !== -1) { var chatBlock = newChatItems === null || newChatItems === void 0 ? void 0 : newChatItems[chatBlockIndex]; chatBlock[key] = newVal; newChatItems[chatBlockIndex] = chatBlock; setChatHistory(__assign(__assign({}, chatHistory), { chatItems: newChatItems })); } }; var onFeedbackSave = function (message, blockId) { var selectBlock = blockId ? blockId : selectedChat === null || selectedChat === void 0 ? void 0 : selectedChat.blockId; var newChatHistory = __spreadArray([], chatHistory.chatItems, true); var chatBlockIndex = newChatHistory === null || newChatHistory === void 0 ? void 0 : newChatHistory.findIndex(function (chat) { return chat.blockId === selectBlock && (chat === null || chat === void 0 ? void 0 : chat.role) === "system"; }); var chatBlock = newChatHistory === null || newChatHistory === void 0 ? void 0 : newChatHistory[chatBlockIndex]; var patchRequest = { chatId: chatId, feedback: message ? message : currentFeedbackText, blockId: chatBlock === null || chatBlock === void 0 ? void 0 : chatBlock.blockId, connectionId: chatHistory.connectionId || activeConnection, }; var request = { key: "feedback", chatItem: patchRequest, }; patchChat(request, { onSuccess: function (response) { var _a; chatBlock.feedback = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.feedback; newChatHistory[chatBlockIndex] = chatBlock; setChatHistory(__assign(__assign({}, chatHistory), { chatItems: newChatHistory })); }, onSettled: function () { setCurrentFeedbackText(""); handleFeedbackClose(); }, }); }; var onGraphNlpEditSave = function () { var newChatHistory = __spreadArray([], chatHistory.chatItems, true); var chatBlockIndex = newChatHistory === null || newChatHistory === void 0 ? void 0 : newChatHistory.findIndex(function (chat) { return chat.blockId === selectedChat.blockId && (chat === null || chat === void 0 ? void 0 : chat.role) === "system"; }); var chatBlock = newChatHistory === null || newChatHistory === void 0 ? void 0 : newChatHistory[chatBlockIndex]; var patchRequest = { chatId: chatId, sql: chatBlock === null || chatBlock === void 0 ? void 0 : chatBlock.sql, graph: chatBlock === null || chatBlock === void 0 ? void 0 : chatBlock.graph, blockId: chatBlock === null || chatBlock === void 0 ? void 0 : chatBlock.blockId, question: currentGraphText, rows: chatBlock === null || chatBlock === void 0 ? void 0 : chatBlock.rows, connectionId: chatHistory.connectionId || activeConnection, }; var request = { key: "graph", chatItem: patchRequest, }; patchChat(request, { onSuccess: function (response) { var _a; chatBlock.graph = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.graph; newChatHistory[chatBlockIndex] = chatBlock; setChatHistory(__assign(__assign({}, chatHistory), { chatItems: newChatHistory })); setCurrentGraphText(""); handleGraphClose(); }, }); }; var addChartToDashboard = function (dashboardSelected, chat, selectedBlockType) { var request = { id: dashboardSelected, obj: { chatItem: { blockId: chat.blockId, rows: chat.rows, graph: chat.graph, sql: chat.sql, chatId: chatId, title: chat.title, value: chat.value, }, type: selectedBlockType, chatId: chatId, x: 0, y: 0, width: selectedBlockType === "tile" ? 3 : 6, height: selectedBlockType === "tile" ? 3 : 6, }, }; updateDashboard(request, { onSuccess: function () { CustomQueryClient.invalidateQueries(["dashboard", dashboardSelected]); }, }); }; useEffect(function () { scrollToBottom(); }, [(_b = chatHistory === null || chatHistory === void 0 ? void 0 : chatHistory.chatItems) === null || _b === void 0 ? void 0 : _b.length]); var handleEnterEvent = function (e) { if (e.keyCode === 13) { onSubmit(currentText); } }; var handleGraphEnterEvent = function (e) { if (e.keyCode === 13) { onGraphNlpEditSave(); } }; var onPredefinedClick = function (text) { setCurrentText(text); onSubmit(text); }; return (_jsxs("div", __assign({ className: classes.root }, { children: [_jsx("div", __assign({ className: classes.top, ref: chatRef }, { children: (_c = chatHistory === null || chatHistory === void 0 ? void 0 : chatHistory.chatItems) === null || _c === void 0 ? void 0 : _c.map(function (chat, index) { var _a, _b, _c, _d, _e, _f; return (_jsx("div", __assign({ className: classes.content }, { children: _jsxs("div", __assign({ className: classes.innerDiv }, { children: [chat.role !== "user" ? (_jsx("img", { className: classes.logoTile, src: logo, alt: "Logo", height: 30 })) : (_jsx(Avatar, __assign({ className: classes.logoTile }, stringAvatar(email)))), _jsxs("div", __assign({ style: { display: "flex", flexDirection: "column", width: "95%", gap: "12px", } }, { children: [(chat === null || chat === void 0 ? void 0 : chat.role) === "loading" && (_jsx("div", __assign({ className: classes.markdown, style: { marginTop: 14 } }, { children: loadingText }))), (chat === null || chat === void 0 ? void 0 : chat.role) === "welcome" && (_jsxs("div", __assign({ className: classes.welcome }, { children: [_jsx("div", { children: "Create visualisations for your dashboards here." }), _jsx("div", { children: "Just type your questions to get started. Generate embeddable links once done." }), ((_a = connection === null || connection === void 0 ? void 0 : connection.data) === null || _a === void 0 ? void 0 : _a.sampleQuestions) && (_jsxs(_Fragment, { children: [_jsx("div", { children: "Below are some common questions asked on this dataset :" }), _jsx("div", __assign({ className: classes.sampleQuestions }, { children: (_c = (_b = connection === null || connection === void 0 ? void 0 : connection.data) === null || _b === void 0 ? void 0 : _b.sampleQuestions) === null || _c === void 0 ? void 0 : _c.map(function (question) { return (_jsx("div", __assign({ className: classes.preDefined }, { children: _jsx(Button, __assign({ className: classes.textq, onClick: function () { return onPredefinedClick(question); } }, { children: question })) }))); }) }))] }))] }))), (chat === null || chat === void 0 ? void 0 : chat.role) === "system" && (_jsx(RowsView, { rows: (chat === null || chat === void 0 ? void 0 : chat.rows) || [], chat: chat, addChartToDashboard: addChartToDashboard, blockId: chat === null || chat === void 0 ? void 0 : chat.blockId, dashboardId: dashboardId, loading: patchingChat })), (chat === null || chat === void 0 ? void 0 : chat.markdownString) && ((chat === null || chat === void 0 ? void 0 : chat.role) === "system" ? (_jsxs(_Fragment, { children: [_jsx("div", __assign({ className: classes.explanation }, { children: _jsx(FormControlLabel, { control: _jsx(StyledSwitch, { shade: "#4B0082", checked: chat === null || chat === void 0 ? void 0 : chat.showExplanation, onChange: function (e) { return onBlockUpdate(chat === null || chat === void 0 ? void 0 : chat.blockId, "showExplanation", e.target.checked); } }), label: "Show explanation", labelPlacement: "start", style: { padding: "8px 0px 8px 0px" } }) })), (chat === null || chat === void 0 ? void 0 : chat.showExplanation) && (_jsx("div", __assign({ style: { border: "1px solid rgba(224, 224, 224, 1)", borderRadius: "12px", padding: "12px", } }, { children: _jsx(ReactMarkdown, { className: classes.markdown, children: chat === null || chat === void 0 ? void 0 : chat.markdownString, remarkPlugins: [remarkGfm], rehypePlugins: [rehypeRaw] }) })))] })) : (_jsx(ReactMarkdown, { className: classes.markdown, children: chat === null || chat === void 0 ? void 0 : chat.markdownString, remarkPlugins: [remarkGfm], rehypePlugins: [rehypeRaw] }))), (chat === null || chat === void 0 ? void 0 : chat.role) === "system" && (chat === null || chat === void 0 ? void 0 : chat.graph) && ((_d = chat.rows) === null || _d === void 0 ? void 0 : _d.length) >= 2 && (_jsxs("div", __assign({ className: classes.graph }, { children: [_jsxs("div", __assign({ style: { display: "flex", gap: "8px", marginLeft: "auto", marginTop: "8px", } }, { children: [_jsx(Button, __assign({ style: { marginLeft: "auto" }, className: classes.textButton, size: "small", onClick: function (e) { return handleGraphClick(e, chat); }, startIcon: _jsx(AutoAwesomeRounded, {}) }, { children: "Edit" })), _jsx(Button, __assign({ style: { marginLeft: "auto" }, className: classes.textButton, onClick: function (e) { return addChartToDashboard(dashboardId, chat, "graph"); }, size: "small", startIcon: _jsx(AddCircleOutlineRounded, {}) }, { children: "Add to Dashboard" }))] })), _jsx("div", __assign({ className: classes.container }, { children: _jsx(Graphs, { rows: chat === null || chat === void 0 ? void 0 : chat.rows, options: chat === null || chat === void 0 ? void 0 : chat.graph }) }))] }))), ((_e = chat === null || chat === void 0 ? void 0 : chat.rows) === null || _e === void 0 ? void 0 : _e.length) === 1 && (chat === null || chat === void 0 ? void 0 : chat.value) && (_jsxs("div", __assign({ className: classes.tile }, { children: [_jsx("div", __assign({ style: { display: "flex", gap: "8px", marginLeft: "auto", marginTop: "8px", marginBottom: "8px", } }, { children: _jsx(Button, __assign({ style: { marginLeft: "auto" }, className: classes.textButton, onClick: function (e) { return addChartToDashboard(dashboardId, chat, "tile"); }, size: "small", startIcon: _jsx(AddCircleOutlineRounded, {}) }, { children: "Add to Dashboard" })) })), _jsx(TileView, { title: chat === null || chat === void 0 ? void 0 : chat.title, value: (_f = chat === null || chat === void 0 ? void 0 : chat.rows) === null || _f === void 0 ? void 0 : _f[0][chat === null || chat === void 0 ? void 0 : chat.value] })] })))] }))] })) }), (chat === null || chat === void 0 ? void 0 : chat.blockId) + (chat === null || chat === void 0 ? void 0 : chat.role))); }) })), _jsx(TextField, { value: currentText, onChange: function (e) { return setCurrentText(e.target.value); }, onKeyDown: handleEnterEvent, sx: { width: "calc(100% - 50px)", marginTop: "auto", padding: "0px 24px 24px 24px", "& .MuiOutlinedInput-root": { "&.Mui-focused fieldset": { borderColor: "#4B0082", borderWidth: 1, }, }, }, placeholder: "Ask a question", ref: inputRef, InputProps: { disabled: addingChat, autoFocus: true, style: { borderRadius: 8, boxShadow: "0px 2px 15px 0px rgba(115, 40, 171, 0.60)", height: 44, }, endAdornment: (_jsx(InputAdornment, __assign({ position: "end" }, { children: addingChat ? (_jsx(CircularProgress, { size: 20, sx: { color: "#4B0082" } })) : (_jsx(IconButton, __assign({ onClick: function () { return onSubmit(currentText); }, className: classes.iconButton }, { children: _jsx(SendRounded, {}) }))) }))), } }), _jsx(Popover, __assign({ id: "graph-edit", open: openGraphPopover, anchorEl: anchorElGraph, className: classes.graphPopper, classes: { paper: classes.paper }, onClose: handleGraphClose, anchorOrigin: { vertical: "bottom", horizontal: "right", }, transformOrigin: { vertical: "top", horizontal: "right", } }, { children: _jsx(TextField, { value: currentGraphText, onChange: function (e) { return setCurrentGraphText(e.target.value); }, onKeyDown: handleGraphEnterEvent, sx: { "& .MuiOutlinedInput-root": { "&.Mui-focused fieldset": { // borderColor: "#4B0082", // borderWidth: 1, border: "transparent", }, fieldset: { border: "transparent", }, }, }, placeholder: "convert it to line, area, bar...", InputProps: { style: { // borderRadius: 6, // boxShadow: "0px 2px 15px 0px rgba(115, 40, 171, 0.60)", height: 36, width: 400, }, endAdornment: (_jsx(InputAdornment, __assign({ position: "end" }, { children: patchingChat ? (_jsx(CircularProgress, { size: 16, sx: { color: "#4B0082" } })) : (_jsx(IconButton, __assign({ onClick: onGraphNlpEditSave, className: classes.iconButton }, { children: _jsx(SendRounded, {}) }))) }))), } }) })), _jsxs(Popover, __assign({ id: "feedback-share", open: feedbackPopover, anchorEl: anchorElFeedback, className: classes.feedbackPopper, classes: { paper: classes.paper }, onClose: handleFeedbackClose, anchorOrigin: { vertical: "bottom", horizontal: "right", }, transformOrigin: { vertical: "top", horizontal: "right", } }, { children: [_jsx(TextField, { value: currentFeedbackText, onChange: function (e) { return setCurrentFeedbackText(e.target.value); }, // onKeyDown={handleFeedbackEnterEvent} sx: { "& .MuiOutlinedInput-root": { "&.Mui-focused fieldset": { border: "transparent", }, fieldset: { border: "transparent", }, }, }, multiline: true, rows: 4, maxRows: 4, placeholder: "improve accuracy by explaining what went wrong...", InputProps: { style: { width: 500, }, } }), _jsx("div", __assign({ className: classes.footer }, { children: _jsx(Button, __assign({ variant: "contained", size: "small", onClick: function () { return onFeedbackSave(); } }, { children: "Submit" })) }))] }))] }))); }