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