Merge branch 'chatUpdate' of https://github.com/logspace-ai/langflow into streaming

This commit is contained in:
Gabriel Almeida 2023-05-06 07:32:31 -03:00
commit b5a1fec33d
3 changed files with 355 additions and 341 deletions

View file

@ -5,7 +5,7 @@ import { PopUpContext } from "../../../contexts/popUpContext";
import { useContext } from "react"; import { useContext } from "react";
import ChatModal from "../../../modals/chatModal"; import ChatModal from "../../../modals/chatModal";
export default function ChatTrigger({open, setOpen,flow}){ export default function ChatTrigger({open, setOpen}){
const {openPopUp} = useContext(PopUpContext) const {openPopUp} = useContext(PopUpContext)
return(<Transition return(<Transition
show={!open} show={!open}

View file

@ -26,7 +26,7 @@ export default function Chat({ flow }: ChatType) {
return ( return (
<> <>
<ChatModal key={flow.id} flow={flow} open={open} setOpen={setOpen} /> <ChatModal key={flow.id} flow={flow} open={open} setOpen={setOpen} />
<ChatTrigger open={open} setOpen={setOpen} flow={flow} /> <ChatTrigger open={open} setOpen={setOpen} />
</> </>
); );
} }

View file

@ -1,13 +1,7 @@
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
import { import { ChatBubbleOvalLeftEllipsisIcon } from "@heroicons/react/24/outline";
ChatBubbleOvalLeftEllipsisIcon,
LockClosedIcon,
PaperAirplaneIcon,
} from "@heroicons/react/24/outline";
import { Fragment, useContext, useEffect, useRef, useState } from "react"; import { Fragment, useContext, useEffect, useRef, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext";
import { FlowType, NodeType } from "../../types/flow"; import { FlowType, NodeType } from "../../types/flow";
import { TabsContext } from "../../contexts/tabsContext";
import { alertContext } from "../../contexts/alertContext"; import { alertContext } from "../../contexts/alertContext";
import { toNormalCase } from "../../utils"; import { toNormalCase } from "../../utils";
import { typesContext } from "../../contexts/typesContext"; import { typesContext } from "../../contexts/typesContext";
@ -32,8 +26,15 @@ export default function ChatModal({
const [chatHistory, setChatHistory] = useState<ChatMessageType[]>([]); const [chatHistory, setChatHistory] = useState<ChatMessageType[]>([]);
const { reactFlowInstance } = useContext(typesContext); const { reactFlowInstance } = useContext(typesContext);
const { setErrorData, setNoticeData } = useContext(alertContext); const { setErrorData, setNoticeData } = useContext(alertContext);
const [ws, setWs] = useState<WebSocket | null>(null); const ws = useRef<WebSocket | null>(null);
const [lockChat, setLockChat] = useState(false); const [lockChat, setLockChat] = useState(false);
const isOpen = useRef(open);
useEffect(() => {
isOpen.current = open;
}, [open]);
var isStream = false;
const addChatHistory = ( const addChatHistory = (
message: string, message: string,
isSend: boolean, isSend: boolean,
@ -53,29 +54,34 @@ export default function ChatModal({
}); });
}; };
function connectWS() { //add proper type signature for function
console.log("conectou");
try {
const urlWs =
process.env.NODE_ENV === "development"
? `ws://localhost:7860/chat/${flow.id}`
: `${window.location.protocol === "https:" ? "wss" : "ws"}://${
window.location.host
}/chat/${flow.id}`;
const newWs = new WebSocket(urlWs); function updateLastMessage({str,thought}:{str?: string, thought?: string}) {
newWs.onopen = () => { setChatHistory((old) => {
console.log("WebSocket connection established!"); let newChat = [...old];
}; if (str) {
newWs.onmessage = (event) => { newChat[newChat.length - 1].message =
try { newChat[newChat.length - 1].message + str;
}
if(thought){
newChat[newChat.length - 1].thought = thought
}
return newChat;
});
}
function handleOnClose(event: CloseEvent) {
if (isOpen.current) {
setLockChat(false); setLockChat(false);
const data = JSON.parse(event.data); setTimeout(() => {
console.log("Received data:", data); connectWS();
//get chat history }, 1000);
if (Array.isArray(data)) { }
console.log(data); }
function handleWsMessage(data: any) {
if (Array.isArray(data)) {
//set chat history
setChatHistory((_) => { setChatHistory((_) => {
let newChatHistory: ChatMessageType[] = []; let newChatHistory: ChatMessageType[] = [];
data.forEach( data.forEach(
@ -107,77 +113,98 @@ export default function ChatModal({
return newChatHistory; return newChatHistory;
}); });
} }
if (data.type === "start") {
console.log("start");
addChatHistory("", false);
isStream = true;
}
if (data.type === "end") { if (data.type === "end") {
if (data.files) { if(data.intermediate_steps){
addChatHistory( updateLastMessage({thought:data.intermediate_steps});
data.message,
false,
data.intermediate_steps,
data.files
);
} else {
addChatHistory(data.message, false, data.intermediate_steps);
} }
setLockChat(false);
isStream = false;
// if (data.files) {
// addChatHistory(
// data.message,
// false,
// data.intermediate_steps,
// data.files
// );
// } else {
// addChatHistory(data.message, false, data.intermediate_steps);
// }
} }
if (data.type == "file") { if (data.type === "file") {
console.log(data); console.log(data);
} }
} catch (error) { if (data.type === "stream" && isStream) {
if (event.data !== "Error: 1005") { updateLastMessage({str:data.message});
setErrorData({ title: event.data });
newWs.close();
connectWS();
} }
} }
function connectWS() {
try {
const urlWs =
process.env.NODE_ENV === "development"
? `ws://localhost:7860/chat/${flow.id}`
: `${window.location.protocol === "https:" ? "wss" : "ws"}://${
window.location.host
}/chat/${flow.id}`;
const newWs = new WebSocket(urlWs);
newWs.onopen = () => {
console.log("WebSocket connection established!");
}; };
newWs.onclose = (_) => { console.log(flow.id);
if (open) { newWs.onmessage = (event) => {
setLockChat(false); const data = JSON.parse(event.data);
setTimeout(() => { console.log("Received data:", data);
connectWS(); handleWsMessage(data);
}, 1000); //get chat history
} };
newWs.onclose = (event) => {
handleOnClose(event);
}; };
newWs.onerror = (ev) => { newWs.onerror = (ev) => {
console.log(ev, "error"); console.log(ev, "error");
setErrorData({
title: "There was an error on web connection, please: ",
list: [
"Refresh the page",
"Use a new flow tab",
"Check if the backend is up",
],
});
}; };
setWs(newWs); ws.current = newWs;
return newWs;
} catch { } catch {
setErrorData({ setErrorData({
title: "There was an error on web connection, please: ", title: "There was an error on web connection, please: ",
list: [ list: [
"refresh the page", "Refresh the page",
"use a new flow tab", "Use a new flow tab",
"check if the backend is up", "Check if the backend is up",
], ],
}); });
} }
} }
useEffect(() => { useEffect(() => {
if (ws && (ws.readyState === ws.CLOSED || ws.readyState === ws.CLOSING)) { connectWS();
let newWs = connectWS();
return () => { return () => {
console.log("trigger"); console.log("unmount");
newWs.close(); console.log(ws);
}; if (ws) {
ws.current.close();
} }
}, [lockChat]);
useEffect(() => {
let newWs = connectWS();
return () => {
console.log("trigger");
newWs.close();
}; };
}, []); }, []);
async function sendAll(data: sendAllProps) { async function sendAll(data: sendAllProps) {
try { try {
if (ws) { if (ws) {
ws.send(JSON.stringify(data)); ws.current.send(JSON.stringify(data));
} }
} catch (error) { } catch (error) {
setErrorData({ setErrorData({
@ -193,12 +220,6 @@ export default function ChatModal({
if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" }); if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" });
}, [chatHistory]); }, [chatHistory]);
useEffect(() => {
if (ws && ws.readyState === ws.CLOSED) {
setLockChat(false);
}
}, [lockChat]);
function validateNode(n: NodeType): Array<string> { function validateNode(n: NodeType): Array<string> {
if (!n.data?.node?.template || !Object.keys(n.data.node.template)) { if (!n.data?.node?.template || !Object.keys(n.data.node.template)) {
setNoticeData({ setNoticeData({
@ -255,7 +276,6 @@ export default function ChatModal({
let message = chatValue; let message = chatValue;
setChatValue(""); setChatValue("");
addChatHistory(message, true); addChatHistory(message, true);
sendAll({ sendAll({
...reactFlowInstance.toObject(), ...reactFlowInstance.toObject(),
message, message,
@ -278,20 +298,14 @@ export default function ChatModal({
} }
function clearChat() { function clearChat() {
setChatHistory([]); setChatHistory([]);
ws.send(JSON.stringify({ clear_history: true })); ws.current.send(JSON.stringify({ clear_history: true }));
} }
const { closePopUp } = useContext(PopUpContext);
function setModalOpen(x: boolean) { function setModalOpen(x: boolean) {
setOpen(x); setOpen(x);
if (x === false) {
setTimeout(() => {
closePopUp();
}, 300);
}
} }
return ( return (
<Transition.Root show={open} appear={true} as={Fragment}> <Transition.Root show={open} appear={open} as={Fragment}>
<Dialog <Dialog
as="div" as="div"
className="relative z-10" className="relative z-10"