From e020e2312442515fe85a3f7723e3071c7edc928e Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 10 Jul 2023 16:20:18 -0300 Subject: [PATCH] Fixed tooltip not being at the top of all nodes --- src/frontend/src/components/ui/tooltip.tsx | 20 +- .../modals/chatModal/chatMessage/index.tsx | 156 ------- src/frontend/src/modals/chatModal/index.tsx | 423 ------------------ 3 files changed, 11 insertions(+), 588 deletions(-) delete mode 100644 src/frontend/src/modals/chatModal/chatMessage/index.tsx delete mode 100644 src/frontend/src/modals/chatModal/index.tsx diff --git a/src/frontend/src/components/ui/tooltip.tsx b/src/frontend/src/components/ui/tooltip.tsx index dc847052e..6bb983652 100644 --- a/src/frontend/src/components/ui/tooltip.tsx +++ b/src/frontend/src/components/ui/tooltip.tsx @@ -14,15 +14,17 @@ const TooltipContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, sideOffset = 4, ...props }, ref) => ( - + + + )); TooltipContent.displayName = TooltipPrimitive.Content.displayName; diff --git a/src/frontend/src/modals/chatModal/chatMessage/index.tsx b/src/frontend/src/modals/chatModal/chatMessage/index.tsx deleted file mode 100644 index 2411f2103..000000000 --- a/src/frontend/src/modals/chatModal/chatMessage/index.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import Convert from "ansi-to-html"; -import { MessageCircle, User2 } from "lucide-react"; -import { useEffect, useRef, useState } from "react"; -import ReactMarkdown from "react-markdown"; -import rehypeMathjax from "rehype-mathjax"; -import remarkGfm from "remark-gfm"; -import remarkMath from "remark-math"; -import AiIcon from "../../../assets/Gooey Ring-5s-271px.svg"; -import AiIconStill from "../../../assets/froze-flow.png"; -import SanitizedHTMLWrapper from "../../../components/SanitizedHTMLWrapper"; -import { ChatMessageType } from "../../../types/chat"; -import { classNames } from "../../../utils"; -import { CodeBlock } from "../../formModal/chatMessage/codeBlock"; -import FileCard from "../../formModal/fileComponent"; -export default function ChatMessage({ - chat, - lockChat, - lastMessage, -}: { - chat: ChatMessageType; - lockChat: boolean; - lastMessage: boolean; -}) { - const convert = new Convert({ newline: true }); - const [message, setMessage] = useState(""); - const imgRef = useRef(null); - useEffect(() => { - setMessage(chat.message); - }, [chat.message]); - const [hidden, setHidden] = useState(true); - return ( -
-
- {!chat.isSend && ( -
- - -
- )} - {chat.isSend && } -
- {!chat.isSend ? ( -
-
- {hidden && chat.thought && chat.thought !== "" && ( -
setHidden((prev) => !prev)} - className="chat-message-modal-icon-div" - > - -
- )} - {chat.thought && chat.thought !== "" && !hidden && ( - setHidden((prev) => !prev)} - /> - )} - {chat.thought && chat.thought !== "" && !hidden &&

} -
-
-
- - ▍ - - ); - } - - children[0] = (children[0] as string).replace( - "`▍`", - "▍" - ); - } - - const match = /language-(\w+)/.exec(className || ""); - - return !inline ? ( - - ) : ( - - {children} - - ); - }, - }} - > - {message} - -
- {chat.files && ( -
- {chat.files.map((file, index) => { - return ( -
- -
- ); - })} -
- )} -
-
-
-
- ) : ( -
-
- {message.split("\n").map((line, index) => ( - - {line} -
-
- ))} -
-
- )} -
- ); -} diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx deleted file mode 100644 index 90baca4df..000000000 --- a/src/frontend/src/modals/chatModal/index.tsx +++ /dev/null @@ -1,423 +0,0 @@ -import { Dialog, Transition } from "@headlessui/react"; -import { Eraser, MessagesSquare, X } from "lucide-react"; -import { Fragment, useContext, useEffect, useRef, useState } from "react"; -import { alertContext } from "../../contexts/alertContext"; -import { typesContext } from "../../contexts/typesContext"; -import { sendAllProps } from "../../types/api"; -import { ChatMessageType } from "../../types/chat"; -import { FlowType } from "../../types/flow"; -import { validateNodes } from "../../utils"; -import ChatInput from "./chatInput"; -import ChatMessage from "./chatMessage"; - -import _ from "lodash"; -import { getHealth } from "../../controllers/API"; - -export default function ChatModal({ - flow, - open, - setOpen, -}: { - open: boolean; - setOpen: Function; - flow: FlowType; -}) { - const [chatValue, setChatValue] = useState(""); - const [chatHistory, setChatHistory] = useState([]); - const { reactFlowInstance } = useContext(typesContext); - const { setErrorData } = useContext(alertContext); - const ws = useRef(null); - const [lockChat, setLockChat] = useState(false); - const isOpen = useRef(open); - const messagesRef = useRef(null); - const id = useRef(flow.id); - - useEffect(() => { - if (messagesRef.current) { - messagesRef.current.scrollTop = messagesRef.current.scrollHeight; - } - }, [chatHistory]); - - useEffect(() => { - isOpen.current = open; - }, [open]); - useEffect(() => { - id.current = flow.id; - }, [flow.id]); - - var isStream = false; - - const addChatHistory = ( - message: string, - isSend: boolean, - thought?: string, - files?: Array - ) => { - setChatHistory((old) => { - let newChat = _.cloneDeep(old); - if (files) { - newChat.push({ message, isSend, files, thought }); - } else if (thought) { - newChat.push({ message, isSend, thought }); - } else { - newChat.push({ message, isSend }); - } - return newChat; - }); - }; - - //add proper type signature for function - - function updateLastMessage({ - str, - thought, - end = false, - files, - }: { - str?: string; - thought?: string; - // end param default is false - end?: boolean; - files?: Array; - }) { - setChatHistory((old) => { - let newChat = [...old]; - if (str) { - if (end) { - newChat[newChat.length - 1].message = str; - } else { - newChat[newChat.length - 1].message += str; - } - } - if (thought) { - if (end) { - newChat[newChat.length - 1].thought = thought; - } else { - newChat[newChat.length - 1].thought += thought; - } - } - if (files) { - newChat[newChat.length - 1].files = files; - } - return newChat; - }); - } - - function handleOnClose(event: CloseEvent) { - if (isOpen.current) { - setErrorData({ title: event.reason }); - setTimeout(() => { - connectWS(); - setLockChat(false); - }, 1000); - } - } - - function getWebSocketUrl(chatId, isDevelopment = false) { - const isSecureProtocol = window.location.protocol === "https:"; - const webSocketProtocol = isSecureProtocol ? "wss" : "ws"; - const host = isDevelopment ? "localhost:7860" : window.location.host; - const chatEndpoint = `/api/v1/chat/${chatId}`; - - return `${ - isDevelopment ? "ws" : webSocketProtocol - }://${host}${chatEndpoint}`; - } - - function handleWsMessage(data: any) { - if (Array.isArray(data)) { - //set chat history - setChatHistory((_) => { - let newChatHistory: ChatMessageType[] = []; - data.forEach( - (chatItem: { - intermediate_steps?: "string"; - is_bot: boolean; - message: string; - type: string; - files?: Array; - }) => { - if (chatItem.message) { - newChatHistory.push( - chatItem.files - ? { - isSend: !chatItem.is_bot, - message: chatItem.message, - thought: chatItem.intermediate_steps, - files: chatItem.files, - } - : { - isSend: !chatItem.is_bot, - message: chatItem.message, - thought: chatItem.intermediate_steps, - } - ); - } - } - ); - return newChatHistory; - }); - } - if (data.type === "start") { - addChatHistory("", false); - isStream = true; - } - if (data.type === "end") { - if (data.message) { - updateLastMessage({ str: data.message, end: true }); - } - if (data.intermediate_steps) { - updateLastMessage({ - str: data.message, - thought: data.intermediate_steps, - end: true, - }); - } - if (data.files) { - updateLastMessage({ - end: true, - files: data.files, - }); - } - - setLockChat(false); - isStream = false; - } - if (data.type === "stream" && isStream) { - updateLastMessage({ - str: data.message, - thought: data.intermediate_steps, - }); - } - } - - function connectWS() { - try { - const urlWs = getWebSocketUrl( - id.current, - process.env.NODE_ENV === "development" - ); - const newWs = new WebSocket(urlWs); - newWs.onopen = () => { - console.log("WebSocket connection established!"); - }; - newWs.onmessage = (event) => { - const data = JSON.parse(event.data); - console.log("Received data:", data); - handleWsMessage(data); - //get chat history - }; - newWs.onclose = (event) => { - handleOnClose(event); - }; - newWs.onerror = (ev) => { - getHealth() - .then((res) => { - if (res.status === 200) { - connectWS(); - } - }) - .catch((err) => { - setErrorData({ - // message when the backend failed - title: "The backend is not responding. Please try again later.", - // possible solution list - list: [ - "Check your internet connection.", - "Check if the backend is running.", - ], - }); - }); - }; - ws.current = newWs; - } catch (error) { - connectWS(); - console.log(error); - } - } - - useEffect(() => { - connectWS(); - return () => { - console.log("unmount"); - console.log(ws); - if (ws.current) { - ws.current.close(); - } - }; - }, []); - - useEffect(() => { - if ( - ws.current && - (ws.current.readyState === ws.current.CLOSED || - ws.current.readyState === ws.current.CLOSING) - ) { - connectWS(); - setLockChat(false); - } - }, [lockChat]); - - async function sendAll(data: sendAllProps) { - try { - if (ws) { - ws.current.send(JSON.stringify(data)); - } - } catch (error) { - setErrorData({ - title: "There was an error sending the message", - list: [error.message], - }); - setChatValue(data.message); - connectWS(); - } - } - - useEffect(() => { - if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" }); - }, [chatHistory]); - - const ref = useRef(null); - - useEffect(() => { - if (open && ref.current) { - ref.current.focus(); - } - }, [open]); - - function sendMessage() { - if (chatValue !== "") { - let nodeValidationErrors = validateNodes(reactFlowInstance); - if (nodeValidationErrors.length === 0) { - setLockChat(true); - let message = chatValue; - setChatValue(""); - addChatHistory(message, true); - sendAll({ - ...reactFlowInstance.toObject(), - message, - chatHistory, - name: flow.name, - description: flow.description, - }); - } else { - setErrorData({ - title: "Oops! Looks like you missed some required information:", - list: nodeValidationErrors, - }); - } - } else { - setErrorData({ - title: "Error sending message", - list: ["The message cannot be empty."], - }); - } - } - function clearChat() { - setChatHistory([]); - ws.current.send(JSON.stringify({ clear_history: true })); - if (lockChat) setLockChat(false); - } - - function setModalOpen(x: boolean) { - setOpen(x); - } - return ( - - - -
- - -
-
- - -
- - -
-
- {chatHistory.length > 0 ? ( - chatHistory.map((c, i) => ( - - )) - ) : ( -
- - πŸ‘‹{" "} - - Langflow Chat - - -
-
- - Start a conversation and click the agent’s thoughts{" "} - - - {" "} - to inspect the chaining process. - -
-
- )} -
-
-
-
- -
-
-
-
-
-
-
-
- ); -}