From dbe3e156d7cae963e188820d5ce617987149138f Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 17 Apr 2023 22:24:28 -0300 Subject: [PATCH 01/74] showing examples name --- .../src/components/loadingComponent/index.tsx | 1 + src/frontend/src/controllers/API/index.ts | 21 +++- src/frontend/src/modals/importModal/index.tsx | 95 ++++++++++++++----- 3 files changed, 90 insertions(+), 27 deletions(-) diff --git a/src/frontend/src/components/loadingComponent/index.tsx b/src/frontend/src/components/loadingComponent/index.tsx index 668c1c5a8..6181fd7cc 100644 --- a/src/frontend/src/components/loadingComponent/index.tsx +++ b/src/frontend/src/components/loadingComponent/index.tsx @@ -10,6 +10,7 @@ export default function LoadingComponent({remSize}:LoadingComponentProps){ +

Loading... ) diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 8fa7ff527..490ec2837 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -1,6 +1,7 @@ import { PromptTypeAPI, errorsTypeAPI } from './../../types/api/index'; import { APIObjectType, sendAllProps } from '../../types/api/index'; import axios, { AxiosResponse } from "axios"; +import { FlowType } from '../../types/flow'; export async function getAll():Promise> { return await axios.get(`/all`); @@ -18,4 +19,22 @@ export async function checkCode(code:string):Promise>{ return await axios.post('/validate/prompt',{template}) -} \ No newline at end of file +} + +export async function getExamples(): Promise { + const url = 'https://api.github.com/repos/logspace-ai/langflow_examples/contents/examples'; + const response = await axios.get(url); + + const jsonFiles = response.data.filter((file: any) => { + return file.name.endsWith('.json'); + }); + + const contentsPromises = jsonFiles.map(async (file: any) => { + const contentResponse = await axios.get(file.download_url); + return contentResponse.data; + }); + + const contents = await Promise.all(contentsPromises); + + return contents; + } \ No newline at end of file diff --git a/src/frontend/src/modals/importModal/index.tsx b/src/frontend/src/modals/importModal/index.tsx index c471f3955..5ca65a030 100644 --- a/src/frontend/src/modals/importModal/index.tsx +++ b/src/frontend/src/modals/importModal/index.tsx @@ -3,19 +3,28 @@ import { XMarkIcon, ArrowDownTrayIcon, DocumentDuplicateIcon, - ComputerDesktopIcon, + ComputerDesktopIcon, ArrowUpTrayIcon, } from "@heroicons/react/24/outline"; import { Fragment, useContext, useRef, useState } from "react"; import { PopUpContext } from "../../contexts/popUpContext"; import { TabsContext } from "../../contexts/tabsContext"; import ButtonBox from "./buttonBox"; +import { getExamples } from "../../controllers/API"; +import { error } from "console"; +import { alertContext } from "../../contexts/alertContext"; +import LoadingComponent from "../../components/loadingComponent"; +import { FlowType } from "../../types/flow"; export default function ImportModal() { const [open, setOpen] = useState(true); + const { setErrorData } = useContext(alertContext); const { closePopUp } = useContext(PopUpContext); const ref = useRef(); - const {uploadFlow} = useContext(TabsContext) + const [showExamples, setShowExamples] = useState(false); + const [loadingExamples, setLoadingExamples] = useState(false); + const [examples, setExamples] = useState([]); + const { uploadFlow } = useContext(TabsContext); function setModalOpen(x: boolean) { setOpen(x); if (x === false) { @@ -24,6 +33,22 @@ export default function ImportModal() { }, 300); } } + + function handleExamples() { + setLoadingExamples(true); + getExamples() + .then((result) => { + setLoadingExamples(false); + setExamples(result); + }) + .catch((error) => + setErrorData({ + title: "there was an error loading examples, please try again", + list: [error.message], + }) + ); + } + return (
-
- - } - onClick={() => console.log("sdsds")} - textColor="text-slate-400" - title="Examples" - > - - } - onClick={() => {uploadFlow();setModalOpen(false)}} - textColor="text-blue-500" - title="Local file" - > -
+ {!showExamples && ( +
+ + } + onClick={() =>{ + setShowExamples(true); + handleExamples(); + }} + textColor="text-emerald-400" + title="Examples" + > + + } + onClick={() => { + uploadFlow(); + setModalOpen(false); + }} + textColor="text-blue-500" + title="Local file" + > +
+ )} + {showExamples && loadingExamples && ( +
+ +
+ )} + {showExamples && !loadingExamples && ( +
+ {examples.map((example, index) => { + return
{example.name}
; + })} +
+ )}
- From 1049275715ea21b1dce34990dd6ab60a92ec72e0 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 17 Apr 2023 23:18:45 -0300 Subject: [PATCH 02/74] set back button and high of the example element --- .../modals/importModal/buttonBox/index.tsx | 68 +++++++++++++++++-- src/frontend/src/modals/importModal/index.tsx | 59 +++++++++++++--- 2 files changed, 111 insertions(+), 16 deletions(-) diff --git a/src/frontend/src/modals/importModal/buttonBox/index.tsx b/src/frontend/src/modals/importModal/buttonBox/index.tsx index 3645a31b9..2bd124bd7 100644 --- a/src/frontend/src/modals/importModal/buttonBox/index.tsx +++ b/src/frontend/src/modals/importModal/buttonBox/index.tsx @@ -9,7 +9,8 @@ export default function ButtonBox({ icon, bgColor, textColor, - deactivate + deactivate, + size }: { onClick: () => void; title: string; @@ -18,27 +19,80 @@ export default function ButtonBox({ bgColor: string; textColor: string; deactivate?:boolean; + size:"small"|"medium"|"big"; }) { + let bigCircle:string; + let smallCircle:string; + let titleFontSize:string; + let descriptionFontSize:string; + let padding:string; + let marginTop:string; + let height:string; + let widht:string; + switch(size){ + case "small": + bigCircle="h-12 w-12"; + smallCircle ="h-8 w-8"; + titleFontSize="text-sm"; + descriptionFontSize="text-xs"; + padding="p-2"; + marginTop="mt-2"; + height="h-36"; + widht="w-28"; + break; + case "medium": + bigCircle="h-16 w-16"; + smallCircle ="h-12 w-12"; + titleFontSize="text-base"; + descriptionFontSize="text-sm"; + padding="p-4"; + marginTop="mt-3"; + height="h-44"; + widht="w-36"; + break; + case "big": + bigCircle="h-20 w-20"; + smallCircle ="h-16 w-16"; + titleFontSize="text-lg"; + descriptionFontSize="text-sm"; + padding="p-8"; + marginTop="mt-6"; + height="h-56"; + widht="w-44"; + break; + default: + bigCircle="h-20 w-20"; + smallCircle ="h-16 w-16"; + titleFontSize="text-lg"; + descriptionFontSize="text-sm"; + padding="p-8"; + marginTop="mt-6"; + height="h-56"; + widht="w-44"; + break; + } return ( + {showExamples && ( +
+ +
+ )}
@@ -110,16 +127,24 @@ export default function ImportModal() {
-
+
{!showExamples && (
} - onClick={() =>{ + onClick={() => { setShowExamples(true); handleExamples(); }} @@ -127,6 +152,7 @@ export default function ImportModal() { title="Examples" >
)} - {showExamples && !loadingExamples && ( -
- {examples.map((example, index) => { - return
{example.name}
; - })} -
- )} + {showExamples && + !loadingExamples && + examples.map((example, index) => { + return ( +
+ {" "} + + } + onClick={() => { + console.log("click"); + }} + textColor="text-slate-400" + title={example.name} + > +
+ ); + })}
From b3d5221ac202bdb59388cdbaaf9a28459ab018dc Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 18 Apr 2023 15:10:58 -0300 Subject: [PATCH 03/74] added new tailwind dependencies --- src/frontend/package-lock.json | 9 +++++++++ src/frontend/package.json | 3 ++- src/frontend/tailwind.config.js | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index df61239c5..35d27c5f4 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -14,6 +14,7 @@ "@heroicons/react": "^2.0.15", "@mui/material": "^5.11.9", "@tailwindcss/forms": "^0.5.3", + "@tailwindcss/line-clamp": "^0.4.4", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -3930,6 +3931,14 @@ "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" } }, + "node_modules/@tailwindcss/line-clamp": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.4.4.tgz", + "integrity": "sha512-5U6SY5z8N42VtrCrKlsTAA35gy2VSyYtHWCsg1H87NU1SXnEfekTVlrga9fzUDrrHcGi2Lb5KenUWb4lRQT5/g==", + "peerDependencies": { + "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" + } + }, "node_modules/@testing-library/dom": { "version": "8.20.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", diff --git a/src/frontend/package.json b/src/frontend/package.json index b669569e3..6eba117fc 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -9,6 +9,7 @@ "@heroicons/react": "^2.0.15", "@mui/material": "^5.11.9", "@tailwindcss/forms": "^0.5.3", + "@tailwindcss/line-clamp": "^0.4.4", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -60,4 +61,4 @@ ] }, "proxy": "http://backend:7860" -} \ No newline at end of file +} diff --git a/src/frontend/tailwind.config.js b/src/frontend/tailwind.config.js index 045f9992b..29ede0d1d 100644 --- a/src/frontend/tailwind.config.js +++ b/src/frontend/tailwind.config.js @@ -40,6 +40,6 @@ module.exports = { } } ) - }) + }),require('@tailwindcss/line-clamp') ], } From 4f72d54cb16dcfdc577d83b4173fc37051ebaa0f Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 18 Apr 2023 15:11:35 -0300 Subject: [PATCH 04/74] update types and improve tooltip component --- .../src/components/TooltipComponent/index.tsx | 5 +++-- src/frontend/src/types/components/index.ts | 14 ++++++++++++++ src/frontend/src/types/tabs/index.ts | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/components/TooltipComponent/index.tsx b/src/frontend/src/components/TooltipComponent/index.tsx index a111d047b..65c8d0e5f 100644 --- a/src/frontend/src/components/TooltipComponent/index.tsx +++ b/src/frontend/src/components/TooltipComponent/index.tsx @@ -1,6 +1,7 @@ import { ReactElement } from "react"; import { LightTooltip } from "../LightTooltipComponent"; +import { TooltipComponentType } from "../../types/components"; -export default function Tooltip({ children, title }:{children:ReactElement,title:string}) { - return {children}; +export default function Tooltip({ children, title,placement }:TooltipComponentType) { + return {children}; } diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index 9ba96d8c0..d7448083e 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -65,3 +65,17 @@ export type FloatComponentType = { disabled?: boolean; onChange: (value: string) => void; }; + +export type TooltipComponentType={children:ReactElement,title:string,placement?: + | 'bottom-end' + | 'bottom-start' + | 'bottom' + | 'left-end' + | 'left-start' + | 'left' + | 'right-end' + | 'right-start' + | 'right' + | 'top-end' + | 'top-start' + | 'top';} \ No newline at end of file diff --git a/src/frontend/src/types/tabs/index.ts b/src/frontend/src/types/tabs/index.ts index 625073fb3..6bb452b31 100644 --- a/src/frontend/src/types/tabs/index.ts +++ b/src/frontend/src/types/tabs/index.ts @@ -6,7 +6,7 @@ export type TabsContextType = { setTabIndex: (index: number) => void; flows: Array; removeFlow: (id: string) => void; - addFlow: (flowData?: any) => void; + addFlow: (flowData?: FlowType) => void; updateFlow: (newFlow: FlowType) => void; incrementNodeId: () => number; downloadFlow: (flow:FlowType) => void; From a923cdeccb71f23481819d490f2b82d83838a465 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 18 Apr 2023 15:12:10 -0300 Subject: [PATCH 05/74] improve example ui --- .../modals/importModal/buttonBox/index.tsx | 122 ++++++++++-------- src/frontend/src/modals/importModal/index.tsx | 7 +- 2 files changed, 75 insertions(+), 54 deletions(-) diff --git a/src/frontend/src/modals/importModal/buttonBox/index.tsx b/src/frontend/src/modals/importModal/buttonBox/index.tsx index 2bd124bd7..e9d59b751 100644 --- a/src/frontend/src/modals/importModal/buttonBox/index.tsx +++ b/src/frontend/src/modals/importModal/buttonBox/index.tsx @@ -1,6 +1,7 @@ import React, { ReactNode } from "react"; import { DocumentDuplicateIcon } from "@heroicons/react/solid"; import { classNames } from "../../../utils"; +import Tooltip from "../../../components/TooltipComponent"; export default function ButtonBox({ onClick, @@ -10,7 +11,7 @@ export default function ButtonBox({ bgColor, textColor, deactivate, - size + size, }: { onClick: () => void; title: string; @@ -18,57 +19,57 @@ export default function ButtonBox({ icon: ReactNode; bgColor: string; textColor: string; - deactivate?:boolean; - size:"small"|"medium"|"big"; + deactivate?: boolean; + size: "small" | "medium" | "big"; }) { - let bigCircle:string; - let smallCircle:string; - let titleFontSize:string; - let descriptionFontSize:string; - let padding:string; - let marginTop:string; - let height:string; - let widht:string; - switch(size){ + let bigCircle: string; + let smallCircle: string; + let titleFontSize: string; + let descriptionFontSize: string; + let padding: string; + let marginTop: string; + let height: string; + let widht: string; + switch (size) { case "small": - bigCircle="h-12 w-12"; - smallCircle ="h-8 w-8"; - titleFontSize="text-sm"; - descriptionFontSize="text-xs"; - padding="p-2"; - marginTop="mt-2"; - height="h-36"; - widht="w-28"; + bigCircle = "h-12 w-12"; + smallCircle = "h-8 w-8"; + titleFontSize = "text-sm"; + descriptionFontSize = "text-xs"; + padding = "p-2"; + marginTop = "mt-2"; + height = "h-36"; + widht = "w-28"; break; case "medium": - bigCircle="h-16 w-16"; - smallCircle ="h-12 w-12"; - titleFontSize="text-base"; - descriptionFontSize="text-sm"; - padding="p-4"; - marginTop="mt-3"; - height="h-44"; - widht="w-36"; + bigCircle = "h-16 w-16"; + smallCircle = "h-12 w-12"; + titleFontSize = "text-base"; + descriptionFontSize = "text-sm"; + padding = "p-4"; + marginTop = "mt-3"; + height = "h-44"; + widht = "w-36"; break; case "big": - bigCircle="h-20 w-20"; - smallCircle ="h-16 w-16"; - titleFontSize="text-lg"; - descriptionFontSize="text-sm"; - padding="p-8"; - marginTop="mt-6"; - height="h-56"; - widht="w-44"; + bigCircle = "h-20 w-20"; + smallCircle = "h-16 w-16"; + titleFontSize = "text-lg"; + descriptionFontSize = "text-sm"; + padding = "p-8"; + marginTop = "mt-6"; + height = "h-56"; + widht = "w-44"; break; default: - bigCircle="h-20 w-20"; - smallCircle ="h-16 w-16"; - titleFontSize="text-lg"; - descriptionFontSize="text-sm"; - padding="p-8"; - marginTop="mt-6"; - height="h-56"; - widht="w-44"; + bigCircle = "h-20 w-20"; + smallCircle = "h-16 w-16"; + titleFontSize = "text-lg"; + descriptionFontSize = "text-sm"; + padding = "p-8"; + marginTop = "mt-6"; + height = "h-56"; + widht = "w-44"; break; } return ( @@ -82,17 +83,36 @@ export default function ButtonBox({ )} >
-
-
-
- {icon} -
+
+
+
{icon}
-

{title}

+

+ {title} +

{title}
-
{deactivate? "Coming soon":description}
+ +
+ {deactivate ? "Coming soon" : description} +
+
diff --git a/src/frontend/src/modals/importModal/index.tsx b/src/frontend/src/modals/importModal/index.tsx index df39875c8..eec06add1 100644 --- a/src/frontend/src/modals/importModal/index.tsx +++ b/src/frontend/src/modals/importModal/index.tsx @@ -26,7 +26,7 @@ export default function ImportModal() { const [showExamples, setShowExamples] = useState(false); const [loadingExamples, setLoadingExamples] = useState(false); const [examples, setExamples] = useState([]); - const { uploadFlow } = useContext(TabsContext); + const { uploadFlow, addFlow } = useContext(TabsContext); function setModalOpen(x: boolean) { setOpen(x); if (x === false) { @@ -181,12 +181,13 @@ export default function ImportModal() { } onClick={() => { - console.log("click"); + addFlow(example) + setModalOpen(false) }} textColor="text-slate-400" title={example.name} From d28d73a37ee04448d6e9eb809068e6124f3931e4 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 18 Apr 2023 15:14:08 -0300 Subject: [PATCH 06/74] update add flow function to show import flow name --- src/frontend/src/contexts/tabsContext.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/contexts/tabsContext.tsx b/src/frontend/src/contexts/tabsContext.tsx index a11f0339d..97e62e5e2 100644 --- a/src/frontend/src/contexts/tabsContext.tsx +++ b/src/frontend/src/contexts/tabsContext.tsx @@ -144,7 +144,7 @@ export function TabsProvider({ children }: { children: ReactNode }) { // Create a new flow with a default name if no flow is provided. let newFlow: FlowType = { description, - name: "New Flow", + name: flow?.name??"New Flow", id: id.toString(), data, chat: flow ? flow.chat : [], From a583a1187624192c7b30f14efe3e61a8bed23e2f Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 18 Apr 2023 15:19:35 -0300 Subject: [PATCH 07/74] improve tabs behavior --- .../src/pages/FlowPage/components/tabComponent/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/pages/FlowPage/components/tabComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/tabComponent/index.tsx index ca21a0a43..a8d098c32 100644 --- a/src/frontend/src/pages/FlowPage/components/tabComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/tabComponent/index.tsx @@ -18,7 +18,8 @@ export default function TabComponent({ selected, flow, onClick }:{flow:FlowType, className="dark:text-white flex justify-between select-none truncate w-44 items-center px-4 my-1.5 border-x border-x-gray-300 dark:border-x-gray-600 -ml-px" onClick={onClick} > - {flow.name} + {flow.name} +
From 26db1f4e1bffcd91708e4f624b24fb2819150e5f Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Wed, 19 Apr 2023 22:11:18 -0300 Subject: [PATCH 15/74] added github logo with link to repo --- src/frontend/src/modals/importModal/index.tsx | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/src/frontend/src/modals/importModal/index.tsx b/src/frontend/src/modals/importModal/index.tsx index f185fb775..b2a65052c 100644 --- a/src/frontend/src/modals/importModal/index.tsx +++ b/src/frontend/src/modals/importModal/index.tsx @@ -51,7 +51,6 @@ export default function ImportModal() { ); } - return (
{showExamples && ( -
- -
+ <> +
+ +
+ + )}
@@ -181,13 +201,15 @@ export default function ImportModal() { } onClick={() => { - addFlow(example) - setModalOpen(false) + addFlow(example); + setModalOpen(false); }} textColor="text-emerald-400" title={example.name} From 53b8f48f969b1b88262c0a36cd2d7b9ef13c021d Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Wed, 19 Apr 2023 22:13:31 -0300 Subject: [PATCH 16/74] change text on examples page --- src/frontend/src/modals/importModal/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/modals/importModal/index.tsx b/src/frontend/src/modals/importModal/index.tsx index b2a65052c..3d22b0ee7 100644 --- a/src/frontend/src/modals/importModal/index.tsx +++ b/src/frontend/src/modals/importModal/index.tsx @@ -143,7 +143,7 @@ export default function ImportModal() { as="h3" className="text-lg font-medium dark:text-white leading-10 text-gray-900" > - Import from + {showExamples ?"Select an example":"Import from"}
From 0a630cd70daa593f74ea3dbe700058dc811d906d Mon Sep 17 00:00:00 2001 From: Gabriel Almeida Date: Wed, 19 Apr 2023 22:23:31 -0300 Subject: [PATCH 17/74] refactor(chat_manager.py): move process_graph function outside of ChatManager class test(websocket.py): add tests for websocket connection, chat history, and sending messages --- src/backend/langflow/api/chat_manager.py | 46 +++++++++++------ tests/test_websocket.py | 63 ++++++++++++++++-------- 2 files changed, 74 insertions(+), 35 deletions(-) diff --git a/src/backend/langflow/api/chat_manager.py b/src/backend/langflow/api/chat_manager.py index 384de4d12..7ca04abf7 100644 --- a/src/backend/langflow/api/chat_manager.py +++ b/src/backend/langflow/api/chat_manager.py @@ -41,13 +41,13 @@ class ChatManager: async def send_json(self, client_id: str, message: ChatMessage): websocket = self.active_connections[client_id] self.chat_history.add_message(client_id, message) - await websocket.send_json(message.dict()) + await websocket.send_json(json.dumps(message.dict())) async def process_message(self, client_id: str, payload: Dict): # Process the graph data and chat message chat_message = payload.pop("message", "") - chat_message = ChatMessage(sender="user", message=chat_message) + chat_message = ChatMessage(sender="you", message=chat_message) self.chat_history.add_message(client_id, chat_message) graph_data = payload @@ -57,22 +57,14 @@ class ChatManager: await self.send_json(client_id, start_resp) is_first_message = len(self.chat_history.get_history(client_id=client_id)) == 0 - langchain_object = load_or_build_langchain_object(graph_data, is_first_message) - logger.debug("Loaded langchain object") - - if langchain_object is None: - # Raise user facing error - raise ValueError( - "There was an error loading the langchain_object. Please, check all the nodes and try again." - ) - # Generate result and thought try: logger.debug("Generating result and thought") - result, intermediate_steps = await async_get_result_and_steps( - langchain_object, chat_message.message or "" + result, intermediate_steps = await process_graph( + graph_data=graph_data, + is_first_message=is_first_message, + chat_message=chat_message, ) - logger.debug("Generated result and intermediate_steps") except Exception as e: # Log stack trace logger.exception(e) @@ -105,3 +97,29 @@ class ChatManager: print(f"Error: {e}") finally: self.disconnect(client_id) + + +async def process_graph( + graph_data: Dict, is_first_message: bool, chat_message: ChatMessage +): + langchain_object = load_or_build_langchain_object(graph_data, is_first_message) + logger.debug("Loaded langchain object") + + if langchain_object is None: + # Raise user facing error + raise ValueError( + "There was an error loading the langchain_object. Please, check all the nodes and try again." + ) + + # Generate result and thought + try: + logger.debug("Generating result and thought") + result, intermediate_steps = await async_get_result_and_steps( + langchain_object, chat_message.message or "" + ) + logger.debug("Generated result and intermediate_steps") + return result, intermediate_steps + except Exception as e: + # Log stack trace + logger.exception(e) + raise e diff --git a/tests/test_websocket.py b/tests/test_websocket.py index 9ce20bc45..41405867f 100644 --- a/tests/test_websocket.py +++ b/tests/test_websocket.py @@ -1,30 +1,51 @@ import json +from unittest.mock import patch +from langflow.api.schemas import ChatMessage +from fastapi.testclient import TestClient -def test_websocket_connection(client): - with client.websocket_connect("/ws") as websocket: - assert websocket.client == client - assert websocket.url.path == "/ws" +def test_websocket_connection(client: TestClient): + with client.websocket_connect("/ws/test_client") as websocket: + assert websocket.scope["client"] == ["testclient", 50000] + assert websocket.scope["path"] == "/ws/test_client" -def test_chat_history(client): - chat_history = ["Test message 1", "Test message 2"] +def test_chat_history(client: TestClient): + chat_history = [] - with client.websocket_connect("/ws") as websocket: - received_history = websocket.receive_text() - received_history = json.loads(received_history) + # Mock the process_graph function to return a specific value + with patch("langflow.api.chat_manager.process_graph") as mock_process_graph: + mock_process_graph.return_value = ("Hello, I'm a mock response!", "") - assert received_history == chat_history + with client.websocket_connect("/ws/test_client") as websocket: + # First message should be the history + history = websocket.receive_json() + assert json.loads(history) == [] # Empty history + # Send a message + payload = {"message": "Hello"} + websocket.send_json(json.dumps(payload)) + # Receive the response from the server + response = websocket.receive_json() + assert json.loads(response) == { + "sender": "bot", + "message": None, + "intermediate_steps": "", + "type": "start", + "data": None, + "data_type": "", + } + # Send another message + payload = {"message": "How are you?"} + websocket.send_json(json.dumps(payload)) -def test_send_message(client, basic_graph): - with client.websocket_connect("/ws") as websocket: - # Send the JSON payload through the WebSocket connection - websocket.send_text(basic_graph) - - # Receive and parse the response from the server - response = websocket.receive_text() - response = json.loads(response) - - # Test that the response is as expected - assert response == "Your response message here" + # Receive the response from the server + response = websocket.receive_json() + assert json.loads(response) == { + "sender": "bot", + "message": "Hello, I'm a mock response!", + "intermediate_steps": "", + "type": "end", + "data": None, + "data_type": "", + } From 3da30cc5bffd0681d9ebb29e424287e45cad6798 Mon Sep 17 00:00:00 2001 From: Gabriel Almeida Date: Thu, 20 Apr 2023 11:09:11 -0300 Subject: [PATCH 18/74] refactor(cache): move cache functionality to a separate class feat(cache): add support for multiple clients and context manager to set client_id feat(cache): add observer pattern to notify on cache changes feat(cache): add async observer pattern to notify on cache changes in async functions feat(cache): add methods to add pandas DataFrame or Series and PIL Image to cache feat(cache): add method to get an object from cache by key feat(cache): add method to get the last added item in cache --- src/backend/langflow/cache/__init__.py | 2 +- src/backend/langflow/cache/base.py | 30 ------ src/backend/langflow/cache/manager.py | 126 +++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 31 deletions(-) create mode 100644 src/backend/langflow/cache/manager.py diff --git a/src/backend/langflow/cache/__init__.py b/src/backend/langflow/cache/__init__.py index f7aac380b..583d5ac6d 100644 --- a/src/backend/langflow/cache/__init__.py +++ b/src/backend/langflow/cache/__init__.py @@ -1 +1 @@ -from langflow.cache.base import add_pandas, add_image, get # noqa +from langflow.cache.manager import cache_manager # noqa diff --git a/src/backend/langflow/cache/base.py b/src/backend/langflow/cache/base.py index 9dd5c1780..ba250da6b 100644 --- a/src/backend/langflow/cache/base.py +++ b/src/backend/langflow/cache/base.py @@ -152,33 +152,3 @@ def load_cache(hash_val): with cache_path.open("rb") as cache_file: return dill.load(cache_file) return None - - -def add_pandas(name: str, obj: Any): - if isinstance(obj, (pd.DataFrame, pd.Series)): - CACHE[name] = {"obj": obj, "type": "pandas"} - else: - raise ValueError("Object is not a pandas DataFrame or Series") - - -def add_image(name: str, obj: Any): - if isinstance(obj, Image.Image): - CACHE[name] = {"obj": obj, "type": "image"} - else: - raise ValueError("Object is not a PIL Image") - - -def get(name: str): - return CACHE.get(name, {}).get("obj", None) - - -# get last added item -def get_last(): - obj_dict = list(CACHE.values())[-1] - if obj_dict["type"] == "pandas": - # return a csv string - return obj_dict["obj"].to_csv() - elif obj_dict["type"] == "image": - # return a base64 encoded string - return base64.b64encode(obj_dict["obj"].tobytes()).decode("utf-8") - return obj_dict["obj"] diff --git a/src/backend/langflow/cache/manager.py b/src/backend/langflow/cache/manager.py new file mode 100644 index 000000000..ba34a3a8d --- /dev/null +++ b/src/backend/langflow/cache/manager.py @@ -0,0 +1,126 @@ +from contextlib import contextmanager +from typing import Any, Awaitable, Callable, List +from PIL import Image +import pandas as pd + + +class Subject: + """Base class for implementing the observer pattern.""" + + def __init__(self): + self.observers: List[Callable[[], None]] = [] + + def attach(self, observer: Callable[[], None]): + """Attach an observer to the subject.""" + self.observers.append(observer) + + def detach(self, observer: Callable[[], None]): + """Detach an observer from the subject.""" + self.observers.remove(observer) + + def notify(self): + """Notify all observers about an event.""" + for observer in self.observers: + if observer is None: + continue + observer() + + +class AsyncSubject: + """Base class for implementing the async observer pattern.""" + + def __init__(self): + self.observers: List[Callable[[], Awaitable]] = [] + + def attach(self, observer: Callable[[], Awaitable]): + """Attach an observer to the subject.""" + self.observers.append(observer) + + def detach(self, observer: Callable[[], Awaitable]): + """Detach an observer from the subject.""" + self.observers.remove(observer) + + async def notify(self): + """Notify all observers about an event.""" + for observer in self.observers: + if observer is None: + continue + await observer() + + +class CacheManager(Subject): + """Manages cache for different clients and notifies observers on changes.""" + + def __init__(self): + super().__init__() + self.CACHE = {} + self.current_client_id = None + + @contextmanager + def set_client_id(self, client_id: str): + """ + Context manager to set the current client_id and associated cache. + + Args: + client_id (str): The client identifier. + """ + previous_client_id = self.current_client_id + self.current_client_id = client_id + self.current_cache = self.CACHE.setdefault(client_id, {}) + try: + yield + finally: + self.current_client_id = previous_client_id + self.current_cache = self.CACHE.get(self.current_client_id, {}) + + def add_pandas(self, name: str, obj: Any): + """ + Add a pandas DataFrame or Series to the current client's cache. + + Args: + name (str): The cache key. + obj (Any): The pandas DataFrame or Series object. + """ + if isinstance(obj, (pd.DataFrame, pd.Series)): + self.current_cache[name] = {"obj": obj, "type": "pandas"} + self.notify() + else: + raise ValueError("Object is not a pandas DataFrame or Series") + + def add_image(self, name: str, obj: Any): + """ + Add a PIL Image to the current client's cache. + + Args: + name (str): The cache key. + obj (Any): The PIL Image object. + """ + if isinstance(obj, Image.Image): + self.current_cache[name] = {"obj": obj, "type": "image"} + self.notify() + else: + raise ValueError("Object is not a PIL Image") + + def get(self, name: str): + """ + Get an object from the current client's cache. + + Args: + name (str): The cache key. + + Returns: + The cached object associated with the given cache key. + """ + return self.current_cache[name] + + def get_last(self): + """ + Get the last added item in the current client's cache. + + Returns: + The last added item in the cache. + """ + return list(self.current_cache.values())[-1] + + +cache_manager = CacheManager() From 5169c0bc27960b678961fa94fed066a648c8efa4 Mon Sep 17 00:00:00 2001 From: Gabriel Almeida Date: Thu, 20 Apr 2023 11:09:42 -0300 Subject: [PATCH 19/74] feat(chat_manager.py): add support for sending file responses fix(schemas.py): add validation for file response type and data type test(test_websocket.py): remove data and data_type fields from ChatResponse messages in tests --- src/backend/langflow/api/chat_manager.py | 69 +++++++++++++++++++++--- src/backend/langflow/api/schemas.py | 20 +++++-- tests/test_websocket.py | 4 -- 3 files changed, 77 insertions(+), 16 deletions(-) diff --git a/src/backend/langflow/api/chat_manager.py b/src/backend/langflow/api/chat_manager.py index 7ca04abf7..8dcaf05ac 100644 --- a/src/backend/langflow/api/chat_manager.py +++ b/src/backend/langflow/api/chat_manager.py @@ -1,22 +1,30 @@ +import asyncio +import base64 +from io import BytesIO from typing import Dict, List from collections import defaultdict from fastapi import WebSocket import json -from langflow.api.schemas import ChatMessage, ChatResponse +from langflow.api.schemas import ChatMessage, ChatResponse, FileResponse +from langflow.cache.manager import AsyncSubject from langflow.interface.run import ( async_get_result_and_steps, load_or_build_langchain_object, ) from langflow.utils.logger import logger +from langflow.cache import cache_manager +from PIL.Image import Image -class ChatHistory: +class ChatHistory(AsyncSubject): def __init__(self): + super().__init__() self.history: Dict[str, List[ChatMessage]] = defaultdict(list) - def add_message(self, client_id: str, message: ChatMessage): + async def add_message(self, client_id: str, message: ChatMessage): self.history[client_id].append(message) + await self.notify() def get_history(self, client_id: str) -> List[ChatMessage]: return self.history[client_id] @@ -26,6 +34,44 @@ class ChatManager: def __init__(self): self.active_connections: Dict[str, WebSocket] = {} self.chat_history = ChatHistory() + self.chat_history.attach(self.on_chat_history_update) + self.cache_manager = cache_manager + self.cache_manager.attach(self.update) + + async def on_chat_history_update(self): + """Send the last chat message to the client.""" + client_id = self.cache_manager.current_client_id + if client_id in self.active_connections: + chat_response = self.chat_history.get_history(client_id)[-1] + if chat_response.sender == "bot": + # Process FileResponse + if isinstance(chat_response, FileResponse): + # If data_type is pandas, convert to csv + if chat_response.data_type == "pandas": + chat_response.data = chat_response.data.to_csv() + elif chat_response.data_type == "image": + # Base64 encode the image + chat_response.data = pil_to_base64(chat_response.data) + + await self.send_json(client_id, chat_response) + + def update(self): + if self.cache_manager.current_client_id in self.active_connections: + self.last_cached_object_dict = self.cache_manager.get_last() + # Add a new ChatResponse with the data + chat_response = FileResponse( + sender="bot", + message=None, + type="file", + data=self.last_cached_object_dict["obj"], + data_type=self.last_cached_object_dict["type"], + ) + + asyncio.create_task( + self.chat_history.add_message( + self.cache_manager.current_client_id, chat_response + ) + ) async def connect(self, client_id: str, websocket: WebSocket): await websocket.accept() @@ -40,7 +86,6 @@ class ChatManager: async def send_json(self, client_id: str, message: ChatMessage): websocket = self.active_connections[client_id] - self.chat_history.add_message(client_id, message) await websocket.send_json(json.dumps(message.dict())) async def process_message(self, client_id: str, payload: Dict): @@ -48,13 +93,13 @@ class ChatManager: chat_message = payload.pop("message", "") chat_message = ChatMessage(sender="you", message=chat_message) - self.chat_history.add_message(client_id, chat_message) + await self.chat_history.add_message(client_id, chat_message) graph_data = payload start_resp = ChatResponse( sender="bot", message=None, type="start", intermediate_steps="" ) - await self.send_json(client_id, start_resp) + await self.chat_history.add_message(client_id, start_resp) is_first_message = len(self.chat_history.get_history(client_id=client_id)) == 0 # Generate result and thought @@ -80,7 +125,7 @@ class ChatManager: intermediate_steps=intermediate_steps or "", type="end", ) - await self.send_json(client_id, response) + await self.chat_history.add_message(client_id, response) async def handle_websocket(self, client_id: str, websocket: WebSocket): await self.connect(client_id, websocket) @@ -91,7 +136,8 @@ class ChatManager: while True: json_payload = await websocket.receive_json() payload = json.loads(json_payload) - await self.process_message(client_id, payload) + with self.cache_manager.set_client_id(client_id): + await self.process_message(client_id, payload) except Exception as e: # Handle any exceptions that might occur print(f"Error: {e}") @@ -123,3 +169,10 @@ async def process_graph( # Log stack trace logger.exception(e) raise e + + +def pil_to_base64(image: Image) -> str: + buffered = BytesIO() + image.save(buffered, format="PNG") + img_str = base64.b64encode(buffered.getvalue()) + return img_str.decode("utf-8") diff --git a/src/backend/langflow/api/schemas.py b/src/backend/langflow/api/schemas.py index fd9ef0816..1aefe5c8e 100644 --- a/src/backend/langflow/api/schemas.py +++ b/src/backend/langflow/api/schemas.py @@ -20,11 +20,23 @@ class ChatResponse(ChatMessage): intermediate_steps: str type: str - data: Any = None - data_type: str = "" @validator("type") def validate_message_type(cls, v): - if v not in ["start", "stream", "end", "error", "info"]: - raise ValueError("type must be start, stream, end, error or info") + if v not in ["start", "stream", "end", "error", "info", "file"]: + raise ValueError("type must be start, stream, end, error, info, or file") + return v + + +class FileResponse(ChatMessage): + """File response schema.""" + + data: Any + data_type: str + type: str = "file" + + @validator("data_type") + def validate_data_type(cls, v): + if v not in ["image", "csv"]: + raise ValueError("data_type must be image or csv") return v diff --git a/tests/test_websocket.py b/tests/test_websocket.py index 41405867f..74e147075 100644 --- a/tests/test_websocket.py +++ b/tests/test_websocket.py @@ -32,8 +32,6 @@ def test_chat_history(client: TestClient): "message": None, "intermediate_steps": "", "type": "start", - "data": None, - "data_type": "", } # Send another message payload = {"message": "How are you?"} @@ -46,6 +44,4 @@ def test_chat_history(client: TestClient): "message": "Hello, I'm a mock response!", "intermediate_steps": "", "type": "end", - "data": None, - "data_type": "", } From ebc1f6a0dfef42e389c0db01678cb569d6bad809 Mon Sep 17 00:00:00 2001 From: Gabriel Almeida Date: Sun, 23 Apr 2023 14:31:21 -0300 Subject: [PATCH 20/74] feat(api): add callback handler for streaming LLM responses Add a new file `callback.py` that contains a new class `StreamingLLMCallbackHandler` that inherits from `AsyncCallbackHandler`. This class handles streaming LLM responses. It has a constructor that takes a `websocket` parameter and sets it as an instance variable. It also has an `on_llm_new_token` method that takes a `token` parameter and sends a `ChatResponse` object to the `websocket` instance variable. Update `chat_manager.py` to import the new `StreamingLLMCallbackHandler` class. Add a new function `try_setting_streaming_options` that takes a `langchain_object` and a `websocket` parameter. This function checks if the `llm` attribute of the `langchain_object` is an instance of `OpenAI`, `ChatOpenAI`, `AzureOpenAI`, or `AzureChatOpenAI`. If it is, it sets the --- src/backend/langflow/api/callback.py | 18 ++++++++++++ src/backend/langflow/api/chat.py | 5 ++-- src/backend/langflow/api/chat_manager.py | 36 ++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 src/backend/langflow/api/callback.py diff --git a/src/backend/langflow/api/callback.py b/src/backend/langflow/api/callback.py new file mode 100644 index 000000000..47a8d945c --- /dev/null +++ b/src/backend/langflow/api/callback.py @@ -0,0 +1,18 @@ +from typing import Any +from langchain.callbacks.base import AsyncCallbackHandler + +from langflow.api.schemas import ChatResponse + + +# https://github.com/hwchase17/chat-langchain/blob/master/callback.py +class StreamingLLMCallbackHandler(AsyncCallbackHandler): + """Callback handler for streaming LLM responses.""" + + def __init__(self, websocket): + self.websocket = websocket + + async def on_llm_new_token(self, token: str, **kwargs: Any) -> None: + resp = ChatResponse( + sender="bot", message=token, type="stream", intermediate_steps="" + ) + await self.websocket.send_json(resp.dict()) diff --git a/src/backend/langflow/api/chat.py b/src/backend/langflow/api/chat.py index 11b861c77..b2da73d52 100644 --- a/src/backend/langflow/api/chat.py +++ b/src/backend/langflow/api/chat.py @@ -1,5 +1,4 @@ from fastapi import APIRouter, WebSocket -from uuid import uuid4 from langflow.api.chat_manager import ChatManager @@ -7,6 +6,8 @@ router = APIRouter() chat_manager = ChatManager() -@router.websocket("/ws/{client_id}") +@router.websocket("/chat/{client_id}") async def websocket_endpoint(client_id: str, websocket: WebSocket): await chat_manager.handle_websocket(client_id, websocket) + + diff --git a/src/backend/langflow/api/chat_manager.py b/src/backend/langflow/api/chat_manager.py index 8dcaf05ac..5ce7d2452 100644 --- a/src/backend/langflow/api/chat_manager.py +++ b/src/backend/langflow/api/chat_manager.py @@ -5,9 +5,12 @@ from typing import Dict, List from collections import defaultdict from fastapi import WebSocket import json +from langchain.llms import OpenAI, AzureOpenAI +from langchain.chat_models import ChatOpenAI, AzureChatOpenAI from langflow.api.schemas import ChatMessage, ChatResponse, FileResponse from langflow.cache.manager import AsyncSubject - +from langchain.callbacks.base import AsyncCallbackManager +from langflow.api.callback import StreamingLLMCallbackHandler from langflow.interface.run import ( async_get_result_and_steps, load_or_build_langchain_object, @@ -90,7 +93,6 @@ class ChatManager: async def process_message(self, client_id: str, payload: Dict): # Process the graph data and chat message - chat_message = payload.pop("message", "") chat_message = ChatMessage(sender="you", message=chat_message) await self.chat_history.add_message(client_id, chat_message) @@ -105,10 +107,12 @@ class ChatManager: # Generate result and thought try: logger.debug("Generating result and thought") + result, intermediate_steps = await process_graph( graph_data=graph_data, is_first_message=is_first_message, chat_message=chat_message, + websocket=self.active_connections[client_id], ) except Exception as e: # Log stack trace @@ -129,6 +133,7 @@ class ChatManager: async def handle_websocket(self, client_id: str, websocket: WebSocket): await self.connect(client_id, websocket) + try: chat_history = self.chat_history.get_history(client_id) await websocket.send_json(json.dumps(chat_history)) @@ -146,9 +151,13 @@ class ChatManager: async def process_graph( - graph_data: Dict, is_first_message: bool, chat_message: ChatMessage + graph_data: Dict, + is_first_message: bool, + chat_message: ChatMessage, + websocket: WebSocket, ): langchain_object = load_or_build_langchain_object(graph_data, is_first_message) + langchain_object = try_setting_streaming_options(langchain_object, websocket) logger.debug("Loaded langchain object") if langchain_object is None: @@ -171,6 +180,27 @@ async def process_graph( raise e +def try_setting_streaming_options(langchain_object, websocket): + # If the LLM type is OpenAI or ChatOpenAI, + # set streaming to True + # First we need to find the LLM + llm = None + if hasattr(langchain_object, "llm"): + llm = langchain_object.llm + elif hasattr(langchain_object, "llm_chain") and hasattr( + langchain_object.llm_chain, "llm" + ): + llm = langchain_object.llm_chain.llm + if isinstance(llm, (OpenAI, ChatOpenAI, AzureOpenAI, AzureChatOpenAI)): + llm.streaming = bool(hasattr(llm, "streaming")) + + if hasattr(langchain_object, "callback_manager"): + stream_handler = StreamingLLMCallbackHandler(websocket) + stream_manager = AsyncCallbackManager([stream_handler]) + langchain_object.callback_manager = stream_manager + return langchain_object + + def pil_to_base64(image: Image) -> str: buffered = BytesIO() image.save(buffered, format="PNG") From a15d605cc82f56e27e876f426210f873c84b892c Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 24 Apr 2023 19:03:20 -0300 Subject: [PATCH 21/74] update styles --- .../modals/importModal/buttonBox/index.tsx | 64 +++++++++---------- .../components/tabsManagerComponent/index.tsx | 8 +-- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/frontend/src/modals/importModal/buttonBox/index.tsx b/src/frontend/src/modals/importModal/buttonBox/index.tsx index e9d59b751..b0757cdae 100644 --- a/src/frontend/src/modals/importModal/buttonBox/index.tsx +++ b/src/frontend/src/modals/importModal/buttonBox/index.tsx @@ -39,7 +39,7 @@ export default function ButtonBox({ padding = "p-2"; marginTop = "mt-2"; height = "h-36"; - widht = "w-28"; + widht = "w-32"; break; case "medium": bigCircle = "h-16 w-16"; @@ -74,48 +74,48 @@ export default function ButtonBox({ } return ( ); } diff --git a/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx index 71c964cbe..6d7a4d844 100644 --- a/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx @@ -60,18 +60,18 @@ export default function TabsManagerComponent() { /> ) } - className="flex items-center gap-1 pr-2 border-gray-400 border-r text-sm text-gray-400 hover:text-gray-500" + className="flex items-center gap-1 pr-2 border-gray-400 border-r text-sm text-gray-600 hover:text-gray-500" > Import + + + ) +} \ No newline at end of file diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 11516f004..6393df55b 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -19,6 +19,7 @@ import { TabsContext } from "../../contexts/tabsContext"; import { ChatType } from "../../types/chat"; import ChatMessage from "./chatMessage"; import { NodeType } from "../../types/flow"; +import ChatTrigger from "./chatTrigger"; const _ = require("lodash"); @@ -258,34 +259,7 @@ export default function Chat({ flow, reactFlowInstance }: ChatType) { - -
-
- -
-
-
+ ); } diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx new file mode 100644 index 000000000..93e4ed3d4 --- /dev/null +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -0,0 +1,102 @@ +import { Dialog, Transition } from "@headlessui/react"; +import { XMarkIcon, ClipboardDocumentListIcon } from "@heroicons/react/24/outline"; +import { Fragment, useContext, useRef, useState } from "react"; +import { PopUpContext } from "../../contexts/popUpContext"; + +export default function TextAreaModal(){ + const [open, setOpen] = useState(true); + const { closePopUp } = useContext(PopUpContext); + const ref = useRef(); + function setModalOpen(x:boolean){ + setOpen(x); + if(x === false){ + setTimeout(() => {closePopUp()}, 300); + } + } + return ( + + + +
+ + +
+
+ + +
+ +
+
+
+
+
+
+ + Edit text + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ ) +} \ No newline at end of file From 8ed1ea92d41c442183a384e14db1e67ee673cbde Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 24 Apr 2023 20:03:05 -0300 Subject: [PATCH 23/74] clean chat area --- .../src/CustomNodes/GenericNode/index.tsx | 2 +- .../chatComponent/chatTrigger/index.tsx | 16 +- src/frontend/src/modals/chatModal/index.tsx | 157 +++++++----------- src/frontend/src/utils.ts | 2 +- 4 files changed, 72 insertions(+), 105 deletions(-) diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index ff13af901..f362ca8ff 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -38,7 +38,7 @@ export default function GenericNode({
diff --git a/src/frontend/src/components/chatComponent/chatTrigger/index.tsx b/src/frontend/src/components/chatComponent/chatTrigger/index.tsx index f1841caba..6c4bbadde 100644 --- a/src/frontend/src/components/chatComponent/chatTrigger/index.tsx +++ b/src/frontend/src/components/chatComponent/chatTrigger/index.tsx @@ -1,8 +1,12 @@ import { Transition } from "@headlessui/react"; -import { Bars3CenterLeftIcon } from "@heroicons/react/24/outline"; +import { Bars3CenterLeftIcon, ChatBubbleBottomCenterTextIcon } from "@heroicons/react/24/outline"; import { nodeColors } from "../../../utils"; +import { PopUpContext } from "../../../contexts/popUpContext"; +import { useContext } from "react"; +import ChatModal from "../../../modals/chatModal"; export default function ChatTrigger({open, setOpen}){ + const {openPopUp} = useContext(PopUpContext) return( -
-
+
+
diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx index 93e4ed3d4..6c232939f 100644 --- a/src/frontend/src/modals/chatModal/index.tsx +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -1,102 +1,65 @@ import { Dialog, Transition } from "@headlessui/react"; -import { XMarkIcon, ClipboardDocumentListIcon } from "@heroicons/react/24/outline"; +import { + XMarkIcon, + ClipboardDocumentListIcon, +} from "@heroicons/react/24/outline"; import { Fragment, useContext, useRef, useState } from "react"; import { PopUpContext } from "../../contexts/popUpContext"; -export default function TextAreaModal(){ - const [open, setOpen] = useState(true); - const { closePopUp } = useContext(PopUpContext); - const ref = useRef(); - function setModalOpen(x:boolean){ - setOpen(x); - if(x === false){ - setTimeout(() => {closePopUp()}, 300); - } - } - return ( - - - -
- +export default function ChatModal() { + const [open, setOpen] = useState(true); + const { closePopUp } = useContext(PopUpContext); + const ref = useRef(); + function setModalOpen(x: boolean) { + setOpen(x); + if (x === false) { + setTimeout(() => { + closePopUp(); + }, 300); + } + } + return ( + + + +
+ -
-
- - -
- -
-
-
-
-
-
- - Edit text - -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- ) -} \ No newline at end of file +
+
+ + +
+
+
+
input area
+
+
+
+
+
+
+
+ ); +} diff --git a/src/frontend/src/utils.ts b/src/frontend/src/utils.ts index 405d56297..608035ff8 100644 --- a/src/frontend/src/utils.ts +++ b/src/frontend/src/utils.ts @@ -78,7 +78,7 @@ export const nodeColors: {[char: string]: string} = { tools: "#FF3434", memories: "#F5B85A", advanced: "#000000", - chat: "#454173", + chat: "#198BF6", thought:"#272541", embeddings:"#42BAA7", documentloaders:"#7AAE42", From 2c0b846f5411ffb090ba3341d84b0a3b64be1607 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 24 Apr 2023 21:02:23 -0300 Subject: [PATCH 24/74] migrate chat logic to chat modal --- .../chatComponent/chatTrigger/index.tsx | 4 +- .../src/components/chatComponent/index.tsx | 2 +- src/frontend/src/contexts/index.tsx | 6 +- src/frontend/src/modals/chatModal/index.tsx | 215 +++++++++++++++++- 4 files changed, 214 insertions(+), 13 deletions(-) diff --git a/src/frontend/src/components/chatComponent/chatTrigger/index.tsx b/src/frontend/src/components/chatComponent/chatTrigger/index.tsx index 6c4bbadde..2f08ae92a 100644 --- a/src/frontend/src/components/chatComponent/chatTrigger/index.tsx +++ b/src/frontend/src/components/chatComponent/chatTrigger/index.tsx @@ -5,7 +5,7 @@ import { PopUpContext } from "../../../contexts/popUpContext"; import { useContext } from "react"; import ChatModal from "../../../modals/chatModal"; -export default function ChatTrigger({open, setOpen}){ +export default function ChatTrigger({open, setOpen,flow}){ const {openPopUp} = useContext(PopUpContext) return( { setOpen(true); - openPopUp() + openPopUp() }} >
diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 6393df55b..c18deb8de 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -259,7 +259,7 @@ export default function Chat({ flow, reactFlowInstance }: ChatType) {
- + ); } diff --git a/src/frontend/src/contexts/index.tsx b/src/frontend/src/contexts/index.tsx index 310606ea5..06c576b83 100644 --- a/src/frontend/src/contexts/index.tsx +++ b/src/frontend/src/contexts/index.tsx @@ -13,12 +13,10 @@ export default function ContextWrapper({ children }: { children: ReactNode }) { - - + - {children} + {children} - diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx index 6c232939f..5d3c8df81 100644 --- a/src/frontend/src/modals/chatModal/index.tsx +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -2,14 +2,177 @@ import { Dialog, Transition } from "@headlessui/react"; import { XMarkIcon, ClipboardDocumentListIcon, + LockClosedIcon, + PaperAirplaneIcon, } from "@heroicons/react/24/outline"; -import { Fragment, useContext, useRef, useState } from "react"; +import { Fragment, useContext, useEffect, useRef, useState } from "react"; import { PopUpContext } from "../../contexts/popUpContext"; +import { NodeType } from "../../types/flow"; +import { TabsContext } from "../../contexts/tabsContext"; +import { alertContext } from "../../contexts/alertContext"; +import { classNames, snakeToNormalCase } from "../../utils"; +import { sendAll } from "../../controllers/API"; +import { typesContext } from "../../contexts/typesContext"; +import ChatMessage from "../../components/chatComponent/chatMessage"; +const _ = require("lodash"); + +export default function ChatModal({ flow }) { + const { updateFlow, lockChat, setLockChat, flows, tabIndex } = + useContext(TabsContext); + const [saveChat, setSaveChat] = useState(false); + const [chatValue, setChatValue] = useState(""); + const [chatHistory, setChatHistory] = useState(flow.chat); + const { reactFlowInstance } = useContext(typesContext); + const { setErrorData, setNoticeData } = useContext(alertContext); + const addChatHistory = ( + message: string, + isSend: boolean, + thought?: string + ) => { + let tabsChange = false; + setChatHistory((old) => { + let newChat = _.cloneDeep(old); + if (JSON.stringify(flow.chat) !== JSON.stringify(old)) { + tabsChange = true; + return old; + } + if (thought) { + newChat.push({ message, isSend, thought }); + } else { + newChat.push({ message, isSend }); + } + return newChat; + }); + if (tabsChange) { + if (thought) { + updateFlow({ + ..._.cloneDeep(flow), + chat: [...flow.chat, { isSend, message, thought }], + }); + } else { + updateFlow({ + ..._.cloneDeep(flow), + chat: [...flow.chat, { isSend, message }], + }); + } + } + setSaveChat((chat) => !chat); + }; + useEffect(() => { + updateFlow({ ..._.cloneDeep(flow), chat: chatHistory }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [saveChat]); + useEffect(() => { + setChatHistory(flow.chat); + }, [flow]); + useEffect(() => { + if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" }); + }, [chatHistory]); + + function validateNode(n: NodeType): Array { + if (!n.data?.node?.template || !Object.keys(n.data.node.template)) { + setNoticeData({ + title: + "We've noticed a potential issue with a node in the flow. Please review it and, if necessary, submit a bug report with your exported flow file. Thank you for your help!", + }); + return []; + } + + const { + type, + node: { template }, + } = n.data; + + return Object.keys(template).reduce( + (errors: Array, t) => + errors.concat( + template[t].required && + template[t].show && + (!template[t].value || template[t].value === "") && + !reactFlowInstance + .getEdges() + .some( + (e) => + e.targetHandle.split("|")[1] === t && + e.targetHandle.split("|")[2] === n.id + ) + ? [ + `${type} is missing ${ + template.display_name + ? template.display_name + : snakeToNormalCase(template[t].name) + }.`, + ] + : [] + ), + [] as string[] + ); + } + + function validateNodes() { + console.log(reactFlowInstance) + return reactFlowInstance + .getNodes() + .flatMap((n: NodeType) => validateNode(n)); + } + + const ref = useRef(null); + + function sendMessage() { + if (chatValue !== "") { + let nodeValidationErrors = validateNodes(); + if (nodeValidationErrors.length === 0) { + setLockChat(true); + let message = chatValue; + setChatValue(""); + addChatHistory(message, true); + + sendAll({ + ...reactFlowInstance.toObject(), + message, + chatHistory, + name: flow.name, + description: flow.description, + }) + .then((r) => { + addChatHistory(r.data.result, false, r.data.thought); + setLockChat(false); + }) + .catch((error) => { + setErrorData({ + title: error.message ?? "Unknown Error", + list: [error.response.data.detail], + }); + setLockChat(false); + let lastMessage; + setChatHistory((chatHistory) => { + let newChat = chatHistory; + + lastMessage = newChat.pop().message; + return newChat; + }); + setChatValue(lastMessage); + }); + } 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([]); + updateFlow({ ..._.cloneDeep(flow), chat: [] }); + } -export default function ChatModal() { const [open, setOpen] = useState(true); const { closePopUp } = useContext(PopUpContext); - const ref = useRef(); function setModalOpen(x: boolean) { setOpen(x); if (x === false) { @@ -50,10 +213,50 @@ export default function ChatModal() { leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > -
-
+
+ {chatHistory.map((c, i) => ( + + ))} +
+
+
+
+ { + if (event.key === "Enter" && !lockChat) { + sendMessage(); + } + }} + type="text" + disabled={lockChat} + value={lockChat ? "Thinking..." : chatValue} + onChange={(e) => { + setChatValue(e.target.value); + }} + className={classNames( + lockChat + ? "bg-gray-500 text-white" + : "dark:bg-gray-700", + "form-input block w-full rounded-md border-gray-300 dark:border-gray-600 dark:text-white pr-10 sm:text-sm" + )} + placeholder={"Send a message..."} + /> +
+ +
-
input area
From 020e9c8461fe7131005849d5ce08e2eacc6196bc Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 24 Apr 2023 21:10:51 -0300 Subject: [PATCH 25/74] chat modal working --- src/frontend/src/modals/chatModal/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx index 5d3c8df81..99f1b4ee0 100644 --- a/src/frontend/src/modals/chatModal/index.tsx +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -213,7 +213,7 @@ export default function ChatModal({ flow }) { leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > -
+
{chatHistory.map((c, i) => ( ))} From 68870301f3df0df7e95fc9f643f8e850f938628e Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 24 Apr 2023 22:04:25 -0300 Subject: [PATCH 26/74] chat modal messages firts version finished --- .../modals/chatModal/chatMessage/index.tsx | 69 +++++++++++++++++++ src/frontend/src/modals/chatModal/index.tsx | 6 +- 2 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 src/frontend/src/modals/chatModal/chatMessage/index.tsx diff --git a/src/frontend/src/modals/chatModal/chatMessage/index.tsx b/src/frontend/src/modals/chatModal/chatMessage/index.tsx new file mode 100644 index 000000000..c29c1c12c --- /dev/null +++ b/src/frontend/src/modals/chatModal/chatMessage/index.tsx @@ -0,0 +1,69 @@ +import { + ChatBubbleLeftEllipsisIcon, + ChatBubbleOvalLeftEllipsisIcon, + PlusSmallIcon, +} from "@heroicons/react/24/outline"; +import { useState } from "react"; +import { ChatMessageType } from "../../../types/chat"; +import { classNames } from "../../../utils"; +import { UserIcon } from "@heroicons/react/24/solid"; +var Convert = require("ansi-to-html"); +var convert = new Convert({ newline: true }); + +export default function ChatMessage({ chat }: { chat: ChatMessageType }) { + const [hidden, setHidden] = useState(true); + return ( +
+
+ {!chat.isSend && 🦜} + {chat.isSend && } +
+ {!chat.isSend ? ( +
+
+ {hidden && chat.thought && chat.thought !== "" && ( +
setHidden((prev) => !prev)} + className="absolute -top-1 -left-2 cursor-pointer" + > + +
+ )} + {chat.thought && chat.thought !== "" && !hidden && ( +
setHidden((prev) => !prev)} + className=" text-start inline-block w-full pb-3 pt-3 px-5 cursor-pointer" + dangerouslySetInnerHTML={{ + __html: convert.toHtml(chat.thought), + }} + >
+ )} + {chat.thought && chat.thought !== "" && !hidden &&

} +
+ {chat.message} +
+
+
+ ) : ( +
+
+ {chat.message} +
+
+ )} +
+ ); +} diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx index 99f1b4ee0..b66acf612 100644 --- a/src/frontend/src/modals/chatModal/index.tsx +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -13,7 +13,7 @@ import { alertContext } from "../../contexts/alertContext"; import { classNames, snakeToNormalCase } from "../../utils"; import { sendAll } from "../../controllers/API"; import { typesContext } from "../../contexts/typesContext"; -import ChatMessage from "../../components/chatComponent/chatMessage"; +import ChatMessage from "./chatMessage"; const _ = require("lodash"); export default function ChatModal({ flow }) { @@ -212,8 +212,8 @@ export default function ChatModal({ flow }) { leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - -
+ +
{chatHistory.map((c, i) => ( ))} From 152525deccd13447c0936d4373f15970dc387596 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 24 Apr 2023 23:10:51 -0300 Subject: [PATCH 27/74] chat clear --- src/frontend/package-lock.json | 8 ++++---- src/frontend/package.json | 2 +- .../src/modals/chatModal/chatMessage/index.tsx | 5 +++-- src/frontend/src/modals/chatModal/index.tsx | 14 +++++++++++--- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index 35d27c5f4..8491f6873 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -31,7 +31,7 @@ "react-cookie": "^4.1.1", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.2", - "react-icons": "^4.7.1", + "react-icons": "^4.8.0", "react-laag": "^2.0.5", "react-router-dom": "^6.8.1", "react-scripts": "5.0.1", @@ -15040,9 +15040,9 @@ "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, "node_modules/react-icons": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.7.1.tgz", - "integrity": "sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.8.0.tgz", + "integrity": "sha512-N6+kOLcihDiAnj5Czu637waJqSnwlMNROzVZMhfX68V/9bu9qHaMIJC4UdozWoOk57gahFCNHwVvWzm0MTzRjg==", "peerDependencies": { "react": "*" } diff --git a/src/frontend/package.json b/src/frontend/package.json index 6eba117fc..feb11e814 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -26,7 +26,7 @@ "react-cookie": "^4.1.1", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.2", - "react-icons": "^4.7.1", + "react-icons": "^4.8.0", "react-laag": "^2.0.5", "react-router-dom": "^6.8.1", "react-scripts": "5.0.1", diff --git a/src/frontend/src/modals/chatModal/chatMessage/index.tsx b/src/frontend/src/modals/chatModal/chatMessage/index.tsx index c29c1c12c..0cec858a4 100644 --- a/src/frontend/src/modals/chatModal/chatMessage/index.tsx +++ b/src/frontend/src/modals/chatModal/chatMessage/index.tsx @@ -7,6 +7,7 @@ import { useState } from "react"; import { ChatMessageType } from "../../../types/chat"; import { classNames } from "../../../utils"; import { UserIcon } from "@heroicons/react/24/solid"; +import {AiFillRobot} from "react-icons/ai" var Convert = require("ansi-to-html"); var convert = new Convert({ newline: true }); @@ -21,10 +22,10 @@ export default function ChatMessage({ chat }: { chat: ChatMessageType }) { >
- {!chat.isSend && 🦜} + {!chat.isSend && } {chat.isSend && }
{!chat.isSend ? ( diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx index b66acf612..56213b031 100644 --- a/src/frontend/src/modals/chatModal/index.tsx +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -14,6 +14,8 @@ import { classNames, snakeToNormalCase } from "../../utils"; import { sendAll } from "../../controllers/API"; import { typesContext } from "../../contexts/typesContext"; import ChatMessage from "./chatMessage"; +import { FaEraser } from "react-icons/fa"; + const _ = require("lodash"); export default function ChatModal({ flow }) { @@ -110,7 +112,7 @@ export default function ChatModal({ flow }) { } function validateNodes() { - console.log(reactFlowInstance) + console.log(reactFlowInstance); return reactFlowInstance .getNodes() .flatMap((n: NodeType) => validateNode(n)); @@ -198,7 +200,7 @@ export default function ChatModal({ flow }) { leaveFrom="opacity-100" leaveTo="opacity-0" > -
+
@@ -212,7 +214,13 @@ export default function ChatModal({ flow }) { leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - + +
+ +
{chatHistory.map((c, i) => ( From 7c166162731ad46a2ef8fad4bb5e5643ccc41484 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 24 Apr 2023 23:21:22 -0300 Subject: [PATCH 28/74] chat popUp not using popUp context --- .../chatComponent/chatTrigger/index.tsx | 1 - .../src/components/chatComponent/index.tsx | 240 +----------------- src/frontend/src/modals/chatModal/index.tsx | 5 +- 3 files changed, 6 insertions(+), 240 deletions(-) diff --git a/src/frontend/src/components/chatComponent/chatTrigger/index.tsx b/src/frontend/src/components/chatComponent/chatTrigger/index.tsx index 2f08ae92a..9d5f67e0c 100644 --- a/src/frontend/src/components/chatComponent/chatTrigger/index.tsx +++ b/src/frontend/src/components/chatComponent/chatTrigger/index.tsx @@ -22,7 +22,6 @@ export default function ChatTrigger({open, setOpen,flow}){ -
-
- {chatHistory.map((c, i) => ( - - ))} -
-
-
-
- { - if (event.key === "Enter" && !lockChat) { - sendMessage(); - } - }} - type="text" - disabled={lockChat} - value={lockChat ? "Thinking..." : chatValue} - onChange={(e) => { - setChatValue(e.target.value); - }} - className={classNames( - lockChat ? "bg-gray-500 text-white" : "dark:bg-gray-700", - "form-input block w-full rounded-md border-gray-300 dark:border-gray-600 dark:text-white pr-10 sm:text-sm" - )} - placeholder={"Send a message..."} - /> -
- -
-
-
-
-
- - + + ); } diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx index 56213b031..15bc2a89a 100644 --- a/src/frontend/src/modals/chatModal/index.tsx +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -1,7 +1,5 @@ import { Dialog, Transition } from "@headlessui/react"; import { - XMarkIcon, - ClipboardDocumentListIcon, LockClosedIcon, PaperAirplaneIcon, } from "@heroicons/react/24/outline"; @@ -18,7 +16,7 @@ import { FaEraser } from "react-icons/fa"; const _ = require("lodash"); -export default function ChatModal({ flow }) { +export default function ChatModal({ flow,open, setOpen }) { const { updateFlow, lockChat, setLockChat, flows, tabIndex } = useContext(TabsContext); const [saveChat, setSaveChat] = useState(false); @@ -173,7 +171,6 @@ export default function ChatModal({ flow }) { updateFlow({ ..._.cloneDeep(flow), chat: [] }); } - const [open, setOpen] = useState(true); const { closePopUp } = useContext(PopUpContext); function setModalOpen(x: boolean) { setOpen(x); From ce7e9d02543ed5434bb7a4de58cd83c88225a283 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 24 Apr 2023 23:31:42 -0300 Subject: [PATCH 29/74] shortcut on ctrl shift k --- .../src/components/chatComponent/index.tsx | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 99e663713..5997deebf 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -1,31 +1,31 @@ -import { Transition } from "@headlessui/react"; import { - Bars3CenterLeftIcon, - LockClosedIcon, - PaperAirplaneIcon, - XMarkIcon, -} from "@heroicons/react/24/outline"; -import { - MouseEventHandler, - useContext, useEffect, useRef, useState, } from "react"; -import { sendAll } from "../../controllers/API"; -import { alertContext } from "../../contexts/alertContext"; -import { classNames, nodeColors, snakeToNormalCase } from "../../utils"; -import { TabsContext } from "../../contexts/tabsContext"; + import { ChatType } from "../../types/chat"; -import ChatMessage from "./chatMessage"; -import { NodeType } from "../../types/flow"; import ChatTrigger from "./chatTrigger"; import ChatModal from "../../modals/chatModal"; const _ = require("lodash"); export default function Chat({ flow }: ChatType) { + const [open, setOpen] = useState(false); + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + console.log(event) + if (event.key === "K" && event.shiftKey && (event.metaKey||event.ctrlKey)) { + console.log("dfdsfds") + setOpen(oldState=>!oldState); + } + }; + document.addEventListener("keydown", handleKeyDown); + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, []); return ( <> From f8f62834646fe651a7fe067ec3525e825aa86c59 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 25 Apr 2023 15:29:02 -0300 Subject: [PATCH 30/74] websocket first implementation --- src/frontend/src/modals/chatModal/index.tsx | 45 ++++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx index 15bc2a89a..cb9397b46 100644 --- a/src/frontend/src/modals/chatModal/index.tsx +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -1,22 +1,19 @@ import { Dialog, Transition } from "@headlessui/react"; -import { - LockClosedIcon, - PaperAirplaneIcon, -} from "@heroicons/react/24/outline"; +import { LockClosedIcon, PaperAirplaneIcon } from "@heroicons/react/24/outline"; import { Fragment, useContext, useEffect, useRef, useState } from "react"; import { PopUpContext } from "../../contexts/popUpContext"; -import { NodeType } from "../../types/flow"; +import { FlowType, NodeType } from "../../types/flow"; import { TabsContext } from "../../contexts/tabsContext"; import { alertContext } from "../../contexts/alertContext"; import { classNames, snakeToNormalCase } from "../../utils"; -import { sendAll } from "../../controllers/API"; import { typesContext } from "../../contexts/typesContext"; import ChatMessage from "./chatMessage"; import { FaEraser } from "react-icons/fa"; +import { sendAllProps } from "../../types/api"; const _ = require("lodash"); -export default function ChatModal({ flow,open, setOpen }) { +export default function ChatModal({ flow, open, setOpen }:{open:boolean,setOpen:Function,flow:FlowType}) { const { updateFlow, lockChat, setLockChat, flows, tabIndex } = useContext(TabsContext); const [saveChat, setSaveChat] = useState(false); @@ -24,6 +21,7 @@ export default function ChatModal({ flow,open, setOpen }) { const [chatHistory, setChatHistory] = useState(flow.chat); const { reactFlowInstance } = useContext(typesContext); const { setErrorData, setNoticeData } = useContext(alertContext); + const [ws, setWs] = useState(null); const addChatHistory = ( message: string, isSend: boolean, @@ -58,6 +56,31 @@ export default function ChatModal({ flow,open, setOpen }) { } setSaveChat((chat) => !chat); }; + + useEffect(() => { + const newWs = new WebSocket(`/chat/${flow.id}`); + newWs.onopen = () => { + console.log('WebSocket connection established!'); + }; + newWs.onmessage = (event) => { + const data = JSON.parse(event.data); + console.log('Received data:', data); + // Do something with the data received from the WebSocket + }; + setWs(newWs); + + return () => { + newWs.close(); + }; + }, []); + + async function sendAll(data: sendAllProps) { + if (ws) { + ws.send(JSON.stringify(data)); + } + return {data:{result:"sdsdsad",thought:"dsdsad"}} + } + useEffect(() => { updateFlow({ ..._.cloneDeep(flow), chat: chatHistory }); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -213,9 +236,11 @@ export default function ChatModal({ flow,open, setOpen }) { >
-
From e4fdfdd6498ff252630d3305773465079d5fb767 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 25 Apr 2023 15:40:21 -0300 Subject: [PATCH 31/74] added new icon --- .../src/assets/Gooey Ring-5s-271px.svg | 40 +++++++++++++++++++ .../src/components/chatComponent/index.tsx | 2 - .../modals/chatModal/chatMessage/index.tsx | 4 +- src/frontend/src/modals/chatModal/index.tsx | 2 +- 4 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 src/frontend/src/assets/Gooey Ring-5s-271px.svg diff --git a/src/frontend/src/assets/Gooey Ring-5s-271px.svg b/src/frontend/src/assets/Gooey Ring-5s-271px.svg new file mode 100644 index 000000000..6c3433420 --- /dev/null +++ b/src/frontend/src/assets/Gooey Ring-5s-271px.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 5997deebf..0b251ee16 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -15,9 +15,7 @@ export default function Chat({ flow }: ChatType) { const [open, setOpen] = useState(false); useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { - console.log(event) if (event.key === "K" && event.shiftKey && (event.metaKey||event.ctrlKey)) { - console.log("dfdsfds") setOpen(oldState=>!oldState); } }; diff --git a/src/frontend/src/modals/chatModal/chatMessage/index.tsx b/src/frontend/src/modals/chatModal/chatMessage/index.tsx index 0cec858a4..d49d5244d 100644 --- a/src/frontend/src/modals/chatModal/chatMessage/index.tsx +++ b/src/frontend/src/modals/chatModal/chatMessage/index.tsx @@ -25,8 +25,8 @@ export default function ChatMessage({ chat }: { chat: ChatMessageType }) { "rounded-full w-8 h-8 flex items-center my-3 justify-center",chat.isSend?"bg-black":"bg-black" )} > - {!chat.isSend && } - {chat.isSend && } + {!chat.isSend && } + {chat.isSend && }
{!chat.isSend ? (
diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx index cb9397b46..c1a0645ad 100644 --- a/src/frontend/src/modals/chatModal/index.tsx +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -58,7 +58,7 @@ export default function ChatModal({ flow, open, setOpen }:{open:boolean,setOpen: }; useEffect(() => { - const newWs = new WebSocket(`/chat/${flow.id}`); + const newWs = new WebSocket(`ws://backend:7860/chat/${flow.id}`); newWs.onopen = () => { console.log('WebSocket connection established!'); }; From e1544aadae4a1b66c5414216760393d1fcb8b894 Mon Sep 17 00:00:00 2001 From: Gabriel Almeida Date: Tue, 25 Apr 2023 16:35:17 -0300 Subject: [PATCH 32/74] chore(pyproject.toml): add websockets dependency refactor(chat_manager.py): remove redundant json.dumps() and convert BaseModel to dict before sending to websocket --- poetry.lock | 144 +++++++++++------------ pyproject.toml | 1 + src/backend/langflow/api/chat_manager.py | 11 +- 3 files changed, 81 insertions(+), 75 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6616801b0..01f7dc4a6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4530,82 +4530,82 @@ files = [ [[package]] name = "websockets" -version = "11.0.1" +version = "11.0.2" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "websockets-11.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d30cc1a90bcbf9e22e1f667c1c5a7428e2d37362288b4ebfd5118eb0b11afa9"}, - {file = "websockets-11.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dc77283a7c7b2b24e00fe8c3c4f7cf36bba4f65125777e906aae4d58d06d0460"}, - {file = "websockets-11.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0929c2ebdf00cedda77bf77685693e38c269011236e7c62182fee5848c29a4fa"}, - {file = "websockets-11.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db234da3aff01e8483cf0015b75486c04d50dbf90004bd3e5b46d384e1bd6c9e"}, - {file = "websockets-11.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7fdfbed727ce6b4b5e6622d15a6efb2098b2d9e22ba4dc54b2e3ce80f982045"}, - {file = "websockets-11.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5f3d0d177b3db3d1d02cce7ba6c0063586499ac28afe0c992be74ffc40d9257"}, - {file = "websockets-11.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25ea5dbd3b00c56b034639dc6fe4d1dd095b8205bab1782d9a47cb020695fdf4"}, - {file = "websockets-11.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:dbeada3b8f1f6d9497840f761906c4236f912a42da4515520168bc7c525b52b0"}, - {file = "websockets-11.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:892959b627eedcdf98ac7022f9f71f050a59624b380b67862da10c32ea3c221a"}, - {file = "websockets-11.0.1-cp310-cp310-win32.whl", hash = "sha256:fc0a96a6828bfa6f1ccec62b54630bcdcc205d483f5a8806c0a8abb26101c54b"}, - {file = "websockets-11.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:3a88375b648a2c479532943cc19a018df1e5fcea85d5f31963c0b22794d1bdc1"}, - {file = "websockets-11.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3cf18bbd44b36749b7b66f047a30a40b799b8c0bd9a1b9173cba86a234b4306b"}, - {file = "websockets-11.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:deb0dd98ea4e76b833f0bfd7a6042b51115360d5dfcc7c1daa72dfc417b3327a"}, - {file = "websockets-11.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:45a85dc6b3ff76239379feb4355aadebc18d6e587c8deb866d11060755f4d3ea"}, - {file = "websockets-11.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d68bd2a3e9fff6f7043c0a711cb1ebba9f202c196a3943d0c885650cd0b6464"}, - {file = "websockets-11.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfd0b9b18d64c51e5cd322e16b5bf4fe490db65c9f7b18fd5382c824062ead7e"}, - {file = "websockets-11.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef0e6253c36e42f2637cfa3ff9b3903df60d05ec040c718999f6a0644ce1c497"}, - {file = "websockets-11.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:12180bc1d72c6a9247472c1dee9dfd7fc2e23786f25feee7204406972d8dab39"}, - {file = "websockets-11.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a797da96d4127e517a5cb0965cd03fd6ec21e02667c1258fa0579501537fbe5c"}, - {file = "websockets-11.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:07cc20655fb16aeef1a8f03236ba8671c61d332580b996b6396a5b7967ba4b3d"}, - {file = "websockets-11.0.1-cp311-cp311-win32.whl", hash = "sha256:a01c674e0efe0f14aec7e722ed0e0e272fa2f10e8ea8260837e1f4f5dc4b3e53"}, - {file = "websockets-11.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:2796f097841619acf053245f266a4f66cb27c040f0d9097e5f21301aab95ff43"}, - {file = "websockets-11.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:54d084756c50dfc8086dce97b945f210ca43950154e1e04a44a30c6e6a2bcbb1"}, - {file = "websockets-11.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fe2aed5963ca267c40a2d29b1ee4e8ab008ac8d5daa284fdda9275201b8a334"}, - {file = "websockets-11.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84e92dbac318a84fef722f38ca57acef19cbb89527aba5d420b96aa2656970ee"}, - {file = "websockets-11.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec4e87eb9916b481216b1fede7d8913be799915f5216a0c801867cbed8eeb903"}, - {file = "websockets-11.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d4e0990b6a04b07095c969969da659eecf9069cf8e7b8f49c8f5ee1bb50e3352"}, - {file = "websockets-11.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c90343fd0774749d23c1891dd8b3e9210f9afd30986673ce0f9d5857f5cb1562"}, - {file = "websockets-11.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ac042e8ba9d7f2618e84af27927fdce0f3e03528eb74f343977486c093868389"}, - {file = "websockets-11.0.1-cp37-cp37m-win32.whl", hash = "sha256:385c5391becb9b58e0a4f33345e12762fd857ccf9fbf6fee428669929ba45e4c"}, - {file = "websockets-11.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:aef1602db81096ce3d3847865128c8879635bdad7963fb2b7df290edb9e9150a"}, - {file = "websockets-11.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:52ba83ea132390e426f9a7b48848248a2dc0e7120ca8c65d5a8fc1efaa4eb51b"}, - {file = "websockets-11.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:007ed0d62f7e06eeb6e3a848b0d83b9fbd9e14674a59a61326845f27d20d7452"}, - {file = "websockets-11.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f888b9565ca1d1c25ab827d184f57f4772ffbfa6baf5710b873b01936cc335ee"}, - {file = "websockets-11.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db78535b791840a584c48cf3f4215eae38a7e2f43271ecd27ce4ba8a798beaaa"}, - {file = "websockets-11.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa1c23ed3a02732fba906ec337df65d4cc23f9f453635e1a803c285b59c7d987"}, - {file = "websockets-11.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e039f106d48d3c241f1943bccfb383bd38ec39900d6dcaad0c73cc5fe129f346"}, - {file = "websockets-11.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b0ed24a3aa4213029e100257e5e73c5f912e70ca35630081de94b7f9e2cf4a9b"}, - {file = "websockets-11.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5a3022f9291bf2d35ebf65929297d625e68effd3a5647b8eb8b89d51b09394c"}, - {file = "websockets-11.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1cb23597819f68ac6a6d133a002a1b3ef12a22850236b083242c93f81f206d5a"}, - {file = "websockets-11.0.1-cp38-cp38-win32.whl", hash = "sha256:349dd1fa56a30d530555988be98013688de67809f384671883f8bf8b8c9de984"}, - {file = "websockets-11.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:87ae582cf2319e45bc457a57232daded27a3c771263cab42fb8864214bbd74ea"}, - {file = "websockets-11.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a88815a0c6253ad1312ef186620832fb347706c177730efec34e3efe75e0e248"}, - {file = "websockets-11.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d5a6fa353b5ef36970c3bd1cd7cecbc08bb8f2f1a3d008b0691208cf34ebf5b0"}, - {file = "websockets-11.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5ffe6fc5e5fe9f2634cdc59b805e4ba1fcccf3a5622f5f36c3c7c287f606e283"}, - {file = "websockets-11.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b138f4bf8a64c344e12c76283dac279d11adab89ac62ae4a32ac8490d3c94832"}, - {file = "websockets-11.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aedd94422745da60672a901f53de1f50b16e85408b18672b9b210db4a776b5a6"}, - {file = "websockets-11.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4667d4e41fa37fa3d836b2603b8b40d6887fa4838496d48791036394f7ace39"}, - {file = "websockets-11.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:43e0de552be624e5c0323ff4fcc9f0b4a9a6dc6e0116b8aa2cbb6e0d3d2baf09"}, - {file = "websockets-11.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ceeef57b9aec8f27e523de4da73c518ece7721aefe7064f18aa28baabfe61b94"}, - {file = "websockets-11.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9d91279d57f6546eaf43671d1de50621e0578f13c2f17c96c458a72d170698d7"}, - {file = "websockets-11.0.1-cp39-cp39-win32.whl", hash = "sha256:29282631da3bfeb5db497e4d3d94d56ee36222fbebd0b51014e68a2e70736fb1"}, - {file = "websockets-11.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:e2654e94c705ce9b768441d8e3a387a84951ca1056efdc4a26a4a6ee723c01b6"}, - {file = "websockets-11.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:60a19d4ff5f451254f8623f6aa4169065f73a50ec7b59ab6b9dcddff4aa00267"}, - {file = "websockets-11.0.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a58e83f82098d062ae5d4cbe7073b8783999c284d6f079f2fefe87cd8957ac8"}, - {file = "websockets-11.0.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b91657b65355954e47f0df874917fa200426b3a7f4e68073326a8cfc2f6deef8"}, - {file = "websockets-11.0.1-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b8e1ee01eb5b8be5c8a69ae26b0820dbc198d092ad50b3451adc3cdd55d455"}, - {file = "websockets-11.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:5d8d5d17371ed9eb9f0e3a8d326bdf8172700164c2e705bc7f1905a719a189be"}, - {file = "websockets-11.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e53419201c6c1439148feb99de6b307651a88b8defd41348cc23bbe2a290de1d"}, - {file = "websockets-11.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:718d19c494637f28e651031b3df6a791b9e86e0097c65ed5e8ec49b400b1210e"}, - {file = "websockets-11.0.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7b2544eb3e7bc39ce59812371214cd97762080dab90c3afc857890039384753"}, - {file = "websockets-11.0.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec4a887d2236e3878c07033ad5566f6b4d5d954b85f92a219519a1745d0c93e9"}, - {file = "websockets-11.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ae59a9f0a77ecb0cbdedea7d206a547ff136e8bfbc7d2d98772fb02d398797bb"}, - {file = "websockets-11.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ef35cef161f76031f833146f895e7e302196e01c704c00d269c04d8e18f3ac37"}, - {file = "websockets-11.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79b6548e57ab18f071b9bfe3ffe02af7184dd899bc674e2817d8fe7e9e7489ec"}, - {file = "websockets-11.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8d9793f3fb0da16232503df14411dabafed5a81fc9077dc430cfc6f60e71179"}, - {file = "websockets-11.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42aa05e890fcf1faed8e535c088a1f0f27675827cbacf62d3024eb1e6d4c9e0c"}, - {file = "websockets-11.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5d4f4b341100d313b08149d7031eb6d12738ac758b0c90d2f9be8675f401b019"}, - {file = "websockets-11.0.1-py3-none-any.whl", hash = "sha256:85b4127f7da332feb932eee833c70e5e1670469e8c9de7ef3874aa2a91a6fbb2"}, - {file = "websockets-11.0.1.tar.gz", hash = "sha256:369410925b240b30ef1c1deadbd6331e9cd865ad0b8966bf31e276cc8e0da159"}, + {file = "websockets-11.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:580cc95c58118f8c39106be71e24d0b7e1ad11a155f40a2ee687f99b3e5e432e"}, + {file = "websockets-11.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:143782041e95b63083b02107f31cda999f392903ae331de1307441f3a4557d51"}, + {file = "websockets-11.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8df63dcd955eb6b2e371d95aacf8b7c535e482192cff1b6ce927d8f43fb4f552"}, + {file = "websockets-11.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9b2dced5cbbc5094678cc1ec62160f7b0fe4defd601cd28a36fde7ee71bbb5"}, + {file = "websockets-11.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0eeeea3b01c97fd3b5049a46c908823f68b59bf0e18d79b231d8d6764bc81ee"}, + {file = "websockets-11.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:502683c5dedfc94b9f0f6790efb26aa0591526e8403ad443dce922cd6c0ec83b"}, + {file = "websockets-11.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d3cc3e48b6c9f7df8c3798004b9c4b92abca09eeea5e1b0a39698f05b7a33b9d"}, + {file = "websockets-11.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:808b8a33c961bbd6d33c55908f7c137569b09ea7dd024bce969969aa04ecf07c"}, + {file = "websockets-11.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:34a6f8996964ccaa40da42ee36aa1572adcb1e213665e24aa2f1037da6080909"}, + {file = "websockets-11.0.2-cp310-cp310-win32.whl", hash = "sha256:8f24cd758cbe1607a91b720537685b64e4d39415649cac9177cd1257317cf30c"}, + {file = "websockets-11.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:3b87cd302f08ea9e74fdc080470eddbed1e165113c1823fb3ee6328bc40ca1d3"}, + {file = "websockets-11.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3565a8f8c7bdde7c29ebe46146bd191290413ee6f8e94cf350609720c075b0a1"}, + {file = "websockets-11.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f97e03d4d5a4f0dca739ea274be9092822f7430b77d25aa02da6775e490f6846"}, + {file = "websockets-11.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8f392587eb2767afa8a34e909f2fec779f90b630622adc95d8b5e26ea8823cb8"}, + {file = "websockets-11.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7742cd4524622cc7aa71734b51294644492a961243c4fe67874971c4d3045982"}, + {file = "websockets-11.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46dda4bc2030c335abe192b94e98686615f9274f6b56f32f2dd661fb303d9d12"}, + {file = "websockets-11.0.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6b2bfa1d884c254b841b0ff79373b6b80779088df6704f034858e4d705a4802"}, + {file = "websockets-11.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1df2413266bf48430ef2a752c49b93086c6bf192d708e4a9920544c74cd2baa6"}, + {file = "websockets-11.0.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf45d273202b0c1cec0f03a7972c655b93611f2e996669667414557230a87b88"}, + {file = "websockets-11.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a09cce3dacb6ad638fdfa3154d9e54a98efe7c8f68f000e55ca9c716496ca67"}, + {file = "websockets-11.0.2-cp311-cp311-win32.whl", hash = "sha256:2174a75d579d811279855df5824676d851a69f52852edb0e7551e0eeac6f59a4"}, + {file = "websockets-11.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:c78ca3037a954a4209b9f900e0eabbc471fb4ebe96914016281df2c974a93e3e"}, + {file = "websockets-11.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2100b02d1aaf66dc48ff1b2a72f34f6ebc575a02bc0350cc8e9fbb35940166"}, + {file = "websockets-11.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dca9708eea9f9ed300394d4775beb2667288e998eb6f542cdb6c02027430c599"}, + {file = "websockets-11.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:320ddceefd2364d4afe6576195201a3632a6f2e6d207b0c01333e965b22dbc84"}, + {file = "websockets-11.0.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2a573c8d71b7af937852b61e7ccb37151d719974146b5dc734aad350ef55a02"}, + {file = "websockets-11.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:13bd5bebcd16a4b5e403061b8b9dcc5c77e7a71e3c57e072d8dff23e33f70fba"}, + {file = "websockets-11.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:95c09427c1c57206fe04277bf871b396476d5a8857fa1b99703283ee497c7a5d"}, + {file = "websockets-11.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2eb042734e710d39e9bc58deab23a65bd2750e161436101488f8af92f183c239"}, + {file = "websockets-11.0.2-cp37-cp37m-win32.whl", hash = "sha256:5875f623a10b9ba154cb61967f940ab469039f0b5e61c80dd153a65f024d9fb7"}, + {file = "websockets-11.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:634239bc844131863762865b75211a913c536817c0da27f691400d49d256df1d"}, + {file = "websockets-11.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3178d965ec204773ab67985a09f5696ca6c3869afeed0bb51703ea404a24e975"}, + {file = "websockets-11.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:955fcdb304833df2e172ce2492b7b47b4aab5dcc035a10e093d911a1916f2c87"}, + {file = "websockets-11.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb46d2c7631b2e6f10f7c8bac7854f7c5e5288f024f1c137d4633c79ead1e3c0"}, + {file = "websockets-11.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25aae96c1060e85836552a113495db6d857400288161299d77b7b20f2ac569f2"}, + {file = "websockets-11.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2abeeae63154b7f63d9f764685b2d299e9141171b8b896688bd8baec6b3e2303"}, + {file = "websockets-11.0.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:daa1e8ea47507555ed7a34f8b49398d33dff5b8548eae3de1dc0ef0607273a33"}, + {file = "websockets-11.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:954eb789c960fa5daaed3cfe336abc066941a5d456ff6be8f0e03dd89886bb4c"}, + {file = "websockets-11.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3ffe251a31f37e65b9b9aca5d2d67fd091c234e530f13d9dce4a67959d5a3fba"}, + {file = "websockets-11.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:adf6385f677ed2e0b021845b36f55c43f171dab3a9ee0ace94da67302f1bc364"}, + {file = "websockets-11.0.2-cp38-cp38-win32.whl", hash = "sha256:aa7b33c1fb2f7b7b9820f93a5d61ffd47f5a91711bc5fa4583bbe0c0601ec0b2"}, + {file = "websockets-11.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:220d5b93764dd70d7617f1663da64256df7e7ea31fc66bc52c0e3750ee134ae3"}, + {file = "websockets-11.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fb4480556825e4e6bf2eebdbeb130d9474c62705100c90e59f2f56459ddab42"}, + {file = "websockets-11.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec00401846569aaf018700249996143f567d50050c5b7b650148989f956547af"}, + {file = "websockets-11.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87c69f50281126dcdaccd64d951fb57fbce272578d24efc59bce72cf264725d0"}, + {file = "websockets-11.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:232b6ba974f5d09b1b747ac232f3a3d8f86de401d7b565e837cc86988edf37ac"}, + {file = "websockets-11.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:392d409178db1e46d1055e51cc850136d302434e12d412a555e5291ab810f622"}, + {file = "websockets-11.0.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4fe2442091ff71dee0769a10449420fd5d3b606c590f78dd2b97d94b7455640"}, + {file = "websockets-11.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ede13a6998ba2568b21825809d96e69a38dc43184bdeebbde3699c8baa21d015"}, + {file = "websockets-11.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4c54086b2d2aec3c3cb887ad97e9c02c6be9f1d48381c7419a4aa932d31661e4"}, + {file = "websockets-11.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e37a76ccd483a6457580077d43bc3dfe1fd784ecb2151fcb9d1c73f424deaeba"}, + {file = "websockets-11.0.2-cp39-cp39-win32.whl", hash = "sha256:d1881518b488a920434a271a6e8a5c9481a67c4f6352ebbdd249b789c0467ddc"}, + {file = "websockets-11.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:25e265686ea385f22a00cc2b719b880797cd1bb53b46dbde969e554fb458bfde"}, + {file = "websockets-11.0.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ce69f5c742eefd039dce8622e99d811ef2135b69d10f9aa79fbf2fdcc1e56cd7"}, + {file = "websockets-11.0.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b985ba2b9e972cf99ddffc07df1a314b893095f62c75bc7c5354a9c4647c6503"}, + {file = "websockets-11.0.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b52def56d2a26e0e9c464f90cadb7e628e04f67b0ff3a76a4d9a18dfc35e3dd"}, + {file = "websockets-11.0.2-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70a438ef2a22a581d65ad7648e949d4ccd20e3c8ed7a90bbc46df4e60320891"}, + {file = "websockets-11.0.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:752fbf420c71416fb1472fec1b4cb8631c1aa2be7149e0a5ba7e5771d75d2bb9"}, + {file = "websockets-11.0.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dd906b0cdc417ea7a5f13bb3c6ca3b5fd563338dc596996cb0fdd7872d691c0a"}, + {file = "websockets-11.0.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e79065ff6549dd3c765e7916067e12a9c91df2affea0ac51bcd302aaf7ad207"}, + {file = "websockets-11.0.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46388a050d9e40316e58a3f0838c63caacb72f94129eb621a659a6e49bad27ce"}, + {file = "websockets-11.0.2-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c7de298371d913824f71b30f7685bb07ad13969c79679cca5b1f7f94fec012f"}, + {file = "websockets-11.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6d872c972c87c393e6a49c1afbdc596432df8c06d0ff7cd05aa18e885e7cfb7c"}, + {file = "websockets-11.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b444366b605d2885f0034dd889faf91b4b47668dd125591e2c64bfde611ac7e1"}, + {file = "websockets-11.0.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b967a4849db6b567dec3f7dd5d97b15ce653e3497b8ce0814e470d5e074750"}, + {file = "websockets-11.0.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2acdc82099999e44fa7bd8c886f03c70a22b1d53ae74252f389be30d64fd6004"}, + {file = "websockets-11.0.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:518ed6782d9916c5721ebd61bb7651d244178b74399028302c8617d0620af291"}, + {file = "websockets-11.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:58477b041099bb504e1a5ddd8aa86302ed1d5c6995bdd3db2b3084ef0135d277"}, + {file = "websockets-11.0.2-py3-none-any.whl", hash = "sha256:5004c087d17251938a52cce21b3dbdabeecbbe432ce3f5bbbf15d8692c36eac9"}, + {file = "websockets-11.0.2.tar.gz", hash = "sha256:b1a69701eb98ed83dd099de4a686dc892c413d974fa31602bc00aca7cb988ac9"}, ] [[package]] @@ -4801,4 +4801,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "f0a23552d8cbd3d38722a69698cf823cdd19a90b707538837da64a933f8d13b4" +content-hash = "1320f2d5466c6569ee0563cc81b28d8c8897c8f07b4e0912c231c6e4033a2bf8" diff --git a/pyproject.toml b/pyproject.toml index bc0753c5d..4136785ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,7 @@ fake-useragent = "^1.1.3" docstring-parser = "^0.15" psycopg2-binary = "^2.9.6" pyarrow = "^11.0.0" +websockets = "^11.0.2" [tool.poetry.group.dev.dependencies] black = "^23.1.0" diff --git a/src/backend/langflow/api/chat_manager.py b/src/backend/langflow/api/chat_manager.py index 5ce7d2452..bc9b2dc2d 100644 --- a/src/backend/langflow/api/chat_manager.py +++ b/src/backend/langflow/api/chat_manager.py @@ -89,7 +89,7 @@ class ChatManager: async def send_json(self, client_id: str, message: ChatMessage): websocket = self.active_connections[client_id] - await websocket.send_json(json.dumps(message.dict())) + await websocket.send_json(message.dict()) async def process_message(self, client_id: str, payload: Dict): # Process the graph data and chat message @@ -136,11 +136,16 @@ class ChatManager: try: chat_history = self.chat_history.get_history(client_id) - await websocket.send_json(json.dumps(chat_history)) + # iterate and make BaseModel into dict + chat_history = [chat.dict() for chat in chat_history] + await websocket.send_json(chat_history) while True: json_payload = await websocket.receive_json() - payload = json.loads(json_payload) + try: + payload = json.loads(json_payload) + except TypeError: + payload = json_payload with self.cache_manager.set_client_id(client_id): await self.process_message(client_id, payload) except Exception as e: From 4fd659703fa9cb9107cebb81505d154a902a358d Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 25 Apr 2023 16:35:44 -0300 Subject: [PATCH 33/74] socket small changes --- src/frontend/src/components/chatComponent/index.tsx | 2 +- .../src/modals/chatModal/chatMessage/index.tsx | 10 ++++------ src/frontend/src/modals/chatModal/index.tsx | 3 +-- src/frontend/src/svg.d.ts | 5 +++++ 4 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 src/frontend/src/svg.d.ts diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 0b251ee16..8108f3f36 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -26,7 +26,7 @@ export default function Chat({ flow }: ChatType) { }, []); return ( <> - + ); diff --git a/src/frontend/src/modals/chatModal/chatMessage/index.tsx b/src/frontend/src/modals/chatModal/chatMessage/index.tsx index d49d5244d..d960a149b 100644 --- a/src/frontend/src/modals/chatModal/chatMessage/index.tsx +++ b/src/frontend/src/modals/chatModal/chatMessage/index.tsx @@ -1,13 +1,11 @@ import { - ChatBubbleLeftEllipsisIcon, ChatBubbleOvalLeftEllipsisIcon, - PlusSmallIcon, } from "@heroicons/react/24/outline"; import { useState } from "react"; import { ChatMessageType } from "../../../types/chat"; import { classNames } from "../../../utils"; +import AiIcon from "../../../assets/Gooey Ring-5s-271px.svg" import { UserIcon } from "@heroicons/react/24/solid"; -import {AiFillRobot} from "react-icons/ai" var Convert = require("ansi-to-html"); var convert = new Convert({ newline: true }); @@ -22,11 +20,11 @@ export default function ChatMessage({ chat }: { chat: ChatMessageType }) { >
- {!chat.isSend && } - {chat.isSend && } + {!chat.isSend && } + {chat.isSend && }
{!chat.isSend ? (
diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx index c1a0645ad..f0783a744 100644 --- a/src/frontend/src/modals/chatModal/index.tsx +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -58,7 +58,7 @@ export default function ChatModal({ flow, open, setOpen }:{open:boolean,setOpen: }; useEffect(() => { - const newWs = new WebSocket(`ws://backend:7860/chat/${flow.id}`); + const newWs = new WebSocket(`ws://localhost:7860/chat/${flow.id}`); newWs.onopen = () => { console.log('WebSocket connection established!'); }; @@ -133,7 +133,6 @@ export default function ChatModal({ flow, open, setOpen }:{open:boolean,setOpen: } function validateNodes() { - console.log(reactFlowInstance); return reactFlowInstance .getNodes() .flatMap((n: NodeType) => validateNode(n)); diff --git a/src/frontend/src/svg.d.ts b/src/frontend/src/svg.d.ts new file mode 100644 index 000000000..a6e109e02 --- /dev/null +++ b/src/frontend/src/svg.d.ts @@ -0,0 +1,5 @@ +declare module '*.svg' { + const content: any; + export default content; + } + \ No newline at end of file From 9053eb81a0b1808dfd82008643c461d81708d4b1 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 25 Apr 2023 16:36:11 -0300 Subject: [PATCH 34/74] package-lock.json update --- package-lock.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..6d722a3cc --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "reactFlow", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} From 3c93e7308269a8982f16e8d7125b396955f900f1 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 25 Apr 2023 16:41:14 -0300 Subject: [PATCH 35/74] new poetry config for websocket --- poetry.lock | 161 ++++++++++++++++++++++++++----------------------- pyproject.toml | 1 + 2 files changed, 88 insertions(+), 74 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6616801b0..5419d50c1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand. +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "aiohttp" @@ -3837,7 +3837,7 @@ files = [ ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and platform_machine == \"aarch64\" or python_version >= \"3\" and platform_machine == \"ppc64le\" or python_version >= \"3\" and platform_machine == \"x86_64\" or python_version >= \"3\" and platform_machine == \"amd64\" or python_version >= \"3\" and platform_machine == \"AMD64\" or python_version >= \"3\" and platform_machine == \"win32\" or python_version >= \"3\" and platform_machine == \"WIN32\""} +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} [package.extras] aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] @@ -4016,6 +4016,10 @@ category = "main" optional = false python-versions = ">=3.8.0" files = [ + {file = "torch-2.0.0-1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:c9090bda7d2eeeecd74f51b721420dbeb44f838d4536cc1b284e879417e3064a"}, + {file = "torch-2.0.0-1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:bd42db2a48a20574d2c33489e120e9f32789c4dc13c514b0c44272972d14a2d7"}, + {file = "torch-2.0.0-1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8969aa8375bcbc0c2993e7ede0a7f889df9515f18b9b548433f412affed478d9"}, + {file = "torch-2.0.0-1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:ab2da16567cb55b67ae39e32d520d68ec736191d88ac79526ca5874754c32203"}, {file = "torch-2.0.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:7a9319a67294ef02459a19738bbfa8727bb5307b822dadd708bc2ccf6c901aca"}, {file = "torch-2.0.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:9f01fe1f6263f31bd04e1757946fd63ad531ae37f28bb2dbf66f5c826ee089f4"}, {file = "torch-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:527f4ae68df7b8301ee6b1158ca56350282ea633686537b30dbb5d7b4a52622a"}, @@ -4233,6 +4237,15 @@ category = "main" optional = false python-versions = "*" files = [ + {file = "triton-2.0.0-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38806ee9663f4b0f7cd64790e96c579374089e58f49aac4a6608121aa55e2505"}, + {file = "triton-2.0.0-1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:226941c7b8595219ddef59a1fdb821e8c744289a132415ddd584facedeb475b1"}, + {file = "triton-2.0.0-1-cp36-cp36m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4c9fc8c89874bc48eb7e7b2107a9b8d2c0bf139778637be5bfccb09191685cfd"}, + {file = "triton-2.0.0-1-cp37-cp37m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d2684b6a60b9f174f447f36f933e9a45f31db96cb723723ecd2dcfd1c57b778b"}, + {file = "triton-2.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9d4978298b74fcf59a75fe71e535c092b023088933b2f1df933ec32615e4beef"}, + {file = "triton-2.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:74f118c12b437fb2ca25e1a04759173b517582fcf4c7be11913316c764213656"}, + {file = "triton-2.0.0-1-pp37-pypy37_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9618815a8da1d9157514f08f855d9e9ff92e329cd81c0305003eb9ec25cc5add"}, + {file = "triton-2.0.0-1-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aca3303629cd3136375b82cb9921727f804e47ebee27b2677fef23005c3851a"}, + {file = "triton-2.0.0-1-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e3e13aa8b527c9b642e3a9defcc0fbd8ffbe1c80d8ac8c15a01692478dc64d8a"}, {file = "triton-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f05a7e64e4ca0565535e3d5d3405d7e49f9d308505bb7773d21fb26a4c008c2"}, {file = "triton-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb4b99ca3c6844066e516658541d876c28a5f6e3a852286bbc97ad57134827fd"}, {file = "triton-2.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47b4d70dc92fb40af553b4460492c31dc7d3a114a979ffb7a5cdedb7eb546c08"}, @@ -4530,82 +4543,82 @@ files = [ [[package]] name = "websockets" -version = "11.0.1" +version = "11.0.2" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "websockets-11.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d30cc1a90bcbf9e22e1f667c1c5a7428e2d37362288b4ebfd5118eb0b11afa9"}, - {file = "websockets-11.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dc77283a7c7b2b24e00fe8c3c4f7cf36bba4f65125777e906aae4d58d06d0460"}, - {file = "websockets-11.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0929c2ebdf00cedda77bf77685693e38c269011236e7c62182fee5848c29a4fa"}, - {file = "websockets-11.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db234da3aff01e8483cf0015b75486c04d50dbf90004bd3e5b46d384e1bd6c9e"}, - {file = "websockets-11.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7fdfbed727ce6b4b5e6622d15a6efb2098b2d9e22ba4dc54b2e3ce80f982045"}, - {file = "websockets-11.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5f3d0d177b3db3d1d02cce7ba6c0063586499ac28afe0c992be74ffc40d9257"}, - {file = "websockets-11.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25ea5dbd3b00c56b034639dc6fe4d1dd095b8205bab1782d9a47cb020695fdf4"}, - {file = "websockets-11.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:dbeada3b8f1f6d9497840f761906c4236f912a42da4515520168bc7c525b52b0"}, - {file = "websockets-11.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:892959b627eedcdf98ac7022f9f71f050a59624b380b67862da10c32ea3c221a"}, - {file = "websockets-11.0.1-cp310-cp310-win32.whl", hash = "sha256:fc0a96a6828bfa6f1ccec62b54630bcdcc205d483f5a8806c0a8abb26101c54b"}, - {file = "websockets-11.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:3a88375b648a2c479532943cc19a018df1e5fcea85d5f31963c0b22794d1bdc1"}, - {file = "websockets-11.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3cf18bbd44b36749b7b66f047a30a40b799b8c0bd9a1b9173cba86a234b4306b"}, - {file = "websockets-11.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:deb0dd98ea4e76b833f0bfd7a6042b51115360d5dfcc7c1daa72dfc417b3327a"}, - {file = "websockets-11.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:45a85dc6b3ff76239379feb4355aadebc18d6e587c8deb866d11060755f4d3ea"}, - {file = "websockets-11.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d68bd2a3e9fff6f7043c0a711cb1ebba9f202c196a3943d0c885650cd0b6464"}, - {file = "websockets-11.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfd0b9b18d64c51e5cd322e16b5bf4fe490db65c9f7b18fd5382c824062ead7e"}, - {file = "websockets-11.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef0e6253c36e42f2637cfa3ff9b3903df60d05ec040c718999f6a0644ce1c497"}, - {file = "websockets-11.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:12180bc1d72c6a9247472c1dee9dfd7fc2e23786f25feee7204406972d8dab39"}, - {file = "websockets-11.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a797da96d4127e517a5cb0965cd03fd6ec21e02667c1258fa0579501537fbe5c"}, - {file = "websockets-11.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:07cc20655fb16aeef1a8f03236ba8671c61d332580b996b6396a5b7967ba4b3d"}, - {file = "websockets-11.0.1-cp311-cp311-win32.whl", hash = "sha256:a01c674e0efe0f14aec7e722ed0e0e272fa2f10e8ea8260837e1f4f5dc4b3e53"}, - {file = "websockets-11.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:2796f097841619acf053245f266a4f66cb27c040f0d9097e5f21301aab95ff43"}, - {file = "websockets-11.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:54d084756c50dfc8086dce97b945f210ca43950154e1e04a44a30c6e6a2bcbb1"}, - {file = "websockets-11.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fe2aed5963ca267c40a2d29b1ee4e8ab008ac8d5daa284fdda9275201b8a334"}, - {file = "websockets-11.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84e92dbac318a84fef722f38ca57acef19cbb89527aba5d420b96aa2656970ee"}, - {file = "websockets-11.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec4e87eb9916b481216b1fede7d8913be799915f5216a0c801867cbed8eeb903"}, - {file = "websockets-11.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d4e0990b6a04b07095c969969da659eecf9069cf8e7b8f49c8f5ee1bb50e3352"}, - {file = "websockets-11.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c90343fd0774749d23c1891dd8b3e9210f9afd30986673ce0f9d5857f5cb1562"}, - {file = "websockets-11.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ac042e8ba9d7f2618e84af27927fdce0f3e03528eb74f343977486c093868389"}, - {file = "websockets-11.0.1-cp37-cp37m-win32.whl", hash = "sha256:385c5391becb9b58e0a4f33345e12762fd857ccf9fbf6fee428669929ba45e4c"}, - {file = "websockets-11.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:aef1602db81096ce3d3847865128c8879635bdad7963fb2b7df290edb9e9150a"}, - {file = "websockets-11.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:52ba83ea132390e426f9a7b48848248a2dc0e7120ca8c65d5a8fc1efaa4eb51b"}, - {file = "websockets-11.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:007ed0d62f7e06eeb6e3a848b0d83b9fbd9e14674a59a61326845f27d20d7452"}, - {file = "websockets-11.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f888b9565ca1d1c25ab827d184f57f4772ffbfa6baf5710b873b01936cc335ee"}, - {file = "websockets-11.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db78535b791840a584c48cf3f4215eae38a7e2f43271ecd27ce4ba8a798beaaa"}, - {file = "websockets-11.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa1c23ed3a02732fba906ec337df65d4cc23f9f453635e1a803c285b59c7d987"}, - {file = "websockets-11.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e039f106d48d3c241f1943bccfb383bd38ec39900d6dcaad0c73cc5fe129f346"}, - {file = "websockets-11.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b0ed24a3aa4213029e100257e5e73c5f912e70ca35630081de94b7f9e2cf4a9b"}, - {file = "websockets-11.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5a3022f9291bf2d35ebf65929297d625e68effd3a5647b8eb8b89d51b09394c"}, - {file = "websockets-11.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1cb23597819f68ac6a6d133a002a1b3ef12a22850236b083242c93f81f206d5a"}, - {file = "websockets-11.0.1-cp38-cp38-win32.whl", hash = "sha256:349dd1fa56a30d530555988be98013688de67809f384671883f8bf8b8c9de984"}, - {file = "websockets-11.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:87ae582cf2319e45bc457a57232daded27a3c771263cab42fb8864214bbd74ea"}, - {file = "websockets-11.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a88815a0c6253ad1312ef186620832fb347706c177730efec34e3efe75e0e248"}, - {file = "websockets-11.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d5a6fa353b5ef36970c3bd1cd7cecbc08bb8f2f1a3d008b0691208cf34ebf5b0"}, - {file = "websockets-11.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5ffe6fc5e5fe9f2634cdc59b805e4ba1fcccf3a5622f5f36c3c7c287f606e283"}, - {file = "websockets-11.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b138f4bf8a64c344e12c76283dac279d11adab89ac62ae4a32ac8490d3c94832"}, - {file = "websockets-11.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aedd94422745da60672a901f53de1f50b16e85408b18672b9b210db4a776b5a6"}, - {file = "websockets-11.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4667d4e41fa37fa3d836b2603b8b40d6887fa4838496d48791036394f7ace39"}, - {file = "websockets-11.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:43e0de552be624e5c0323ff4fcc9f0b4a9a6dc6e0116b8aa2cbb6e0d3d2baf09"}, - {file = "websockets-11.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ceeef57b9aec8f27e523de4da73c518ece7721aefe7064f18aa28baabfe61b94"}, - {file = "websockets-11.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9d91279d57f6546eaf43671d1de50621e0578f13c2f17c96c458a72d170698d7"}, - {file = "websockets-11.0.1-cp39-cp39-win32.whl", hash = "sha256:29282631da3bfeb5db497e4d3d94d56ee36222fbebd0b51014e68a2e70736fb1"}, - {file = "websockets-11.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:e2654e94c705ce9b768441d8e3a387a84951ca1056efdc4a26a4a6ee723c01b6"}, - {file = "websockets-11.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:60a19d4ff5f451254f8623f6aa4169065f73a50ec7b59ab6b9dcddff4aa00267"}, - {file = "websockets-11.0.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a58e83f82098d062ae5d4cbe7073b8783999c284d6f079f2fefe87cd8957ac8"}, - {file = "websockets-11.0.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b91657b65355954e47f0df874917fa200426b3a7f4e68073326a8cfc2f6deef8"}, - {file = "websockets-11.0.1-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b8e1ee01eb5b8be5c8a69ae26b0820dbc198d092ad50b3451adc3cdd55d455"}, - {file = "websockets-11.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:5d8d5d17371ed9eb9f0e3a8d326bdf8172700164c2e705bc7f1905a719a189be"}, - {file = "websockets-11.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e53419201c6c1439148feb99de6b307651a88b8defd41348cc23bbe2a290de1d"}, - {file = "websockets-11.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:718d19c494637f28e651031b3df6a791b9e86e0097c65ed5e8ec49b400b1210e"}, - {file = "websockets-11.0.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7b2544eb3e7bc39ce59812371214cd97762080dab90c3afc857890039384753"}, - {file = "websockets-11.0.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec4a887d2236e3878c07033ad5566f6b4d5d954b85f92a219519a1745d0c93e9"}, - {file = "websockets-11.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ae59a9f0a77ecb0cbdedea7d206a547ff136e8bfbc7d2d98772fb02d398797bb"}, - {file = "websockets-11.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ef35cef161f76031f833146f895e7e302196e01c704c00d269c04d8e18f3ac37"}, - {file = "websockets-11.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79b6548e57ab18f071b9bfe3ffe02af7184dd899bc674e2817d8fe7e9e7489ec"}, - {file = "websockets-11.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8d9793f3fb0da16232503df14411dabafed5a81fc9077dc430cfc6f60e71179"}, - {file = "websockets-11.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42aa05e890fcf1faed8e535c088a1f0f27675827cbacf62d3024eb1e6d4c9e0c"}, - {file = "websockets-11.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5d4f4b341100d313b08149d7031eb6d12738ac758b0c90d2f9be8675f401b019"}, - {file = "websockets-11.0.1-py3-none-any.whl", hash = "sha256:85b4127f7da332feb932eee833c70e5e1670469e8c9de7ef3874aa2a91a6fbb2"}, - {file = "websockets-11.0.1.tar.gz", hash = "sha256:369410925b240b30ef1c1deadbd6331e9cd865ad0b8966bf31e276cc8e0da159"}, + {file = "websockets-11.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:580cc95c58118f8c39106be71e24d0b7e1ad11a155f40a2ee687f99b3e5e432e"}, + {file = "websockets-11.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:143782041e95b63083b02107f31cda999f392903ae331de1307441f3a4557d51"}, + {file = "websockets-11.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8df63dcd955eb6b2e371d95aacf8b7c535e482192cff1b6ce927d8f43fb4f552"}, + {file = "websockets-11.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9b2dced5cbbc5094678cc1ec62160f7b0fe4defd601cd28a36fde7ee71bbb5"}, + {file = "websockets-11.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0eeeea3b01c97fd3b5049a46c908823f68b59bf0e18d79b231d8d6764bc81ee"}, + {file = "websockets-11.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:502683c5dedfc94b9f0f6790efb26aa0591526e8403ad443dce922cd6c0ec83b"}, + {file = "websockets-11.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d3cc3e48b6c9f7df8c3798004b9c4b92abca09eeea5e1b0a39698f05b7a33b9d"}, + {file = "websockets-11.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:808b8a33c961bbd6d33c55908f7c137569b09ea7dd024bce969969aa04ecf07c"}, + {file = "websockets-11.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:34a6f8996964ccaa40da42ee36aa1572adcb1e213665e24aa2f1037da6080909"}, + {file = "websockets-11.0.2-cp310-cp310-win32.whl", hash = "sha256:8f24cd758cbe1607a91b720537685b64e4d39415649cac9177cd1257317cf30c"}, + {file = "websockets-11.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:3b87cd302f08ea9e74fdc080470eddbed1e165113c1823fb3ee6328bc40ca1d3"}, + {file = "websockets-11.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3565a8f8c7bdde7c29ebe46146bd191290413ee6f8e94cf350609720c075b0a1"}, + {file = "websockets-11.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f97e03d4d5a4f0dca739ea274be9092822f7430b77d25aa02da6775e490f6846"}, + {file = "websockets-11.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8f392587eb2767afa8a34e909f2fec779f90b630622adc95d8b5e26ea8823cb8"}, + {file = "websockets-11.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7742cd4524622cc7aa71734b51294644492a961243c4fe67874971c4d3045982"}, + {file = "websockets-11.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46dda4bc2030c335abe192b94e98686615f9274f6b56f32f2dd661fb303d9d12"}, + {file = "websockets-11.0.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6b2bfa1d884c254b841b0ff79373b6b80779088df6704f034858e4d705a4802"}, + {file = "websockets-11.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1df2413266bf48430ef2a752c49b93086c6bf192d708e4a9920544c74cd2baa6"}, + {file = "websockets-11.0.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf45d273202b0c1cec0f03a7972c655b93611f2e996669667414557230a87b88"}, + {file = "websockets-11.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a09cce3dacb6ad638fdfa3154d9e54a98efe7c8f68f000e55ca9c716496ca67"}, + {file = "websockets-11.0.2-cp311-cp311-win32.whl", hash = "sha256:2174a75d579d811279855df5824676d851a69f52852edb0e7551e0eeac6f59a4"}, + {file = "websockets-11.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:c78ca3037a954a4209b9f900e0eabbc471fb4ebe96914016281df2c974a93e3e"}, + {file = "websockets-11.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2100b02d1aaf66dc48ff1b2a72f34f6ebc575a02bc0350cc8e9fbb35940166"}, + {file = "websockets-11.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dca9708eea9f9ed300394d4775beb2667288e998eb6f542cdb6c02027430c599"}, + {file = "websockets-11.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:320ddceefd2364d4afe6576195201a3632a6f2e6d207b0c01333e965b22dbc84"}, + {file = "websockets-11.0.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2a573c8d71b7af937852b61e7ccb37151d719974146b5dc734aad350ef55a02"}, + {file = "websockets-11.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:13bd5bebcd16a4b5e403061b8b9dcc5c77e7a71e3c57e072d8dff23e33f70fba"}, + {file = "websockets-11.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:95c09427c1c57206fe04277bf871b396476d5a8857fa1b99703283ee497c7a5d"}, + {file = "websockets-11.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2eb042734e710d39e9bc58deab23a65bd2750e161436101488f8af92f183c239"}, + {file = "websockets-11.0.2-cp37-cp37m-win32.whl", hash = "sha256:5875f623a10b9ba154cb61967f940ab469039f0b5e61c80dd153a65f024d9fb7"}, + {file = "websockets-11.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:634239bc844131863762865b75211a913c536817c0da27f691400d49d256df1d"}, + {file = "websockets-11.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3178d965ec204773ab67985a09f5696ca6c3869afeed0bb51703ea404a24e975"}, + {file = "websockets-11.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:955fcdb304833df2e172ce2492b7b47b4aab5dcc035a10e093d911a1916f2c87"}, + {file = "websockets-11.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb46d2c7631b2e6f10f7c8bac7854f7c5e5288f024f1c137d4633c79ead1e3c0"}, + {file = "websockets-11.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25aae96c1060e85836552a113495db6d857400288161299d77b7b20f2ac569f2"}, + {file = "websockets-11.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2abeeae63154b7f63d9f764685b2d299e9141171b8b896688bd8baec6b3e2303"}, + {file = "websockets-11.0.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:daa1e8ea47507555ed7a34f8b49398d33dff5b8548eae3de1dc0ef0607273a33"}, + {file = "websockets-11.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:954eb789c960fa5daaed3cfe336abc066941a5d456ff6be8f0e03dd89886bb4c"}, + {file = "websockets-11.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3ffe251a31f37e65b9b9aca5d2d67fd091c234e530f13d9dce4a67959d5a3fba"}, + {file = "websockets-11.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:adf6385f677ed2e0b021845b36f55c43f171dab3a9ee0ace94da67302f1bc364"}, + {file = "websockets-11.0.2-cp38-cp38-win32.whl", hash = "sha256:aa7b33c1fb2f7b7b9820f93a5d61ffd47f5a91711bc5fa4583bbe0c0601ec0b2"}, + {file = "websockets-11.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:220d5b93764dd70d7617f1663da64256df7e7ea31fc66bc52c0e3750ee134ae3"}, + {file = "websockets-11.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fb4480556825e4e6bf2eebdbeb130d9474c62705100c90e59f2f56459ddab42"}, + {file = "websockets-11.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec00401846569aaf018700249996143f567d50050c5b7b650148989f956547af"}, + {file = "websockets-11.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87c69f50281126dcdaccd64d951fb57fbce272578d24efc59bce72cf264725d0"}, + {file = "websockets-11.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:232b6ba974f5d09b1b747ac232f3a3d8f86de401d7b565e837cc86988edf37ac"}, + {file = "websockets-11.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:392d409178db1e46d1055e51cc850136d302434e12d412a555e5291ab810f622"}, + {file = "websockets-11.0.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4fe2442091ff71dee0769a10449420fd5d3b606c590f78dd2b97d94b7455640"}, + {file = "websockets-11.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ede13a6998ba2568b21825809d96e69a38dc43184bdeebbde3699c8baa21d015"}, + {file = "websockets-11.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4c54086b2d2aec3c3cb887ad97e9c02c6be9f1d48381c7419a4aa932d31661e4"}, + {file = "websockets-11.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e37a76ccd483a6457580077d43bc3dfe1fd784ecb2151fcb9d1c73f424deaeba"}, + {file = "websockets-11.0.2-cp39-cp39-win32.whl", hash = "sha256:d1881518b488a920434a271a6e8a5c9481a67c4f6352ebbdd249b789c0467ddc"}, + {file = "websockets-11.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:25e265686ea385f22a00cc2b719b880797cd1bb53b46dbde969e554fb458bfde"}, + {file = "websockets-11.0.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ce69f5c742eefd039dce8622e99d811ef2135b69d10f9aa79fbf2fdcc1e56cd7"}, + {file = "websockets-11.0.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b985ba2b9e972cf99ddffc07df1a314b893095f62c75bc7c5354a9c4647c6503"}, + {file = "websockets-11.0.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b52def56d2a26e0e9c464f90cadb7e628e04f67b0ff3a76a4d9a18dfc35e3dd"}, + {file = "websockets-11.0.2-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70a438ef2a22a581d65ad7648e949d4ccd20e3c8ed7a90bbc46df4e60320891"}, + {file = "websockets-11.0.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:752fbf420c71416fb1472fec1b4cb8631c1aa2be7149e0a5ba7e5771d75d2bb9"}, + {file = "websockets-11.0.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dd906b0cdc417ea7a5f13bb3c6ca3b5fd563338dc596996cb0fdd7872d691c0a"}, + {file = "websockets-11.0.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e79065ff6549dd3c765e7916067e12a9c91df2affea0ac51bcd302aaf7ad207"}, + {file = "websockets-11.0.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46388a050d9e40316e58a3f0838c63caacb72f94129eb621a659a6e49bad27ce"}, + {file = "websockets-11.0.2-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c7de298371d913824f71b30f7685bb07ad13969c79679cca5b1f7f94fec012f"}, + {file = "websockets-11.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6d872c972c87c393e6a49c1afbdc596432df8c06d0ff7cd05aa18e885e7cfb7c"}, + {file = "websockets-11.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b444366b605d2885f0034dd889faf91b4b47668dd125591e2c64bfde611ac7e1"}, + {file = "websockets-11.0.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b967a4849db6b567dec3f7dd5d97b15ce653e3497b8ce0814e470d5e074750"}, + {file = "websockets-11.0.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2acdc82099999e44fa7bd8c886f03c70a22b1d53ae74252f389be30d64fd6004"}, + {file = "websockets-11.0.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:518ed6782d9916c5721ebd61bb7651d244178b74399028302c8617d0620af291"}, + {file = "websockets-11.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:58477b041099bb504e1a5ddd8aa86302ed1d5c6995bdd3db2b3084ef0135d277"}, + {file = "websockets-11.0.2-py3-none-any.whl", hash = "sha256:5004c087d17251938a52cce21b3dbdabeecbbe432ce3f5bbbf15d8692c36eac9"}, + {file = "websockets-11.0.2.tar.gz", hash = "sha256:b1a69701eb98ed83dd099de4a686dc892c413d974fa31602bc00aca7cb988ac9"}, ] [[package]] @@ -4801,4 +4814,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "f0a23552d8cbd3d38722a69698cf823cdd19a90b707538837da64a933f8d13b4" +content-hash = "1320f2d5466c6569ee0563cc81b28d8c8897c8f07b4e0912c231c6e4033a2bf8" diff --git a/pyproject.toml b/pyproject.toml index bc0753c5d..4136785ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,7 @@ fake-useragent = "^1.1.3" docstring-parser = "^0.15" psycopg2-binary = "^2.9.6" pyarrow = "^11.0.0" +websockets = "^11.0.2" [tool.poetry.group.dev.dependencies] black = "^23.1.0" From 2d6854165024a6bdffa98e05e78b792a6a88db17 Mon Sep 17 00:00:00 2001 From: Gabriel Almeida Date: Tue, 25 Apr 2023 17:30:53 -0300 Subject: [PATCH 36/74] refactor(api): remove sender field from ChatMessage and ChatResponse schemas fix(api): fix ChatManager.get_history method to exclude start and stream messages feat(api): add is_bot field to ChatMessage, ChatResponse, and FileResponse schemas --- src/backend/langflow/api/callback.py | 4 +--- src/backend/langflow/api/chat.py | 3 +-- src/backend/langflow/api/chat_manager.py | 30 +++++++++++------------- src/backend/langflow/api/schemas.py | 11 ++++----- 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/backend/langflow/api/callback.py b/src/backend/langflow/api/callback.py index 47a8d945c..cad4b1416 100644 --- a/src/backend/langflow/api/callback.py +++ b/src/backend/langflow/api/callback.py @@ -12,7 +12,5 @@ class StreamingLLMCallbackHandler(AsyncCallbackHandler): self.websocket = websocket async def on_llm_new_token(self, token: str, **kwargs: Any) -> None: - resp = ChatResponse( - sender="bot", message=token, type="stream", intermediate_steps="" - ) + resp = ChatResponse(message=token, type="stream", intermediate_steps="") await self.websocket.send_json(resp.dict()) diff --git a/src/backend/langflow/api/chat.py b/src/backend/langflow/api/chat.py index b2da73d52..d5c2dc879 100644 --- a/src/backend/langflow/api/chat.py +++ b/src/backend/langflow/api/chat.py @@ -8,6 +8,5 @@ chat_manager = ChatManager() @router.websocket("/chat/{client_id}") async def websocket_endpoint(client_id: str, websocket: WebSocket): + """Websocket endpoint for chat.""" await chat_manager.handle_websocket(client_id, websocket) - - diff --git a/src/backend/langflow/api/chat_manager.py b/src/backend/langflow/api/chat_manager.py index bc9b2dc2d..8f407a791 100644 --- a/src/backend/langflow/api/chat_manager.py +++ b/src/backend/langflow/api/chat_manager.py @@ -26,11 +26,17 @@ class ChatHistory(AsyncSubject): self.history: Dict[str, List[ChatMessage]] = defaultdict(list) async def add_message(self, client_id: str, message: ChatMessage): + """Add a message to the chat history.""" + self.history[client_id].append(message) await self.notify() def get_history(self, client_id: str) -> List[ChatMessage]: - return self.history[client_id] + """Get the chat history for a client.""" + if history := self.history.get(client_id, []): + return [msg for msg in history if msg.type not in ["start", "stream"]] + else: + return [] class ChatManager: @@ -46,7 +52,7 @@ class ChatManager: client_id = self.cache_manager.current_client_id if client_id in self.active_connections: chat_response = self.chat_history.get_history(client_id)[-1] - if chat_response.sender == "bot": + if chat_response.is_bot: # Process FileResponse if isinstance(chat_response, FileResponse): # If data_type is pandas, convert to csv @@ -63,7 +69,6 @@ class ChatManager: self.last_cached_object_dict = self.cache_manager.get_last() # Add a new ChatResponse with the data chat_response = FileResponse( - sender="bot", message=None, type="file", data=self.last_cached_object_dict["obj"], @@ -94,13 +99,11 @@ class ChatManager: async def process_message(self, client_id: str, payload: Dict): # Process the graph data and chat message chat_message = payload.pop("message", "") - chat_message = ChatMessage(sender="you", message=chat_message) + chat_message = ChatMessage(message=chat_message) await self.chat_history.add_message(client_id, chat_message) graph_data = payload - start_resp = ChatResponse( - sender="bot", message=None, type="start", intermediate_steps="" - ) + start_resp = ChatResponse(message=None, type="start", intermediate_steps="") await self.chat_history.add_message(client_id, start_resp) is_first_message = len(self.chat_history.get_history(client_id=client_id)) == 0 @@ -117,14 +120,9 @@ class ChatManager: except Exception as e: # Log stack trace logger.exception(e) - error_resp = ChatResponse( - sender="bot", message=str(e), type="error", intermediate_steps="" - ) - await self.send_json(client_id, error_resp) - return + raise e # Send a response back to the frontend, if needed response = ChatResponse( - sender="bot", message=result or "", intermediate_steps=intermediate_steps or "", type="end", @@ -151,6 +149,7 @@ class ChatManager: except Exception as e: # Handle any exceptions that might occur print(f"Error: {e}") + raise e finally: self.disconnect(client_id) @@ -198,11 +197,10 @@ def try_setting_streaming_options(langchain_object, websocket): llm = langchain_object.llm_chain.llm if isinstance(llm, (OpenAI, ChatOpenAI, AzureOpenAI, AzureChatOpenAI)): llm.streaming = bool(hasattr(llm, "streaming")) - - if hasattr(langchain_object, "callback_manager"): stream_handler = StreamingLLMCallbackHandler(websocket) stream_manager = AsyncCallbackManager([stream_handler]) - langchain_object.callback_manager = stream_manager + llm.callback_manager = stream_manager + return langchain_object diff --git a/src/backend/langflow/api/schemas.py b/src/backend/langflow/api/schemas.py index 1aefe5c8e..c9b210210 100644 --- a/src/backend/langflow/api/schemas.py +++ b/src/backend/langflow/api/schemas.py @@ -5,14 +5,9 @@ from pydantic import BaseModel, validator class ChatMessage(BaseModel): """Chat message schema.""" - sender: str + is_bot: bool = False message: Union[str, None] = None - - @validator("sender") - def sender_must_be_bot_or_you(cls, v): - if v not in ["bot", "you"]: - raise ValueError("sender must be bot or you") - return v + type: str = "human" class ChatResponse(ChatMessage): @@ -20,6 +15,7 @@ class ChatResponse(ChatMessage): intermediate_steps: str type: str + is_bot: bool = True @validator("type") def validate_message_type(cls, v): @@ -34,6 +30,7 @@ class FileResponse(ChatMessage): data: Any data_type: str type: str = "file" + is_bot: bool = True @validator("data_type") def validate_data_type(cls, v): From b526c436cd6d4a2f65e0249044de8176d117170e Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 25 Apr 2023 17:34:14 -0300 Subject: [PATCH 37/74] removed chat history from flow save --- .../src/components/chatComponent/index.tsx | 3 +- src/frontend/src/contexts/tabsContext.tsx | 55 ++++++++------- src/frontend/src/modals/chatModal/index.tsx | 69 ++++++++----------- src/frontend/src/types/flow/index.ts | 1 - 4 files changed, 60 insertions(+), 68 deletions(-) diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 8108f3f36..668a970bd 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -4,14 +4,13 @@ import { useState, } from "react"; -import { ChatType } from "../../types/chat"; +import { ChatMessageType, ChatType } from "../../types/chat"; import ChatTrigger from "./chatTrigger"; import ChatModal from "../../modals/chatModal"; const _ = require("lodash"); export default function Chat({ flow }: ChatType) { - const [open, setOpen] = useState(false); useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { diff --git a/src/frontend/src/contexts/tabsContext.tsx b/src/frontend/src/contexts/tabsContext.tsx index 97e62e5e2..b430591b1 100644 --- a/src/frontend/src/contexts/tabsContext.tsx +++ b/src/frontend/src/contexts/tabsContext.tsx @@ -1,11 +1,18 @@ -import { createContext, useEffect, useState, useRef, ReactNode, useContext } from "react"; +import { + createContext, + useEffect, + useState, + useRef, + ReactNode, + useContext, +} from "react"; import { FlowType } from "../types/flow"; import { TabsContextType } from "../types/tabs"; import { normalCaseToSnakeCase } from "../utils"; import { alertContext } from "./alertContext"; const TabsContextInitialValue: TabsContextType = { - save:()=>{}, + save: () => {}, tabIndex: 0, setTabIndex: (index: number) => {}, flows: [], @@ -13,11 +20,11 @@ const TabsContextInitialValue: TabsContextType = { addFlow: (flowData?: any) => {}, updateFlow: (newFlow: FlowType) => {}, incrementNodeId: () => 0, - downloadFlow: (flow:FlowType) => {}, + downloadFlow: (flow: FlowType) => {}, uploadFlow: () => {}, lockChat: false, - setLockChat:(prevState:boolean)=>{}, - hardReset:()=>{}, + setLockChat: (prevState: boolean) => {}, + hardReset: () => {}, }; export const TabsContext = createContext( @@ -25,7 +32,7 @@ export const TabsContext = createContext( ); export function TabsProvider({ children }: { children: ReactNode }) { - const {setNoticeData} = useContext(alertContext) + const { setNoticeData } = useContext(alertContext); const [tabIndex, setTabIndex] = useState(0); const [flows, setFlows] = useState>([]); const [id, setId] = useState(0); @@ -36,20 +43,18 @@ export function TabsProvider({ children }: { children: ReactNode }) { newNodeId.current = newNodeId.current + 1; return newNodeId.current; } - function save(){ + function save() { if (flows.length !== 0) - window.localStorage.setItem( - "tabsData", - JSON.stringify({ tabIndex, flows, id, nodeId: newNodeId.current }) - ); + window.localStorage.setItem( + "tabsData", + JSON.stringify({ tabIndex, flows, id, nodeId: newNodeId.current }) + ); } useEffect(() => { //save tabs locally - save() + save(); }, [flows, id, tabIndex, newNodeId]); - - useEffect(() => { //get tabs locally saved let cookie = window.localStorage.getItem("tabsData"); @@ -61,15 +66,17 @@ export function TabsProvider({ children }: { children: ReactNode }) { newNodeId.current = cookieObject.nodeId; } }, []); - function hardReset(){ - newNodeId.current=0; - setTabIndex(0);setFlows([]);setId(0); + function hardReset() { + newNodeId.current = 0; + setTabIndex(0); + setFlows([]); + setId(0); } /** * Downloads the current flow as a JSON file */ - function downloadFlow(flow:FlowType) { + function downloadFlow(flow: FlowType) { // create a data URI with the current flow data const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( JSON.stringify(flow) @@ -82,7 +89,9 @@ export function TabsProvider({ children }: { children: ReactNode }) { // simulate a click on the link element to trigger the download link.click(); - setNoticeData({title:"Warning: Critical data,JSON file may including API keys."}) + setNoticeData({ + title: "Warning: Critical data,JSON file may including API keys.", + }); } /** @@ -139,15 +148,14 @@ export function TabsProvider({ children }: { children: ReactNode }) { function addFlow(flow?: FlowType) { // Get data from the flow or set it to null if there's no flow provided. const data = flow?.data ? flow.data : null; - const description = flow?.description?flow.description:"" + const description = flow?.description ? flow.description : ""; // Create a new flow with a default name if no flow is provided. let newFlow: FlowType = { description, - name: flow?.name??"New Flow", + name: flow?.name ?? "New Flow", id: id.toString(), data, - chat: flow ? flow.chat : [], }; // Increment the ID counter. @@ -171,10 +179,9 @@ export function TabsProvider({ children }: { children: ReactNode }) { const newFlows = [...prevState]; const index = newFlows.findIndex((flow) => flow.id === newFlow.id); if (index !== -1) { - newFlows[index].description = newFlow.description??"" + newFlows[index].description = newFlow.description ?? ""; newFlows[index].data = newFlow.data; newFlows[index].name = newFlow.name; - newFlows[index].chat = newFlow.chat; } return newFlows; }); diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx index f0783a744..dc462e328 100644 --- a/src/frontend/src/modals/chatModal/index.tsx +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -10,15 +10,23 @@ import { typesContext } from "../../contexts/typesContext"; import ChatMessage from "./chatMessage"; import { FaEraser } from "react-icons/fa"; import { sendAllProps } from "../../types/api"; +import { ChatMessageType } from "../../types/chat"; const _ = require("lodash"); -export default function ChatModal({ flow, open, setOpen }:{open:boolean,setOpen:Function,flow:FlowType}) { - const { updateFlow, lockChat, setLockChat, flows, tabIndex } = +export default function ChatModal({ + flow, + open, + setOpen, +}: { + open: boolean; + setOpen: Function; + flow: FlowType; +}) { + const { updateFlow, lockChat, setLockChat} = useContext(TabsContext); - const [saveChat, setSaveChat] = useState(false); const [chatValue, setChatValue] = useState(""); - const [chatHistory, setChatHistory] = useState(flow.chat); + const [chatHistory, setChatHistory] = useState([]); const { reactFlowInstance } = useContext(typesContext); const { setErrorData, setNoticeData } = useContext(alertContext); const [ws, setWs] = useState(null); @@ -27,13 +35,9 @@ export default function ChatModal({ flow, open, setOpen }:{open:boolean,setOpen: isSend: boolean, thought?: string ) => { - let tabsChange = false; + setChatHistory((old) => { let newChat = _.cloneDeep(old); - if (JSON.stringify(flow.chat) !== JSON.stringify(old)) { - tabsChange = true; - return old; - } if (thought) { newChat.push({ message, isSend, thought }); } else { @@ -41,53 +45,36 @@ export default function ChatModal({ flow, open, setOpen }:{open:boolean,setOpen: } return newChat; }); - if (tabsChange) { - if (thought) { - updateFlow({ - ..._.cloneDeep(flow), - chat: [...flow.chat, { isSend, message, thought }], - }); - } else { - updateFlow({ - ..._.cloneDeep(flow), - chat: [...flow.chat, { isSend, message }], - }); - } - } - setSaveChat((chat) => !chat); }; useEffect(() => { const newWs = new WebSocket(`ws://localhost:7860/chat/${flow.id}`); newWs.onopen = () => { - console.log('WebSocket connection established!'); + console.log("WebSocket connection established!"); }; newWs.onmessage = (event) => { - const data = JSON.parse(event.data); - console.log('Received data:', data); - // Do something with the data received from the WebSocket + const data = JSON.parse(event.data); + console.log("Received data:", data); + if(Array.isArray(data)){ + console.log("entrou") + setChatHistory([{isSend:true,message:"sdsdsad"}]) + } + // Do something with the data received from the WebSocket }; setWs(newWs); - + return () => { - newWs.close(); + newWs.close(); }; - }, []); + }, []); - async function sendAll(data: sendAllProps) { + async function sendAll(data: sendAllProps) { if (ws) { - ws.send(JSON.stringify(data)); + ws.send(JSON.stringify(data)); } - return {data:{result:"sdsdsad",thought:"dsdsad"}} - } + return { data: { result: "sdsdsad", thought: "dsdsad" } }; + } - useEffect(() => { - updateFlow({ ..._.cloneDeep(flow), chat: chatHistory }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [saveChat]); - useEffect(() => { - setChatHistory(flow.chat); - }, [flow]); useEffect(() => { if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" }); }, [chatHistory]); diff --git a/src/frontend/src/types/flow/index.ts b/src/frontend/src/types/flow/index.ts index 50b0cab7a..26354c55c 100644 --- a/src/frontend/src/types/flow/index.ts +++ b/src/frontend/src/types/flow/index.ts @@ -6,7 +6,6 @@ export type FlowType = { name: string; id: string; data: ReactFlowJsonObject; - chat: Array; description:string; }; export type NodeType = {id:string,type:string,position:XYPosition,data:NodeDataType} From 61a3b9aad4cdcd0adc59cce7bdb2d0a97beb6808 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 25 Apr 2023 17:51:16 -0300 Subject: [PATCH 38/74] chat working as old with websocket, need to improve error handling and file events --- src/frontend/src/modals/chatModal/index.tsx | 38 +++++++++++++++------ 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx index dc462e328..9eb6de490 100644 --- a/src/frontend/src/modals/chatModal/index.tsx +++ b/src/frontend/src/modals/chatModal/index.tsx @@ -10,7 +10,7 @@ import { typesContext } from "../../contexts/typesContext"; import ChatMessage from "./chatMessage"; import { FaEraser } from "react-icons/fa"; import { sendAllProps } from "../../types/api"; -import { ChatMessageType } from "../../types/chat"; +import { ChatMessageType, ChatType } from "../../types/chat"; const _ = require("lodash"); @@ -23,8 +23,7 @@ export default function ChatModal({ setOpen: Function; flow: FlowType; }) { - const { updateFlow, lockChat, setLockChat} = - useContext(TabsContext); + const { updateFlow, lockChat, setLockChat } = useContext(TabsContext); const [chatValue, setChatValue] = useState(""); const [chatHistory, setChatHistory] = useState([]); const { reactFlowInstance } = useContext(typesContext); @@ -35,7 +34,6 @@ export default function ChatModal({ isSend: boolean, thought?: string ) => { - setChatHistory((old) => { let newChat = _.cloneDeep(old); if (thought) { @@ -55,9 +53,31 @@ export default function ChatModal({ newWs.onmessage = (event) => { const data = JSON.parse(event.data); console.log("Received data:", data); - if(Array.isArray(data)){ - console.log("entrou") - setChatHistory([{isSend:true,message:"sdsdsad"}]) + //get chat history + if (Array.isArray(data)) { + console.log("entrou"); + + setChatHistory((_) => { + let newChatHistory: ChatMessageType[] = []; + data.forEach( + (chatItem: { + intermediate_steps?: "string"; + is_bot: boolean; + message: string; + type: string; + }) => { + newChatHistory.push({ + isSend: !chatItem.is_bot, + message: chatItem.message, + thought:chatItem.intermediate_steps + }); + } + ); + return newChatHistory; + }); + } + if(data.type==='end'){ + addChatHistory(data.message, false, data.intermediate_steps); } // Do something with the data received from the WebSocket }; @@ -72,7 +92,6 @@ export default function ChatModal({ if (ws) { ws.send(JSON.stringify(data)); } - return { data: { result: "sdsdsad", thought: "dsdsad" } }; } useEffect(() => { @@ -143,8 +162,7 @@ export default function ChatModal({ name: flow.name, description: flow.description, }) - .then((r) => { - addChatHistory(r.data.result, false, r.data.thought); + .then(() => { setLockChat(false); }) .catch((error) => { From be5b7822d7dc68417b0b9af1e272485f60a285bd Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 25 Apr 2023 18:36:46 -0300 Subject: [PATCH 39/74] custom scrollbar and text input became text area for chat --- .../src/modals/chatModal/chatInput/index.tsx | 57 +++++++++++++++++++ src/frontend/src/modals/chatModal/index.tsx | 44 +++----------- src/frontend/tailwind.config.js | 16 +++++- 3 files changed, 80 insertions(+), 37 deletions(-) create mode 100644 src/frontend/src/modals/chatModal/chatInput/index.tsx diff --git a/src/frontend/src/modals/chatModal/chatInput/index.tsx b/src/frontend/src/modals/chatModal/chatInput/index.tsx new file mode 100644 index 000000000..7b371edb1 --- /dev/null +++ b/src/frontend/src/modals/chatModal/chatInput/index.tsx @@ -0,0 +1,57 @@ +import { LockClosedIcon, PaperAirplaneIcon } from "@heroicons/react/24/outline"; +import { classNames } from "../../../utils"; +import { useRef } from "react"; + +export default function ChatInput({ + lockChat, + chatValue, + sendMessage, + setChatValue, +}: { + lockChat:boolean; + chatValue:string; + sendMessage:Function; + setChatValue:Function; +}) { + const inputRef = useRef(null); + return ( + <> +